Merge pull request #1972 from esdrubal/proc_pidpath
[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/mono-debug-debugger.h>
53 #include <mono/metadata/gc-internal.h>
54 #include <mono/metadata/security-manager.h>
55 #include <mono/metadata/threads-types.h>
56 #include <mono/metadata/security-core-clr.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);
147
148 /* helper methods signatures */
149 static MonoMethodSignature *helper_sig_domain_get;
150 static MonoMethodSignature *helper_sig_rgctx_lazy_fetch_trampoline;
151
152 /*
153  * Instruction metadata
154  */
155 #ifdef MINI_OP
156 #undef MINI_OP
157 #endif
158 #ifdef MINI_OP3
159 #undef MINI_OP3
160 #endif
161 #define MINI_OP(a,b,dest,src1,src2) dest, src1, src2, ' ',
162 #define MINI_OP3(a,b,dest,src1,src2,src3) dest, src1, src2, src3,
163 #define NONE ' '
164 #define IREG 'i'
165 #define FREG 'f'
166 #define VREG 'v'
167 #define XREG 'x'
168 #if SIZEOF_REGISTER == 8 && SIZEOF_REGISTER == SIZEOF_VOID_P
169 #define LREG IREG
170 #else
171 #define LREG 'l'
172 #endif
173 /* keep in sync with the enum in mini.h */
174 const char
175 ins_info[] = {
176 #include "mini-ops.h"
177 };
178 #undef MINI_OP
179 #undef MINI_OP3
180
181 #define MINI_OP(a,b,dest,src1,src2) ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0)),
182 #define MINI_OP3(a,b,dest,src1,src2,src3) ((src3) != NONE ? 3 : ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0))),
183 /* 
184  * This should contain the index of the last sreg + 1. This is not the same
185  * as the number of sregs for opcodes like IA64_CMP_EQ_IMM.
186  */
187 const gint8 ins_sreg_counts[] = {
188 #include "mini-ops.h"
189 };
190 #undef MINI_OP
191 #undef MINI_OP3
192
193 #define MONO_INIT_VARINFO(vi,id) do { \
194         (vi)->range.first_use.pos.bid = 0xffff; \
195         (vi)->reg = -1; \
196         (vi)->idx = (id); \
197 } while (0)
198
199 guint32
200 mono_alloc_ireg (MonoCompile *cfg)
201 {
202         return alloc_ireg (cfg);
203 }
204
205 guint32
206 mono_alloc_lreg (MonoCompile *cfg)
207 {
208         return alloc_lreg (cfg);
209 }
210
211 guint32
212 mono_alloc_freg (MonoCompile *cfg)
213 {
214         return alloc_freg (cfg);
215 }
216
217 guint32
218 mono_alloc_preg (MonoCompile *cfg)
219 {
220         return alloc_preg (cfg);
221 }
222
223 guint32
224 mono_alloc_dreg (MonoCompile *cfg, MonoStackType stack_type)
225 {
226         return alloc_dreg (cfg, stack_type);
227 }
228
229 /*
230  * mono_alloc_ireg_ref:
231  *
232  *   Allocate an IREG, and mark it as holding a GC ref.
233  */
234 guint32
235 mono_alloc_ireg_ref (MonoCompile *cfg)
236 {
237         return alloc_ireg_ref (cfg);
238 }
239
240 /*
241  * mono_alloc_ireg_mp:
242  *
243  *   Allocate an IREG, and mark it as holding a managed pointer.
244  */
245 guint32
246 mono_alloc_ireg_mp (MonoCompile *cfg)
247 {
248         return alloc_ireg_mp (cfg);
249 }
250
251 /*
252  * mono_alloc_ireg_copy:
253  *
254  *   Allocate an IREG with the same GC type as VREG.
255  */
256 guint32
257 mono_alloc_ireg_copy (MonoCompile *cfg, guint32 vreg)
258 {
259         if (vreg_is_ref (cfg, vreg))
260                 return alloc_ireg_ref (cfg);
261         else if (vreg_is_mp (cfg, vreg))
262                 return alloc_ireg_mp (cfg);
263         else
264                 return alloc_ireg (cfg);
265 }
266
267 guint
268 mono_type_to_regmove (MonoCompile *cfg, MonoType *type)
269 {
270         if (type->byref)
271                 return OP_MOVE;
272
273         type = mini_get_underlying_type (type);
274 handle_enum:
275         switch (type->type) {
276         case MONO_TYPE_I1:
277         case MONO_TYPE_U1:
278                 return OP_MOVE;
279         case MONO_TYPE_I2:
280         case MONO_TYPE_U2:
281                 return OP_MOVE;
282         case MONO_TYPE_I4:
283         case MONO_TYPE_U4:
284                 return OP_MOVE;
285         case MONO_TYPE_I:
286         case MONO_TYPE_U:
287         case MONO_TYPE_PTR:
288         case MONO_TYPE_FNPTR:
289                 return OP_MOVE;
290         case MONO_TYPE_CLASS:
291         case MONO_TYPE_STRING:
292         case MONO_TYPE_OBJECT:
293         case MONO_TYPE_SZARRAY:
294         case MONO_TYPE_ARRAY:    
295                 return OP_MOVE;
296         case MONO_TYPE_I8:
297         case MONO_TYPE_U8:
298 #if SIZEOF_REGISTER == 8
299                 return OP_MOVE;
300 #else
301                 return OP_LMOVE;
302 #endif
303         case MONO_TYPE_R4:
304                 return cfg->r4fp ? OP_RMOVE : OP_FMOVE;
305         case MONO_TYPE_R8:
306                 return OP_FMOVE;
307         case MONO_TYPE_VALUETYPE:
308                 if (type->data.klass->enumtype) {
309                         type = mono_class_enum_basetype (type->data.klass);
310                         goto handle_enum;
311                 }
312                 if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (type)))
313                         return OP_XMOVE;
314                 return OP_VMOVE;
315         case MONO_TYPE_TYPEDBYREF:
316                 return OP_VMOVE;
317         case MONO_TYPE_GENERICINST:
318                 type = &type->data.generic_class->container_class->byval_arg;
319                 goto handle_enum;
320         case MONO_TYPE_VAR:
321         case MONO_TYPE_MVAR:
322                 g_assert (cfg->gshared);
323                 if (mini_type_var_is_vt (type))
324                         return OP_VMOVE;
325                 else
326                         return mono_type_to_regmove (cfg, mini_get_underlying_type (type));
327         default:
328                 g_error ("unknown type 0x%02x in type_to_regstore", type->type);
329         }
330         return -1;
331 }
332
333 void
334 mono_print_bb (MonoBasicBlock *bb, const char *msg)
335 {
336         int i;
337         MonoInst *tree;
338
339         printf ("\n%s %d: [IN: ", msg, bb->block_num);
340         for (i = 0; i < bb->in_count; ++i)
341                 printf (" BB%d(%d)", bb->in_bb [i]->block_num, bb->in_bb [i]->dfn);
342         printf (", OUT: ");
343         for (i = 0; i < bb->out_count; ++i)
344                 printf (" BB%d(%d)", bb->out_bb [i]->block_num, bb->out_bb [i]->dfn);
345         printf (" ]\n");
346         for (tree = bb->code; tree; tree = tree->next)
347                 mono_print_ins_index (-1, tree);
348 }
349
350 void
351 mono_create_helper_signatures (void)
352 {
353         helper_sig_domain_get = mono_create_icall_signature ("ptr");
354         helper_sig_rgctx_lazy_fetch_trampoline = mono_create_icall_signature ("ptr ptr");
355 }
356
357 static MONO_NEVER_INLINE void
358 break_on_unverified (void)
359 {
360         if (mini_get_debug_options ()->break_on_unverified)
361                 G_BREAKPOINT ();
362 }
363
364 static MONO_NEVER_INLINE void
365 method_access_failure (MonoCompile *cfg, MonoMethod *method, MonoMethod *cil_method)
366 {
367         char *method_fname = mono_method_full_name (method, TRUE);
368         char *cil_method_fname = mono_method_full_name (cil_method, TRUE);
369         mono_cfg_set_exception (cfg, MONO_EXCEPTION_METHOD_ACCESS);
370         cfg->exception_message = g_strdup_printf ("Method `%s' is inaccessible from method `%s'\n", cil_method_fname, method_fname);
371         g_free (method_fname);
372         g_free (cil_method_fname);
373 }
374
375 static MONO_NEVER_INLINE void
376 field_access_failure (MonoCompile *cfg, MonoMethod *method, MonoClassField *field)
377 {
378         char *method_fname = mono_method_full_name (method, TRUE);
379         char *field_fname = mono_field_full_name (field);
380         mono_cfg_set_exception (cfg, MONO_EXCEPTION_FIELD_ACCESS);
381         cfg->exception_message = g_strdup_printf ("Field `%s' is inaccessible from method `%s'\n", field_fname, method_fname);
382         g_free (method_fname);
383         g_free (field_fname);
384 }
385
386 static MONO_NEVER_INLINE void
387 inline_failure (MonoCompile *cfg, const char *msg)
388 {
389         if (cfg->verbose_level >= 2)
390                 printf ("inline failed: %s\n", msg);
391         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INLINE_FAILED);
392 }
393
394 static MONO_NEVER_INLINE void
395 gshared_failure (MonoCompile *cfg, int opcode, const char *file, int line)
396 {
397         if (cfg->verbose_level > 2)                                                                                     \
398                 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);
399         mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED);
400 }
401
402 static MONO_NEVER_INLINE void
403 gsharedvt_failure (MonoCompile *cfg, int opcode, const char *file, int line)
404 {
405         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);
406         if (cfg->verbose_level >= 2)
407                 printf ("%s\n", cfg->exception_message);
408         mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED);
409 }
410
411 /*
412  * When using gsharedvt, some instatiations might be verifiable, and some might be not. i.e. 
413  * foo<T> (int i) { ldarg.0; box T; }
414  */
415 #define UNVERIFIED do { \
416         if (cfg->gsharedvt) { \
417                 if (cfg->verbose_level > 2)                                                                     \
418                         printf ("gsharedvt method failed to verify, falling back to instantiation.\n"); \
419                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED); \
420                 goto exception_exit;                                                                                    \
421         }                                                                                                                                       \
422         break_on_unverified ();                                                                                         \
423         goto unverified;                                                                                                        \
424 } while (0)
425
426 #define GET_BBLOCK(cfg,tblock,ip) do {  \
427                 (tblock) = cfg->cil_offset_to_bb [(ip) - cfg->cil_start]; \
428                 if (!(tblock)) {        \
429                         if ((ip) >= end || (ip) < header->code) UNVERIFIED; \
430             NEW_BBLOCK (cfg, (tblock)); \
431                         (tblock)->cil_code = (ip);      \
432                         ADD_BBLOCK (cfg, (tblock));     \
433                 } \
434         } while (0)
435
436 #if defined(TARGET_X86) || defined(TARGET_AMD64)
437 #define EMIT_NEW_X86_LEA(cfg,dest,sr1,sr2,shift,imm) do { \
438                 MONO_INST_NEW (cfg, dest, OP_X86_LEA); \
439                 (dest)->dreg = alloc_ireg_mp ((cfg)); \
440                 (dest)->sreg1 = (sr1); \
441                 (dest)->sreg2 = (sr2); \
442                 (dest)->inst_imm = (imm); \
443                 (dest)->backend.shift_amount = (shift); \
444                 MONO_ADD_INS ((cfg)->cbb, (dest)); \
445         } while (0)
446 #endif
447
448 /* Emit conversions so both operands of a binary opcode are of the same type */
449 static void
450 add_widen_op (MonoCompile *cfg, MonoInst *ins, MonoInst **arg1_ref, MonoInst **arg2_ref)
451 {
452         MonoInst *arg1 = *arg1_ref;
453         MonoInst *arg2 = *arg2_ref;
454
455         if (cfg->r4fp &&
456                 ((arg1->type == STACK_R4 && arg2->type == STACK_R8) ||
457                  (arg1->type == STACK_R8 && arg2->type == STACK_R4))) {
458                 MonoInst *conv;
459
460                 /* Mixing r4/r8 is allowed by the spec */
461                 if (arg1->type == STACK_R4) {
462                         int dreg = alloc_freg (cfg);
463
464                         EMIT_NEW_UNALU (cfg, conv, OP_RCONV_TO_R8, dreg, arg1->dreg);
465                         conv->type = STACK_R8;
466                         ins->sreg1 = dreg;
467                         *arg1_ref = conv;
468                 }
469                 if (arg2->type == STACK_R4) {
470                         int dreg = alloc_freg (cfg);
471
472                         EMIT_NEW_UNALU (cfg, conv, OP_RCONV_TO_R8, dreg, arg2->dreg);
473                         conv->type = STACK_R8;
474                         ins->sreg2 = dreg;
475                         *arg2_ref = conv;
476                 }
477         }
478
479 #if SIZEOF_REGISTER == 8
480         /* FIXME: Need to add many more cases */
481         if ((arg1)->type == STACK_PTR && (arg2)->type == STACK_I4) {
482                 MonoInst *widen;
483
484                 int dr = alloc_preg (cfg);
485                 EMIT_NEW_UNALU (cfg, widen, OP_SEXT_I4, dr, (arg2)->dreg);
486                 (ins)->sreg2 = widen->dreg;
487         }
488 #endif
489 }
490
491 #define ADD_BINOP(op) do {      \
492                 MONO_INST_NEW (cfg, ins, (op)); \
493                 sp -= 2;        \
494                 ins->sreg1 = sp [0]->dreg;      \
495                 ins->sreg2 = sp [1]->dreg;      \
496                 type_from_op (cfg, ins, sp [0], sp [1]);        \
497                 CHECK_TYPE (ins);       \
498                 /* Have to insert a widening op */               \
499         add_widen_op (cfg, ins, &sp [0], &sp [1]);               \
500         ins->dreg = alloc_dreg ((cfg), (ins)->type); \
501         MONO_ADD_INS ((cfg)->cbb, (ins)); \
502         *sp++ = mono_decompose_opcode ((cfg), (ins));   \
503         } while (0)
504
505 #define ADD_UNOP(op) do {       \
506                 MONO_INST_NEW (cfg, ins, (op)); \
507                 sp--;   \
508                 ins->sreg1 = sp [0]->dreg;      \
509                 type_from_op (cfg, ins, sp [0], NULL);  \
510                 CHECK_TYPE (ins);       \
511         (ins)->dreg = alloc_dreg ((cfg), (ins)->type); \
512         MONO_ADD_INS ((cfg)->cbb, (ins)); \
513                 *sp++ = mono_decompose_opcode (cfg, ins);       \
514         } while (0)
515
516 #define ADD_BINCOND(next_block) do {    \
517                 MonoInst *cmp;  \
518                 sp -= 2; \
519                 MONO_INST_NEW(cfg, cmp, OP_COMPARE);    \
520                 cmp->sreg1 = sp [0]->dreg;      \
521                 cmp->sreg2 = sp [1]->dreg;      \
522                 type_from_op (cfg, cmp, sp [0], sp [1]);        \
523                 CHECK_TYPE (cmp);       \
524                 add_widen_op (cfg, cmp, &sp [0], &sp [1]);                                              \
525                 type_from_op (cfg, ins, sp [0], sp [1]);                                                        \
526                 ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);      \
527                 GET_BBLOCK (cfg, tblock, target);               \
528                 link_bblock (cfg, cfg->cbb, tblock);    \
529                 ins->inst_true_bb = tblock;     \
530                 if ((next_block)) {     \
531                         link_bblock (cfg, cfg->cbb, (next_block));      \
532                         ins->inst_false_bb = (next_block);      \
533                         start_new_bblock = 1;   \
534                 } else {        \
535                         GET_BBLOCK (cfg, tblock, ip);           \
536                         link_bblock (cfg, cfg->cbb, tblock);    \
537                         ins->inst_false_bb = tblock;    \
538                         start_new_bblock = 2;   \
539                 }       \
540                 if (sp != stack_start) {                                                                        \
541                     handle_stack_args (cfg, stack_start, sp - stack_start); \
542                         CHECK_UNVERIFIABLE (cfg); \
543                 } \
544         MONO_ADD_INS (cfg->cbb, cmp); \
545                 MONO_ADD_INS (cfg->cbb, ins);   \
546         } while (0)
547
548 /* *
549  * link_bblock: Links two basic blocks
550  *
551  * links two basic blocks in the control flow graph, the 'from'
552  * argument is the starting block and the 'to' argument is the block
553  * the control flow ends to after 'from'.
554  */
555 static void
556 link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
557 {
558         MonoBasicBlock **newa;
559         int i, found;
560
561 #if 0
562         if (from->cil_code) {
563                 if (to->cil_code)
564                         printf ("edge from IL%04x to IL_%04x\n", from->cil_code - cfg->cil_code, to->cil_code - cfg->cil_code);
565                 else
566                         printf ("edge from IL%04x to exit\n", from->cil_code - cfg->cil_code);
567         } else {
568                 if (to->cil_code)
569                         printf ("edge from entry to IL_%04x\n", to->cil_code - cfg->cil_code);
570                 else
571                         printf ("edge from entry to exit\n");
572         }
573 #endif
574
575         found = FALSE;
576         for (i = 0; i < from->out_count; ++i) {
577                 if (to == from->out_bb [i]) {
578                         found = TRUE;
579                         break;
580                 }
581         }
582         if (!found) {
583                 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (from->out_count + 1));
584                 for (i = 0; i < from->out_count; ++i) {
585                         newa [i] = from->out_bb [i];
586                 }
587                 newa [i] = to;
588                 from->out_count++;
589                 from->out_bb = newa;
590         }
591
592         found = FALSE;
593         for (i = 0; i < to->in_count; ++i) {
594                 if (from == to->in_bb [i]) {
595                         found = TRUE;
596                         break;
597                 }
598         }
599         if (!found) {
600                 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (to->in_count + 1));
601                 for (i = 0; i < to->in_count; ++i) {
602                         newa [i] = to->in_bb [i];
603                 }
604                 newa [i] = from;
605                 to->in_count++;
606                 to->in_bb = newa;
607         }
608 }
609
610 void
611 mono_link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
612 {
613         link_bblock (cfg, from, to);
614 }
615
616 /**
617  * mono_find_block_region:
618  *
619  *   We mark each basic block with a region ID. We use that to avoid BB
620  *   optimizations when blocks are in different regions.
621  *
622  * Returns:
623  *   A region token that encodes where this region is, and information
624  *   about the clause owner for this block.
625  *
626  *   The region encodes the try/catch/filter clause that owns this block
627  *   as well as the type.  -1 is a special value that represents a block
628  *   that is in none of try/catch/filter.
629  */
630 static int
631 mono_find_block_region (MonoCompile *cfg, int offset)
632 {
633         MonoMethodHeader *header = cfg->header;
634         MonoExceptionClause *clause;
635         int i;
636
637         for (i = 0; i < header->num_clauses; ++i) {
638                 clause = &header->clauses [i];
639                 if ((clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) && (offset >= clause->data.filter_offset) &&
640                     (offset < (clause->handler_offset)))
641                         return ((i + 1) << 8) | MONO_REGION_FILTER | clause->flags;
642                            
643                 if (MONO_OFFSET_IN_HANDLER (clause, offset)) {
644                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY)
645                                 return ((i + 1) << 8) | MONO_REGION_FINALLY | clause->flags;
646                         else if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
647                                 return ((i + 1) << 8) | MONO_REGION_FAULT | clause->flags;
648                         else
649                                 return ((i + 1) << 8) | MONO_REGION_CATCH | clause->flags;
650                 }
651         }
652         for (i = 0; i < header->num_clauses; ++i) {
653                 clause = &header->clauses [i];
654
655                 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
656                         return ((i + 1) << 8) | clause->flags;
657         }
658
659         return -1;
660 }
661
662 static GList*
663 mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *target, int type)
664 {
665         MonoMethodHeader *header = cfg->header;
666         MonoExceptionClause *clause;
667         int i;
668         GList *res = NULL;
669
670         for (i = 0; i < header->num_clauses; ++i) {
671                 clause = &header->clauses [i];
672                 if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) && 
673                     (!MONO_OFFSET_IN_CLAUSE (clause, (target - header->code)))) {
674                         if (clause->flags == type)
675                                 res = g_list_append (res, clause);
676                 }
677         }
678         return res;
679 }
680
681 static void
682 mono_create_spvar_for_region (MonoCompile *cfg, int region)
683 {
684         MonoInst *var;
685
686         var = g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
687         if (var)
688                 return;
689
690         var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
691         /* prevent it from being register allocated */
692         var->flags |= MONO_INST_VOLATILE;
693
694         g_hash_table_insert (cfg->spvars, GINT_TO_POINTER (region), var);
695 }
696
697 MonoInst *
698 mono_find_exvar_for_offset (MonoCompile *cfg, int offset)
699 {
700         return g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
701 }
702
703 static MonoInst*
704 mono_create_exvar_for_offset (MonoCompile *cfg, int offset)
705 {
706         MonoInst *var;
707
708         var = g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
709         if (var)
710                 return var;
711
712         var = mono_compile_create_var (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL);
713         /* prevent it from being register allocated */
714         var->flags |= MONO_INST_VOLATILE;
715
716         g_hash_table_insert (cfg->exvars, GINT_TO_POINTER (offset), var);
717
718         return var;
719 }
720
721 /*
722  * Returns the type used in the eval stack when @type is loaded.
723  * FIXME: return a MonoType/MonoClass for the byref and VALUETYPE cases.
724  */
725 void
726 type_to_eval_stack_type (MonoCompile *cfg, MonoType *type, MonoInst *inst)
727 {
728         MonoClass *klass;
729
730         type = mini_get_underlying_type (type);
731         inst->klass = klass = mono_class_from_mono_type (type);
732         if (type->byref) {
733                 inst->type = STACK_MP;
734                 return;
735         }
736
737 handle_enum:
738         switch (type->type) {
739         case MONO_TYPE_VOID:
740                 inst->type = STACK_INV;
741                 return;
742         case MONO_TYPE_I1:
743         case MONO_TYPE_U1:
744         case MONO_TYPE_I2:
745         case MONO_TYPE_U2:
746         case MONO_TYPE_I4:
747         case MONO_TYPE_U4:
748                 inst->type = STACK_I4;
749                 return;
750         case MONO_TYPE_I:
751         case MONO_TYPE_U:
752         case MONO_TYPE_PTR:
753         case MONO_TYPE_FNPTR:
754                 inst->type = STACK_PTR;
755                 return;
756         case MONO_TYPE_CLASS:
757         case MONO_TYPE_STRING:
758         case MONO_TYPE_OBJECT:
759         case MONO_TYPE_SZARRAY:
760         case MONO_TYPE_ARRAY:    
761                 inst->type = STACK_OBJ;
762                 return;
763         case MONO_TYPE_I8:
764         case MONO_TYPE_U8:
765                 inst->type = STACK_I8;
766                 return;
767         case MONO_TYPE_R4:
768                 inst->type = cfg->r4_stack_type;
769                 break;
770         case MONO_TYPE_R8:
771                 inst->type = STACK_R8;
772                 return;
773         case MONO_TYPE_VALUETYPE:
774                 if (type->data.klass->enumtype) {
775                         type = mono_class_enum_basetype (type->data.klass);
776                         goto handle_enum;
777                 } else {
778                         inst->klass = klass;
779                         inst->type = STACK_VTYPE;
780                         return;
781                 }
782         case MONO_TYPE_TYPEDBYREF:
783                 inst->klass = mono_defaults.typed_reference_class;
784                 inst->type = STACK_VTYPE;
785                 return;
786         case MONO_TYPE_GENERICINST:
787                 type = &type->data.generic_class->container_class->byval_arg;
788                 goto handle_enum;
789         case MONO_TYPE_VAR:
790         case MONO_TYPE_MVAR:
791                 g_assert (cfg->gshared);
792                 if (mini_is_gsharedvt_type (type)) {
793                         g_assert (cfg->gsharedvt);
794                         inst->type = STACK_VTYPE;
795                 } else {
796                         type_to_eval_stack_type (cfg, mini_get_underlying_type (type), inst);
797                 }
798                 return;
799         default:
800                 g_error ("unknown type 0x%02x in eval stack type", type->type);
801         }
802 }
803
804 /*
805  * The following tables are used to quickly validate the IL code in type_from_op ().
806  */
807 static const char
808 bin_num_table [STACK_MAX] [STACK_MAX] = {
809         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
810         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
811         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
812         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
813         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8,  STACK_INV, STACK_INV, STACK_INV, STACK_R8},
814         {STACK_INV, STACK_MP,  STACK_INV, STACK_MP,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV},
815         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
816         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
817         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8, STACK_INV, STACK_INV, STACK_INV, STACK_R4}
818 };
819
820 static const char 
821 neg_table [] = {
822         STACK_INV, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_INV, STACK_INV, STACK_INV, STACK_R4
823 };
824
825 /* reduce the size of this table */
826 static const char
827 bin_int_table [STACK_MAX] [STACK_MAX] = {
828         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
829         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
830         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
831         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
832         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
833         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
834         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
835         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
836 };
837
838 static const char
839 bin_comp_table [STACK_MAX] [STACK_MAX] = {
840 /*      Inv i  L  p  F  &  O  vt r4 */
841         {0},
842         {0, 1, 0, 1, 0, 0, 0, 0}, /* i, int32 */
843         {0, 0, 1, 0, 0, 0, 0, 0}, /* L, int64 */
844         {0, 1, 0, 1, 0, 2, 4, 0}, /* p, ptr */
845         {0, 0, 0, 0, 1, 0, 0, 0, 1}, /* F, R8 */
846         {0, 0, 0, 2, 0, 1, 0, 0}, /* &, managed pointer */
847         {0, 0, 0, 4, 0, 0, 3, 0}, /* O, reference */
848         {0, 0, 0, 0, 0, 0, 0, 0}, /* vt value type */
849         {0, 0, 0, 0, 1, 0, 0, 0, 1}, /* r, r4 */
850 };
851
852 /* reduce the size of this table */
853 static const char
854 shift_table [STACK_MAX] [STACK_MAX] = {
855         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
856         {STACK_INV, STACK_I4,  STACK_INV, STACK_I4,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
857         {STACK_INV, STACK_I8,  STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
858         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
859         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
860         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
861         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
862         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
863 };
864
865 /*
866  * Tables to map from the non-specific opcode to the matching
867  * type-specific opcode.
868  */
869 /* handles from CEE_ADD to CEE_SHR_UN (CEE_REM_UN for floats) */
870 static const guint16
871 binops_op_map [STACK_MAX] = {
872         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
873 };
874
875 /* handles from CEE_NEG to CEE_CONV_U8 */
876 static const guint16
877 unops_op_map [STACK_MAX] = {
878         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
879 };
880
881 /* handles from CEE_CONV_U2 to CEE_SUB_OVF_UN */
882 static const guint16
883 ovfops_op_map [STACK_MAX] = {
884         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
885 };
886
887 /* handles from CEE_CONV_OVF_I1_UN to CEE_CONV_OVF_U_UN */
888 static const guint16
889 ovf2ops_op_map [STACK_MAX] = {
890         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
891 };
892
893 /* handles from CEE_CONV_OVF_I1 to CEE_CONV_OVF_U8 */
894 static const guint16
895 ovf3ops_op_map [STACK_MAX] = {
896         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
897 };
898
899 /* handles from CEE_BEQ to CEE_BLT_UN */
900 static const guint16
901 beqops_op_map [STACK_MAX] = {
902         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
903 };
904
905 /* handles from CEE_CEQ to CEE_CLT_UN */
906 static const guint16
907 ceqops_op_map [STACK_MAX] = {
908         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
909 };
910
911 /*
912  * Sets ins->type (the type on the eval stack) according to the
913  * type of the opcode and the arguments to it.
914  * Invalid IL code is marked by setting ins->type to the invalid value STACK_INV.
915  *
916  * FIXME: this function sets ins->type unconditionally in some cases, but
917  * it should set it to invalid for some types (a conv.x on an object)
918  */
919 static void
920 type_from_op (MonoCompile *cfg, MonoInst *ins, MonoInst *src1, MonoInst *src2)
921 {
922         switch (ins->opcode) {
923         /* binops */
924         case CEE_ADD:
925         case CEE_SUB:
926         case CEE_MUL:
927         case CEE_DIV:
928         case CEE_REM:
929                 /* FIXME: check unverifiable args for STACK_MP */
930                 ins->type = bin_num_table [src1->type] [src2->type];
931                 ins->opcode += binops_op_map [ins->type];
932                 break;
933         case CEE_DIV_UN:
934         case CEE_REM_UN:
935         case CEE_AND:
936         case CEE_OR:
937         case CEE_XOR:
938                 ins->type = bin_int_table [src1->type] [src2->type];
939                 ins->opcode += binops_op_map [ins->type];
940                 break;
941         case CEE_SHL:
942         case CEE_SHR:
943         case CEE_SHR_UN:
944                 ins->type = shift_table [src1->type] [src2->type];
945                 ins->opcode += binops_op_map [ins->type];
946                 break;
947         case OP_COMPARE:
948         case OP_LCOMPARE:
949         case OP_ICOMPARE:
950                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
951                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
952                         ins->opcode = OP_LCOMPARE;
953                 else if (src1->type == STACK_R4)
954                         ins->opcode = OP_RCOMPARE;
955                 else if (src1->type == STACK_R8)
956                         ins->opcode = OP_FCOMPARE;
957                 else
958                         ins->opcode = OP_ICOMPARE;
959                 break;
960         case OP_ICOMPARE_IMM:
961                 ins->type = bin_comp_table [src1->type] [src1->type] ? STACK_I4 : STACK_INV;
962                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
963                         ins->opcode = OP_LCOMPARE_IMM;          
964                 break;
965         case CEE_BEQ:
966         case CEE_BGE:
967         case CEE_BGT:
968         case CEE_BLE:
969         case CEE_BLT:
970         case CEE_BNE_UN:
971         case CEE_BGE_UN:
972         case CEE_BGT_UN:
973         case CEE_BLE_UN:
974         case CEE_BLT_UN:
975                 ins->opcode += beqops_op_map [src1->type];
976                 break;
977         case OP_CEQ:
978                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
979                 ins->opcode += ceqops_op_map [src1->type];
980                 break;
981         case OP_CGT:
982         case OP_CGT_UN:
983         case OP_CLT:
984         case OP_CLT_UN:
985                 ins->type = (bin_comp_table [src1->type] [src2->type] & 1) ? STACK_I4: STACK_INV;
986                 ins->opcode += ceqops_op_map [src1->type];
987                 break;
988         /* unops */
989         case CEE_NEG:
990                 ins->type = neg_table [src1->type];
991                 ins->opcode += unops_op_map [ins->type];
992                 break;
993         case CEE_NOT:
994                 if (src1->type >= STACK_I4 && src1->type <= STACK_PTR)
995                         ins->type = src1->type;
996                 else
997                         ins->type = STACK_INV;
998                 ins->opcode += unops_op_map [ins->type];
999                 break;
1000         case CEE_CONV_I1:
1001         case CEE_CONV_I2:
1002         case CEE_CONV_I4:
1003         case CEE_CONV_U4:
1004                 ins->type = STACK_I4;
1005                 ins->opcode += unops_op_map [src1->type];
1006                 break;
1007         case CEE_CONV_R_UN:
1008                 ins->type = STACK_R8;
1009                 switch (src1->type) {
1010                 case STACK_I4:
1011                 case STACK_PTR:
1012                         ins->opcode = OP_ICONV_TO_R_UN;
1013                         break;
1014                 case STACK_I8:
1015                         ins->opcode = OP_LCONV_TO_R_UN; 
1016                         break;
1017                 }
1018                 break;
1019         case CEE_CONV_OVF_I1:
1020         case CEE_CONV_OVF_U1:
1021         case CEE_CONV_OVF_I2:
1022         case CEE_CONV_OVF_U2:
1023         case CEE_CONV_OVF_I4:
1024         case CEE_CONV_OVF_U4:
1025                 ins->type = STACK_I4;
1026                 ins->opcode += ovf3ops_op_map [src1->type];
1027                 break;
1028         case CEE_CONV_OVF_I_UN:
1029         case CEE_CONV_OVF_U_UN:
1030                 ins->type = STACK_PTR;
1031                 ins->opcode += ovf2ops_op_map [src1->type];
1032                 break;
1033         case CEE_CONV_OVF_I1_UN:
1034         case CEE_CONV_OVF_I2_UN:
1035         case CEE_CONV_OVF_I4_UN:
1036         case CEE_CONV_OVF_U1_UN:
1037         case CEE_CONV_OVF_U2_UN:
1038         case CEE_CONV_OVF_U4_UN:
1039                 ins->type = STACK_I4;
1040                 ins->opcode += ovf2ops_op_map [src1->type];
1041                 break;
1042         case CEE_CONV_U:
1043                 ins->type = STACK_PTR;
1044                 switch (src1->type) {
1045                 case STACK_I4:
1046                         ins->opcode = OP_ICONV_TO_U;
1047                         break;
1048                 case STACK_PTR:
1049                 case STACK_MP:
1050 #if SIZEOF_VOID_P == 8
1051                         ins->opcode = OP_LCONV_TO_U;
1052 #else
1053                         ins->opcode = OP_MOVE;
1054 #endif
1055                         break;
1056                 case STACK_I8:
1057                         ins->opcode = OP_LCONV_TO_U;
1058                         break;
1059                 case STACK_R8:
1060                         ins->opcode = OP_FCONV_TO_U;
1061                         break;
1062                 }
1063                 break;
1064         case CEE_CONV_I8:
1065         case CEE_CONV_U8:
1066                 ins->type = STACK_I8;
1067                 ins->opcode += unops_op_map [src1->type];
1068                 break;
1069         case CEE_CONV_OVF_I8:
1070         case CEE_CONV_OVF_U8:
1071                 ins->type = STACK_I8;
1072                 ins->opcode += ovf3ops_op_map [src1->type];
1073                 break;
1074         case CEE_CONV_OVF_U8_UN:
1075         case CEE_CONV_OVF_I8_UN:
1076                 ins->type = STACK_I8;
1077                 ins->opcode += ovf2ops_op_map [src1->type];
1078                 break;
1079         case CEE_CONV_R4:
1080                 ins->type = cfg->r4_stack_type;
1081                 ins->opcode += unops_op_map [src1->type];
1082                 break;
1083         case CEE_CONV_R8:
1084                 ins->type = STACK_R8;
1085                 ins->opcode += unops_op_map [src1->type];
1086                 break;
1087         case OP_CKFINITE:
1088                 ins->type = STACK_R8;           
1089                 break;
1090         case CEE_CONV_U2:
1091         case CEE_CONV_U1:
1092                 ins->type = STACK_I4;
1093                 ins->opcode += ovfops_op_map [src1->type];
1094                 break;
1095         case CEE_CONV_I:
1096         case CEE_CONV_OVF_I:
1097         case CEE_CONV_OVF_U:
1098                 ins->type = STACK_PTR;
1099                 ins->opcode += ovfops_op_map [src1->type];
1100                 break;
1101         case CEE_ADD_OVF:
1102         case CEE_ADD_OVF_UN:
1103         case CEE_MUL_OVF:
1104         case CEE_MUL_OVF_UN:
1105         case CEE_SUB_OVF:
1106         case CEE_SUB_OVF_UN:
1107                 ins->type = bin_num_table [src1->type] [src2->type];
1108                 ins->opcode += ovfops_op_map [src1->type];
1109                 if (ins->type == STACK_R8)
1110                         ins->type = STACK_INV;
1111                 break;
1112         case OP_LOAD_MEMBASE:
1113                 ins->type = STACK_PTR;
1114                 break;
1115         case OP_LOADI1_MEMBASE:
1116         case OP_LOADU1_MEMBASE:
1117         case OP_LOADI2_MEMBASE:
1118         case OP_LOADU2_MEMBASE:
1119         case OP_LOADI4_MEMBASE:
1120         case OP_LOADU4_MEMBASE:
1121                 ins->type = STACK_PTR;
1122                 break;
1123         case OP_LOADI8_MEMBASE:
1124                 ins->type = STACK_I8;
1125                 break;
1126         case OP_LOADR4_MEMBASE:
1127                 ins->type = cfg->r4_stack_type;
1128                 break;
1129         case OP_LOADR8_MEMBASE:
1130                 ins->type = STACK_R8;
1131                 break;
1132         default:
1133                 g_error ("opcode 0x%04x not handled in type from op", ins->opcode);
1134                 break;
1135         }
1136
1137         if (ins->type == STACK_MP)
1138                 ins->klass = mono_defaults.object_class;
1139 }
1140
1141 static const char 
1142 ldind_type [] = {
1143         STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_R8, STACK_OBJ
1144 };
1145
1146 #if 0
1147
1148 static const char
1149 param_table [STACK_MAX] [STACK_MAX] = {
1150         {0},
1151 };
1152
1153 static int
1154 check_values_to_signature (MonoInst *args, MonoType *this_ins, MonoMethodSignature *sig)
1155 {
1156         int i;
1157
1158         if (sig->hasthis) {
1159                 switch (args->type) {
1160                 case STACK_I4:
1161                 case STACK_I8:
1162                 case STACK_R8:
1163                 case STACK_VTYPE:
1164                 case STACK_INV:
1165                         return 0;
1166                 }
1167                 args++;
1168         }
1169         for (i = 0; i < sig->param_count; ++i) {
1170                 switch (args [i].type) {
1171                 case STACK_INV:
1172                         return 0;
1173                 case STACK_MP:
1174                         if (!sig->params [i]->byref)
1175                                 return 0;
1176                         continue;
1177                 case STACK_OBJ:
1178                         if (sig->params [i]->byref)
1179                                 return 0;
1180                         switch (sig->params [i]->type) {
1181                         case MONO_TYPE_CLASS:
1182                         case MONO_TYPE_STRING:
1183                         case MONO_TYPE_OBJECT:
1184                         case MONO_TYPE_SZARRAY:
1185                         case MONO_TYPE_ARRAY:
1186                                 break;
1187                         default:
1188                                 return 0;
1189                         }
1190                         continue;
1191                 case STACK_R8:
1192                         if (sig->params [i]->byref)
1193                                 return 0;
1194                         if (sig->params [i]->type != MONO_TYPE_R4 && sig->params [i]->type != MONO_TYPE_R8)
1195                                 return 0;
1196                         continue;
1197                 case STACK_PTR:
1198                 case STACK_I4:
1199                 case STACK_I8:
1200                 case STACK_VTYPE:
1201                         break;
1202                 }
1203                 /*if (!param_table [args [i].type] [sig->params [i]->type])
1204                         return 0;*/
1205         }
1206         return 1;
1207 }
1208 #endif
1209
1210 /*
1211  * When we need a pointer to the current domain many times in a method, we
1212  * call mono_domain_get() once and we store the result in a local variable.
1213  * This function returns the variable that represents the MonoDomain*.
1214  */
1215 inline static MonoInst *
1216 mono_get_domainvar (MonoCompile *cfg)
1217 {
1218         if (!cfg->domainvar)
1219                 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1220         return cfg->domainvar;
1221 }
1222
1223 /*
1224  * The got_var contains the address of the Global Offset Table when AOT 
1225  * compiling.
1226  */
1227 MonoInst *
1228 mono_get_got_var (MonoCompile *cfg)
1229 {
1230 #ifdef MONO_ARCH_NEED_GOT_VAR
1231         if (!cfg->compile_aot)
1232                 return NULL;
1233         if (!cfg->got_var) {
1234                 cfg->got_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1235         }
1236         return cfg->got_var;
1237 #else
1238         return NULL;
1239 #endif
1240 }
1241
1242 static MonoInst *
1243 mono_get_vtable_var (MonoCompile *cfg)
1244 {
1245         g_assert (cfg->gshared);
1246
1247         if (!cfg->rgctx_var) {
1248                 cfg->rgctx_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1249                 /* force the var to be stack allocated */
1250                 cfg->rgctx_var->flags |= MONO_INST_VOLATILE;
1251         }
1252
1253         return cfg->rgctx_var;
1254 }
1255
1256 static MonoType*
1257 type_from_stack_type (MonoInst *ins) {
1258         switch (ins->type) {
1259         case STACK_I4: return &mono_defaults.int32_class->byval_arg;
1260         case STACK_I8: return &mono_defaults.int64_class->byval_arg;
1261         case STACK_PTR: return &mono_defaults.int_class->byval_arg;
1262         case STACK_R4: return &mono_defaults.single_class->byval_arg;
1263         case STACK_R8: return &mono_defaults.double_class->byval_arg;
1264         case STACK_MP:
1265                 return &ins->klass->this_arg;
1266         case STACK_OBJ: return &mono_defaults.object_class->byval_arg;
1267         case STACK_VTYPE: return &ins->klass->byval_arg;
1268         default:
1269                 g_error ("stack type %d to monotype not handled\n", ins->type);
1270         }
1271         return NULL;
1272 }
1273
1274 static G_GNUC_UNUSED int
1275 type_to_stack_type (MonoCompile *cfg, MonoType *t)
1276 {
1277         t = mono_type_get_underlying_type (t);
1278         switch (t->type) {
1279         case MONO_TYPE_I1:
1280         case MONO_TYPE_U1:
1281         case MONO_TYPE_I2:
1282         case MONO_TYPE_U2:
1283         case MONO_TYPE_I4:
1284         case MONO_TYPE_U4:
1285                 return STACK_I4;
1286         case MONO_TYPE_I:
1287         case MONO_TYPE_U:
1288         case MONO_TYPE_PTR:
1289         case MONO_TYPE_FNPTR:
1290                 return STACK_PTR;
1291         case MONO_TYPE_CLASS:
1292         case MONO_TYPE_STRING:
1293         case MONO_TYPE_OBJECT:
1294         case MONO_TYPE_SZARRAY:
1295         case MONO_TYPE_ARRAY:    
1296                 return STACK_OBJ;
1297         case MONO_TYPE_I8:
1298         case MONO_TYPE_U8:
1299                 return STACK_I8;
1300         case MONO_TYPE_R4:
1301                 return cfg->r4_stack_type;
1302         case MONO_TYPE_R8:
1303                 return STACK_R8;
1304         case MONO_TYPE_VALUETYPE:
1305         case MONO_TYPE_TYPEDBYREF:
1306                 return STACK_VTYPE;
1307         case MONO_TYPE_GENERICINST:
1308                 if (mono_type_generic_inst_is_valuetype (t))
1309                         return STACK_VTYPE;
1310                 else
1311                         return STACK_OBJ;
1312                 break;
1313         default:
1314                 g_assert_not_reached ();
1315         }
1316
1317         return -1;
1318 }
1319
1320 static MonoClass*
1321 array_access_to_klass (int opcode)
1322 {
1323         switch (opcode) {
1324         case CEE_LDELEM_U1:
1325                 return mono_defaults.byte_class;
1326         case CEE_LDELEM_U2:
1327                 return mono_defaults.uint16_class;
1328         case CEE_LDELEM_I:
1329         case CEE_STELEM_I:
1330                 return mono_defaults.int_class;
1331         case CEE_LDELEM_I1:
1332         case CEE_STELEM_I1:
1333                 return mono_defaults.sbyte_class;
1334         case CEE_LDELEM_I2:
1335         case CEE_STELEM_I2:
1336                 return mono_defaults.int16_class;
1337         case CEE_LDELEM_I4:
1338         case CEE_STELEM_I4:
1339                 return mono_defaults.int32_class;
1340         case CEE_LDELEM_U4:
1341                 return mono_defaults.uint32_class;
1342         case CEE_LDELEM_I8:
1343         case CEE_STELEM_I8:
1344                 return mono_defaults.int64_class;
1345         case CEE_LDELEM_R4:
1346         case CEE_STELEM_R4:
1347                 return mono_defaults.single_class;
1348         case CEE_LDELEM_R8:
1349         case CEE_STELEM_R8:
1350                 return mono_defaults.double_class;
1351         case CEE_LDELEM_REF:
1352         case CEE_STELEM_REF:
1353                 return mono_defaults.object_class;
1354         default:
1355                 g_assert_not_reached ();
1356         }
1357         return NULL;
1358 }
1359
1360 /*
1361  * We try to share variables when possible
1362  */
1363 static MonoInst *
1364 mono_compile_get_interface_var (MonoCompile *cfg, int slot, MonoInst *ins)
1365 {
1366         MonoInst *res;
1367         int pos, vnum;
1368
1369         /* inlining can result in deeper stacks */ 
1370         if (slot >= cfg->header->max_stack)
1371                 return mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1372
1373         pos = ins->type - 1 + slot * STACK_MAX;
1374
1375         switch (ins->type) {
1376         case STACK_I4:
1377         case STACK_I8:
1378         case STACK_R8:
1379         case STACK_PTR:
1380         case STACK_MP:
1381         case STACK_OBJ:
1382                 if ((vnum = cfg->intvars [pos]))
1383                         return cfg->varinfo [vnum];
1384                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1385                 cfg->intvars [pos] = res->inst_c0;
1386                 break;
1387         default:
1388                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1389         }
1390         return res;
1391 }
1392
1393 static void
1394 mono_save_token_info (MonoCompile *cfg, MonoImage *image, guint32 token, gpointer key)
1395 {
1396         /* 
1397          * Don't use this if a generic_context is set, since that means AOT can't
1398          * look up the method using just the image+token.
1399          * table == 0 means this is a reference made from a wrapper.
1400          */
1401         if (cfg->compile_aot && !cfg->generic_context && (mono_metadata_token_table (token) > 0)) {
1402                 MonoJumpInfoToken *jump_info_token = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoToken));
1403                 jump_info_token->image = image;
1404                 jump_info_token->token = token;
1405                 g_hash_table_insert (cfg->token_info_hash, key, jump_info_token);
1406         }
1407 }
1408
1409 /*
1410  * This function is called to handle items that are left on the evaluation stack
1411  * at basic block boundaries. What happens is that we save the values to local variables
1412  * and we reload them later when first entering the target basic block (with the
1413  * handle_loaded_temps () function).
1414  * A single joint point will use the same variables (stored in the array bb->out_stack or
1415  * bb->in_stack, if the basic block is before or after the joint point).
1416  *
1417  * This function needs to be called _before_ emitting the last instruction of
1418  * the bb (i.e. before emitting a branch).
1419  * If the stack merge fails at a join point, cfg->unverifiable is set.
1420  */
1421 static void
1422 handle_stack_args (MonoCompile *cfg, MonoInst **sp, int count)
1423 {
1424         int i, bindex;
1425         MonoBasicBlock *bb = cfg->cbb;
1426         MonoBasicBlock *outb;
1427         MonoInst *inst, **locals;
1428         gboolean found;
1429
1430         if (!count)
1431                 return;
1432         if (cfg->verbose_level > 3)
1433                 printf ("%d item(s) on exit from B%d\n", count, bb->block_num);
1434         if (!bb->out_scount) {
1435                 bb->out_scount = count;
1436                 //printf ("bblock %d has out:", bb->block_num);
1437                 found = FALSE;
1438                 for (i = 0; i < bb->out_count; ++i) {
1439                         outb = bb->out_bb [i];
1440                         /* exception handlers are linked, but they should not be considered for stack args */
1441                         if (outb->flags & BB_EXCEPTION_HANDLER)
1442                                 continue;
1443                         //printf (" %d", outb->block_num);
1444                         if (outb->in_stack) {
1445                                 found = TRUE;
1446                                 bb->out_stack = outb->in_stack;
1447                                 break;
1448                         }
1449                 }
1450                 //printf ("\n");
1451                 if (!found) {
1452                         bb->out_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * count);
1453                         for (i = 0; i < count; ++i) {
1454                                 /* 
1455                                  * try to reuse temps already allocated for this purpouse, if they occupy the same
1456                                  * stack slot and if they are of the same type.
1457                                  * This won't cause conflicts since if 'local' is used to 
1458                                  * store one of the values in the in_stack of a bblock, then
1459                                  * the same variable will be used for the same outgoing stack 
1460                                  * slot as well. 
1461                                  * This doesn't work when inlining methods, since the bblocks
1462                                  * in the inlined methods do not inherit their in_stack from
1463                                  * the bblock they are inlined to. See bug #58863 for an
1464                                  * example.
1465                                  */
1466                                 if (cfg->inlined_method)
1467                                         bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
1468                                 else
1469                                         bb->out_stack [i] = mono_compile_get_interface_var (cfg, i, sp [i]);
1470                         }
1471                 }
1472         }
1473
1474         for (i = 0; i < bb->out_count; ++i) {
1475                 outb = bb->out_bb [i];
1476                 /* exception handlers are linked, but they should not be considered for stack args */
1477                 if (outb->flags & BB_EXCEPTION_HANDLER)
1478                         continue;
1479                 if (outb->in_scount) {
1480                         if (outb->in_scount != bb->out_scount) {
1481                                 cfg->unverifiable = TRUE;
1482                                 return;
1483                         }
1484                         continue; /* check they are the same locals */
1485                 }
1486                 outb->in_scount = count;
1487                 outb->in_stack = bb->out_stack;
1488         }
1489
1490         locals = bb->out_stack;
1491         cfg->cbb = bb;
1492         for (i = 0; i < count; ++i) {
1493                 EMIT_NEW_TEMPSTORE (cfg, inst, locals [i]->inst_c0, sp [i]);
1494                 inst->cil_code = sp [i]->cil_code;
1495                 sp [i] = locals [i];
1496                 if (cfg->verbose_level > 3)
1497                         printf ("storing %d to temp %d\n", i, (int)locals [i]->inst_c0);
1498         }
1499
1500         /*
1501          * It is possible that the out bblocks already have in_stack assigned, and
1502          * the in_stacks differ. In this case, we will store to all the different 
1503          * in_stacks.
1504          */
1505
1506         found = TRUE;
1507         bindex = 0;
1508         while (found) {
1509                 /* Find a bblock which has a different in_stack */
1510                 found = FALSE;
1511                 while (bindex < bb->out_count) {
1512                         outb = bb->out_bb [bindex];
1513                         /* exception handlers are linked, but they should not be considered for stack args */
1514                         if (outb->flags & BB_EXCEPTION_HANDLER) {
1515                                 bindex++;
1516                                 continue;
1517                         }
1518                         if (outb->in_stack != locals) {
1519                                 for (i = 0; i < count; ++i) {
1520                                         EMIT_NEW_TEMPSTORE (cfg, inst, outb->in_stack [i]->inst_c0, sp [i]);
1521                                         inst->cil_code = sp [i]->cil_code;
1522                                         sp [i] = locals [i];
1523                                         if (cfg->verbose_level > 3)
1524                                                 printf ("storing %d to temp %d\n", i, (int)outb->in_stack [i]->inst_c0);
1525                                 }
1526                                 locals = outb->in_stack;
1527                                 found = TRUE;
1528                                 break;
1529                         }
1530                         bindex ++;
1531                 }
1532         }
1533 }
1534
1535 static void
1536 mini_emit_interface_bitmap_check (MonoCompile *cfg, int intf_bit_reg, int base_reg, int offset, MonoClass *klass)
1537 {
1538         int ibitmap_reg = alloc_preg (cfg);
1539 #ifdef COMPRESSED_INTERFACE_BITMAP
1540         MonoInst *args [2];
1541         MonoInst *res, *ins;
1542         NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, ibitmap_reg, base_reg, offset);
1543         MONO_ADD_INS (cfg->cbb, ins);
1544         args [0] = ins;
1545         if (cfg->compile_aot)
1546                 EMIT_NEW_AOTCONST (cfg, args [1], MONO_PATCH_INFO_IID, klass);
1547         else
1548                 EMIT_NEW_ICONST (cfg, args [1], klass->interface_id);
1549         res = mono_emit_jit_icall (cfg, mono_class_interface_match, args);
1550         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, intf_bit_reg, res->dreg);
1551 #else
1552         int ibitmap_byte_reg = alloc_preg (cfg);
1553
1554         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, ibitmap_reg, base_reg, offset);
1555
1556         if (cfg->compile_aot) {
1557                 int iid_reg = alloc_preg (cfg);
1558                 int shifted_iid_reg = alloc_preg (cfg);
1559                 int ibitmap_byte_address_reg = alloc_preg (cfg);
1560                 int masked_iid_reg = alloc_preg (cfg);
1561                 int iid_one_bit_reg = alloc_preg (cfg);
1562                 int iid_bit_reg = alloc_preg (cfg);
1563                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1564                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, shifted_iid_reg, iid_reg, 3);
1565                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, ibitmap_byte_address_reg, ibitmap_reg, shifted_iid_reg);
1566                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, ibitmap_byte_reg, ibitmap_byte_address_reg, 0);
1567                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, masked_iid_reg, iid_reg, 7);
1568                 MONO_EMIT_NEW_ICONST (cfg, iid_one_bit_reg, 1);
1569                 MONO_EMIT_NEW_BIALU (cfg, OP_ISHL, iid_bit_reg, iid_one_bit_reg, masked_iid_reg);
1570                 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, intf_bit_reg, ibitmap_byte_reg, iid_bit_reg);
1571         } else {
1572                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, ibitmap_byte_reg, ibitmap_reg, klass->interface_id >> 3);
1573                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, intf_bit_reg, ibitmap_byte_reg, 1 << (klass->interface_id & 7));
1574         }
1575 #endif
1576 }
1577
1578 /* 
1579  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoClass
1580  * stored in "klass_reg" implements the interface "klass".
1581  */
1582 static void
1583 mini_emit_load_intf_bit_reg_class (MonoCompile *cfg, int intf_bit_reg, int klass_reg, MonoClass *klass)
1584 {
1585         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, interface_bitmap), klass);
1586 }
1587
1588 /* 
1589  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoVTable
1590  * stored in "vtable_reg" implements the interface "klass".
1591  */
1592 static void
1593 mini_emit_load_intf_bit_reg_vtable (MonoCompile *cfg, int intf_bit_reg, int vtable_reg, MonoClass *klass)
1594 {
1595         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, interface_bitmap), klass);
1596 }
1597
1598 /* 
1599  * Emit code which checks whenever the interface id of @klass is smaller than
1600  * than the value given by max_iid_reg.
1601 */
1602 static void
1603 mini_emit_max_iid_check (MonoCompile *cfg, int max_iid_reg, MonoClass *klass,
1604                                                  MonoBasicBlock *false_target)
1605 {
1606         if (cfg->compile_aot) {
1607                 int iid_reg = alloc_preg (cfg);
1608                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1609                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, max_iid_reg, iid_reg);
1610         }
1611         else
1612                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, max_iid_reg, klass->interface_id);
1613         if (false_target)
1614                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1615         else
1616                 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1617 }
1618
1619 /* Same as above, but obtains max_iid from a vtable */
1620 static void
1621 mini_emit_max_iid_check_vtable (MonoCompile *cfg, int vtable_reg, MonoClass *klass,
1622                                                                  MonoBasicBlock *false_target)
1623 {
1624         int max_iid_reg = alloc_preg (cfg);
1625                 
1626         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, max_interface_id));
1627         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1628 }
1629
1630 /* Same as above, but obtains max_iid from a klass */
1631 static void
1632 mini_emit_max_iid_check_class (MonoCompile *cfg, int klass_reg, MonoClass *klass,
1633                                                                  MonoBasicBlock *false_target)
1634 {
1635         int max_iid_reg = alloc_preg (cfg);
1636
1637         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, max_interface_id));
1638         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1639 }
1640
1641 static void
1642 mini_emit_isninst_cast_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_ins, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1643 {
1644         int idepth_reg = alloc_preg (cfg);
1645         int stypes_reg = alloc_preg (cfg);
1646         int stype = alloc_preg (cfg);
1647
1648         mono_class_setup_supertypes (klass);
1649
1650         if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1651                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth));
1652                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1653                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1654         }
1655         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes));
1656         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1657         if (klass_ins) {
1658                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, klass_ins->dreg);
1659         } else if (cfg->compile_aot) {
1660                 int const_reg = alloc_preg (cfg);
1661                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1662                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, const_reg);
1663         } else {
1664                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, stype, klass);
1665         }
1666         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, true_target);
1667 }
1668
1669 static void
1670 mini_emit_isninst_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1671 {
1672         mini_emit_isninst_cast_inst (cfg, klass_reg, klass, NULL, false_target, true_target);
1673 }
1674
1675 static void
1676 mini_emit_iface_cast (MonoCompile *cfg, int vtable_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1677 {
1678         int intf_reg = alloc_preg (cfg);
1679
1680         mini_emit_max_iid_check_vtable (cfg, vtable_reg, klass, false_target);
1681         mini_emit_load_intf_bit_reg_vtable (cfg, intf_reg, vtable_reg, klass);
1682         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_reg, 0);
1683         if (true_target)
1684                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1685         else
1686                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");               
1687 }
1688
1689 /*
1690  * Variant of the above that takes a register to the class, not the vtable.
1691  */
1692 static void
1693 mini_emit_iface_class_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1694 {
1695         int intf_bit_reg = alloc_preg (cfg);
1696
1697         mini_emit_max_iid_check_class (cfg, klass_reg, klass, false_target);
1698         mini_emit_load_intf_bit_reg_class (cfg, intf_bit_reg, klass_reg, klass);
1699         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_bit_reg, 0);
1700         if (true_target)
1701                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1702         else
1703                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
1704 }
1705
1706 static inline void
1707 mini_emit_class_check_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_inst)
1708 {
1709         if (klass_inst) {
1710                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_inst->dreg);
1711         } else if (cfg->compile_aot) {
1712                 int const_reg = alloc_preg (cfg);
1713                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1714                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, const_reg);
1715         } else {
1716                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
1717         }
1718         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1719 }
1720
1721 static inline void
1722 mini_emit_class_check (MonoCompile *cfg, int klass_reg, MonoClass *klass)
1723 {
1724         mini_emit_class_check_inst (cfg, klass_reg, klass, NULL);
1725 }
1726
1727 static inline void
1728 mini_emit_class_check_branch (MonoCompile *cfg, int klass_reg, MonoClass *klass, int branch_op, MonoBasicBlock *target)
1729 {
1730         if (cfg->compile_aot) {
1731                 int const_reg = alloc_preg (cfg);
1732                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1733                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, const_reg);
1734         } else {
1735                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
1736         }
1737         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, branch_op, target);
1738 }
1739
1740 static void
1741 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null);
1742         
1743 static void
1744 mini_emit_castclass_inst (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoInst *klass_inst, MonoBasicBlock *object_is_null)
1745 {
1746         if (klass->rank) {
1747                 int rank_reg = alloc_preg (cfg);
1748                 int eclass_reg = alloc_preg (cfg);
1749
1750                 g_assert (!klass_inst);
1751                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, rank));
1752                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
1753                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1754                 //              MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
1755                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
1756                 if (klass->cast_class == mono_defaults.object_class) {
1757                         int parent_reg = alloc_preg (cfg);
1758                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
1759                         mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, object_is_null);
1760                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1761                 } else if (klass->cast_class == mono_defaults.enum_class->parent) {
1762                         mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, object_is_null);
1763                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1764                 } else if (klass->cast_class == mono_defaults.enum_class) {
1765                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1766                 } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1767                         mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, NULL, NULL);
1768                 } else {
1769                         // Pass -1 as obj_reg to skip the check below for arrays of arrays
1770                         mini_emit_castclass (cfg, -1, eclass_reg, klass->cast_class, object_is_null);
1771                 }
1772
1773                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY) && (obj_reg != -1)) {
1774                         /* Check that the object is a vector too */
1775                         int bounds_reg = alloc_preg (cfg);
1776                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
1777                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
1778                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1779                 }
1780         } else {
1781                 int idepth_reg = alloc_preg (cfg);
1782                 int stypes_reg = alloc_preg (cfg);
1783                 int stype = alloc_preg (cfg);
1784
1785                 mono_class_setup_supertypes (klass);
1786
1787                 if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1788                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth));
1789                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1790                         MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1791                 }
1792                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes));
1793                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1794                 mini_emit_class_check_inst (cfg, stype, klass, klass_inst);
1795         }
1796 }
1797
1798 static void
1799 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null)
1800 {
1801         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, NULL, object_is_null);
1802 }
1803
1804 static void 
1805 mini_emit_memset (MonoCompile *cfg, int destreg, int offset, int size, int val, int align)
1806 {
1807         int val_reg;
1808
1809         g_assert (val == 0);
1810
1811         if (align == 0)
1812                 align = 4;
1813
1814         if ((size <= SIZEOF_REGISTER) && (size <= align)) {
1815                 switch (size) {
1816                 case 1:
1817                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, destreg, offset, val);
1818                         return;
1819                 case 2:
1820                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI2_MEMBASE_IMM, destreg, offset, val);
1821                         return;
1822                 case 4:
1823                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI4_MEMBASE_IMM, destreg, offset, val);
1824                         return;
1825 #if SIZEOF_REGISTER == 8
1826                 case 8:
1827                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI8_MEMBASE_IMM, destreg, offset, val);
1828                         return;
1829 #endif
1830                 }
1831         }
1832
1833         val_reg = alloc_preg (cfg);
1834
1835         if (SIZEOF_REGISTER == 8)
1836                 MONO_EMIT_NEW_I8CONST (cfg, val_reg, val);
1837         else
1838                 MONO_EMIT_NEW_ICONST (cfg, val_reg, val);
1839
1840         if (align < 4) {
1841                 /* This could be optimized further if neccesary */
1842                 while (size >= 1) {
1843                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1844                         offset += 1;
1845                         size -= 1;
1846                 }
1847                 return;
1848         }       
1849
1850 #if !NO_UNALIGNED_ACCESS
1851         if (SIZEOF_REGISTER == 8) {
1852                 if (offset % 8) {
1853                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1854                         offset += 4;
1855                         size -= 4;
1856                 }
1857                 while (size >= 8) {
1858                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, offset, val_reg);
1859                         offset += 8;
1860                         size -= 8;
1861                 }
1862         }       
1863 #endif
1864
1865         while (size >= 4) {
1866                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1867                 offset += 4;
1868                 size -= 4;
1869         }
1870         while (size >= 2) {
1871                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, val_reg);
1872                 offset += 2;
1873                 size -= 2;
1874         }
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 }
1881
1882 void 
1883 mini_emit_memcpy (MonoCompile *cfg, int destreg, int doffset, int srcreg, int soffset, int size, int align)
1884 {
1885         int cur_reg;
1886
1887         if (align == 0)
1888                 align = 4;
1889
1890         /*FIXME arbitrary hack to avoid unbound code expansion.*/
1891         g_assert (size < 10000);
1892
1893         if (align < 4) {
1894                 /* This could be optimized further if neccesary */
1895                 while (size >= 1) {
1896                         cur_reg = alloc_preg (cfg);
1897                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1898                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1899                         doffset += 1;
1900                         soffset += 1;
1901                         size -= 1;
1902                 }
1903         }
1904
1905 #if !NO_UNALIGNED_ACCESS
1906         if (SIZEOF_REGISTER == 8) {
1907                 while (size >= 8) {
1908                         cur_reg = alloc_preg (cfg);
1909                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI8_MEMBASE, cur_reg, srcreg, soffset);
1910                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, doffset, cur_reg);
1911                         doffset += 8;
1912                         soffset += 8;
1913                         size -= 8;
1914                 }
1915         }       
1916 #endif
1917
1918         while (size >= 4) {
1919                 cur_reg = alloc_preg (cfg);
1920                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, cur_reg, srcreg, soffset);
1921                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, doffset, cur_reg);
1922                 doffset += 4;
1923                 soffset += 4;
1924                 size -= 4;
1925         }
1926         while (size >= 2) {
1927                 cur_reg = alloc_preg (cfg);
1928                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, cur_reg, srcreg, soffset);
1929                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, doffset, cur_reg);
1930                 doffset += 2;
1931                 soffset += 2;
1932                 size -= 2;
1933         }
1934         while (size >= 1) {
1935                 cur_reg = alloc_preg (cfg);
1936                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1937                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1938                 doffset += 1;
1939                 soffset += 1;
1940                 size -= 1;
1941         }
1942 }
1943
1944 static void
1945 emit_tls_set (MonoCompile *cfg, int sreg1, int tls_key)
1946 {
1947         MonoInst *ins, *c;
1948
1949         if (cfg->compile_aot) {
1950                 EMIT_NEW_TLS_OFFSETCONST (cfg, c, tls_key);
1951                 MONO_INST_NEW (cfg, ins, OP_TLS_SET_REG);
1952                 ins->sreg1 = sreg1;
1953                 ins->sreg2 = c->dreg;
1954                 MONO_ADD_INS (cfg->cbb, ins);
1955         } else {
1956                 MONO_INST_NEW (cfg, ins, OP_TLS_SET);
1957                 ins->sreg1 = sreg1;
1958                 ins->inst_offset = mini_get_tls_offset (tls_key);
1959                 MONO_ADD_INS (cfg->cbb, ins);
1960         }
1961 }
1962
1963 /*
1964  * emit_push_lmf:
1965  *
1966  *   Emit IR to push the current LMF onto the LMF stack.
1967  */
1968 static void
1969 emit_push_lmf (MonoCompile *cfg)
1970 {
1971         /*
1972          * Emit IR to push the LMF:
1973          * lmf_addr = <lmf_addr from tls>
1974          * lmf->lmf_addr = lmf_addr
1975          * lmf->prev_lmf = *lmf_addr
1976          * *lmf_addr = lmf
1977          */
1978         int lmf_reg, prev_lmf_reg;
1979         MonoInst *ins, *lmf_ins;
1980
1981         if (!cfg->lmf_ir)
1982                 return;
1983
1984         if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
1985                 /* Load current lmf */
1986                 lmf_ins = mono_get_lmf_intrinsic (cfg);
1987                 g_assert (lmf_ins);
1988                 MONO_ADD_INS (cfg->cbb, lmf_ins);
1989                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
1990                 lmf_reg = ins->dreg;
1991                 /* Save previous_lmf */
1992                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), lmf_ins->dreg);
1993                 /* Set new LMF */
1994                 emit_tls_set (cfg, lmf_reg, TLS_KEY_LMF);
1995         } else {
1996                 /*
1997                  * Store lmf_addr in a variable, so it can be allocated to a global register.
1998                  */
1999                 if (!cfg->lmf_addr_var)
2000                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2001
2002 #ifdef HOST_WIN32
2003                 ins = mono_get_jit_tls_intrinsic (cfg);
2004                 if (ins) {
2005                         int jit_tls_dreg = ins->dreg;
2006
2007                         MONO_ADD_INS (cfg->cbb, ins);
2008                         lmf_reg = alloc_preg (cfg);
2009                         EMIT_NEW_BIALU_IMM (cfg, lmf_ins, OP_PADD_IMM, lmf_reg, jit_tls_dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, lmf));
2010                 } else {
2011                         lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
2012                 }
2013 #else
2014                 lmf_ins = mono_get_lmf_addr_intrinsic (cfg);
2015                 if (lmf_ins) {
2016                         MONO_ADD_INS (cfg->cbb, lmf_ins);
2017                 } else {
2018 #ifdef TARGET_IOS
2019                         MonoInst *args [16], *jit_tls_ins, *ins;
2020
2021                         /* Inline mono_get_lmf_addr () */
2022                         /* jit_tls = pthread_getspecific (mono_jit_tls_id); lmf_addr = &jit_tls->lmf; */
2023
2024                         /* Load mono_jit_tls_id */
2025                         if (cfg->compile_aot)
2026                                 EMIT_NEW_AOTCONST (cfg, args [0], MONO_PATCH_INFO_JIT_TLS_ID, NULL);
2027                         else
2028                                 EMIT_NEW_ICONST (cfg, args [0], mono_jit_tls_id);
2029                         /* call pthread_getspecific () */
2030                         jit_tls_ins = mono_emit_jit_icall (cfg, pthread_getspecific, args);
2031                         /* lmf_addr = &jit_tls->lmf */
2032                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, cfg->lmf_addr_var->dreg, jit_tls_ins->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, lmf));
2033                         lmf_ins = ins;
2034 #else
2035                         lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
2036 #endif
2037                 }
2038 #endif
2039                 lmf_ins->dreg = cfg->lmf_addr_var->dreg;
2040
2041                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2042                 lmf_reg = ins->dreg;
2043
2044                 prev_lmf_reg = alloc_preg (cfg);
2045                 /* Save previous_lmf */
2046                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, cfg->lmf_addr_var->dreg, 0);
2047                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), prev_lmf_reg);
2048                 /* Set new lmf */
2049                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, cfg->lmf_addr_var->dreg, 0, lmf_reg);
2050         }
2051 }
2052
2053 /*
2054  * emit_pop_lmf:
2055  *
2056  *   Emit IR to pop the current LMF from the LMF stack.
2057  */
2058 static void
2059 emit_pop_lmf (MonoCompile *cfg)
2060 {
2061         int lmf_reg, lmf_addr_reg, prev_lmf_reg;
2062         MonoInst *ins;
2063
2064         if (!cfg->lmf_ir)
2065                 return;
2066
2067         EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2068         lmf_reg = ins->dreg;
2069
2070         if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
2071                 /* Load previous_lmf */
2072                 prev_lmf_reg = alloc_preg (cfg);
2073                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
2074                 /* Set new LMF */
2075                 emit_tls_set (cfg, prev_lmf_reg, TLS_KEY_LMF);
2076         } else {
2077                 /*
2078                  * Emit IR to pop the LMF:
2079                  * *(lmf->lmf_addr) = lmf->prev_lmf
2080                  */
2081                 /* This could be called before emit_push_lmf () */
2082                 if (!cfg->lmf_addr_var)
2083                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2084                 lmf_addr_reg = cfg->lmf_addr_var->dreg;
2085
2086                 prev_lmf_reg = alloc_preg (cfg);
2087                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
2088                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_addr_reg, 0, prev_lmf_reg);
2089         }
2090 }
2091
2092 static void
2093 emit_instrumentation_call (MonoCompile *cfg, void *func)
2094 {
2095         MonoInst *iargs [1];
2096
2097         /*
2098          * Avoid instrumenting inlined methods since it can
2099          * distort profiling results.
2100          */
2101         if (cfg->method != cfg->current_method)
2102                 return;
2103
2104         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE) {
2105                 EMIT_NEW_METHODCONST (cfg, iargs [0], cfg->method);
2106                 mono_emit_jit_icall (cfg, func, iargs);
2107         }
2108 }
2109
2110 static int
2111 ret_type_to_call_opcode (MonoCompile *cfg, MonoType *type, int calli, int virt)
2112 {
2113 handle_enum:
2114         type = mini_get_underlying_type (type);
2115         switch (type->type) {
2116         case MONO_TYPE_VOID:
2117                 return calli? OP_VOIDCALL_REG: virt? OP_VOIDCALL_MEMBASE: OP_VOIDCALL;
2118         case MONO_TYPE_I1:
2119         case MONO_TYPE_U1:
2120         case MONO_TYPE_I2:
2121         case MONO_TYPE_U2:
2122         case MONO_TYPE_I4:
2123         case MONO_TYPE_U4:
2124                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2125         case MONO_TYPE_I:
2126         case MONO_TYPE_U:
2127         case MONO_TYPE_PTR:
2128         case MONO_TYPE_FNPTR:
2129                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2130         case MONO_TYPE_CLASS:
2131         case MONO_TYPE_STRING:
2132         case MONO_TYPE_OBJECT:
2133         case MONO_TYPE_SZARRAY:
2134         case MONO_TYPE_ARRAY:    
2135                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2136         case MONO_TYPE_I8:
2137         case MONO_TYPE_U8:
2138                 return calli? OP_LCALL_REG: virt? OP_LCALL_MEMBASE: OP_LCALL;
2139         case MONO_TYPE_R4:
2140                 if (cfg->r4fp)
2141                         return calli? OP_RCALL_REG: virt? OP_RCALL_MEMBASE: OP_RCALL;
2142                 else
2143                         return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
2144         case MONO_TYPE_R8:
2145                 return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
2146         case MONO_TYPE_VALUETYPE:
2147                 if (type->data.klass->enumtype) {
2148                         type = mono_class_enum_basetype (type->data.klass);
2149                         goto handle_enum;
2150                 } else
2151                         return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2152         case MONO_TYPE_TYPEDBYREF:
2153                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2154         case MONO_TYPE_GENERICINST:
2155                 type = &type->data.generic_class->container_class->byval_arg;
2156                 goto handle_enum;
2157         case MONO_TYPE_VAR:
2158         case MONO_TYPE_MVAR:
2159                 /* gsharedvt */
2160                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2161         default:
2162                 g_error ("unknown type 0x%02x in ret_type_to_call_opcode", type->type);
2163         }
2164         return -1;
2165 }
2166
2167 /*
2168  * target_type_is_incompatible:
2169  * @cfg: MonoCompile context
2170  *
2171  * Check that the item @arg on the evaluation stack can be stored
2172  * in the target type (can be a local, or field, etc).
2173  * The cfg arg can be used to check if we need verification or just
2174  * validity checks.
2175  *
2176  * Returns: non-0 value if arg can't be stored on a target.
2177  */
2178 static int
2179 target_type_is_incompatible (MonoCompile *cfg, MonoType *target, MonoInst *arg)
2180 {
2181         MonoType *simple_type;
2182         MonoClass *klass;
2183
2184         if (target->byref) {
2185                 /* FIXME: check that the pointed to types match */
2186                 if (arg->type == STACK_MP)
2187                         return arg->klass != mono_class_from_mono_type (target);
2188                 if (arg->type == STACK_PTR)
2189                         return 0;
2190                 return 1;
2191         }
2192
2193         simple_type = mini_get_underlying_type (target);
2194         switch (simple_type->type) {
2195         case MONO_TYPE_VOID:
2196                 return 1;
2197         case MONO_TYPE_I1:
2198         case MONO_TYPE_U1:
2199         case MONO_TYPE_I2:
2200         case MONO_TYPE_U2:
2201         case MONO_TYPE_I4:
2202         case MONO_TYPE_U4:
2203                 if (arg->type != STACK_I4 && arg->type != STACK_PTR)
2204                         return 1;
2205                 return 0;
2206         case MONO_TYPE_PTR:
2207                 /* STACK_MP is needed when setting pinned locals */
2208                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2209                         return 1;
2210                 return 0;
2211         case MONO_TYPE_I:
2212         case MONO_TYPE_U:
2213         case MONO_TYPE_FNPTR:
2214                 /* 
2215                  * Some opcodes like ldloca returns 'transient pointers' which can be stored in
2216                  * in native int. (#688008).
2217                  */
2218                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2219                         return 1;
2220                 return 0;
2221         case MONO_TYPE_CLASS:
2222         case MONO_TYPE_STRING:
2223         case MONO_TYPE_OBJECT:
2224         case MONO_TYPE_SZARRAY:
2225         case MONO_TYPE_ARRAY:    
2226                 if (arg->type != STACK_OBJ)
2227                         return 1;
2228                 /* FIXME: check type compatibility */
2229                 return 0;
2230         case MONO_TYPE_I8:
2231         case MONO_TYPE_U8:
2232                 if (arg->type != STACK_I8)
2233                         return 1;
2234                 return 0;
2235         case MONO_TYPE_R4:
2236                 if (arg->type != cfg->r4_stack_type)
2237                         return 1;
2238                 return 0;
2239         case MONO_TYPE_R8:
2240                 if (arg->type != STACK_R8)
2241                         return 1;
2242                 return 0;
2243         case MONO_TYPE_VALUETYPE:
2244                 if (arg->type != STACK_VTYPE)
2245                         return 1;
2246                 klass = mono_class_from_mono_type (simple_type);
2247                 if (klass != arg->klass)
2248                         return 1;
2249                 return 0;
2250         case MONO_TYPE_TYPEDBYREF:
2251                 if (arg->type != STACK_VTYPE)
2252                         return 1;
2253                 klass = mono_class_from_mono_type (simple_type);
2254                 if (klass != arg->klass)
2255                         return 1;
2256                 return 0;
2257         case MONO_TYPE_GENERICINST:
2258                 if (mono_type_generic_inst_is_valuetype (simple_type)) {
2259                         if (arg->type != STACK_VTYPE)
2260                                 return 1;
2261                         klass = mono_class_from_mono_type (simple_type);
2262                         /* The second cases is needed when doing partial sharing */
2263                         if (klass != arg->klass && mono_class_from_mono_type (target) != arg->klass)
2264                                 return 1;
2265                         return 0;
2266                 } else {
2267                         if (arg->type != STACK_OBJ)
2268                                 return 1;
2269                         /* FIXME: check type compatibility */
2270                         return 0;
2271                 }
2272         case MONO_TYPE_VAR:
2273         case MONO_TYPE_MVAR:
2274                 g_assert (cfg->gshared);
2275                 if (mini_type_var_is_vt (simple_type)) {
2276                         if (arg->type != STACK_VTYPE)
2277                                 return 1;
2278                 } else {
2279                         if (arg->type != STACK_OBJ)
2280                                 return 1;
2281                 }
2282                 return 0;
2283         default:
2284                 g_error ("unknown type 0x%02x in target_type_is_incompatible", simple_type->type);
2285         }
2286         return 1;
2287 }
2288
2289 /*
2290  * Prepare arguments for passing to a function call.
2291  * Return a non-zero value if the arguments can't be passed to the given
2292  * signature.
2293  * The type checks are not yet complete and some conversions may need
2294  * casts on 32 or 64 bit architectures.
2295  *
2296  * FIXME: implement this using target_type_is_incompatible ()
2297  */
2298 static int
2299 check_call_signature (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args)
2300 {
2301         MonoType *simple_type;
2302         int i;
2303
2304         if (sig->hasthis) {
2305                 if (args [0]->type != STACK_OBJ && args [0]->type != STACK_MP && args [0]->type != STACK_PTR)
2306                         return 1;
2307                 args++;
2308         }
2309         for (i = 0; i < sig->param_count; ++i) {
2310                 if (sig->params [i]->byref) {
2311                         if (args [i]->type != STACK_MP && args [i]->type != STACK_PTR)
2312                                 return 1;
2313                         continue;
2314                 }
2315                 simple_type = mini_get_underlying_type (sig->params [i]);
2316 handle_enum:
2317                 switch (simple_type->type) {
2318                 case MONO_TYPE_VOID:
2319                         return 1;
2320                         continue;
2321                 case MONO_TYPE_I1:
2322                 case MONO_TYPE_U1:
2323                 case MONO_TYPE_I2:
2324                 case MONO_TYPE_U2:
2325                 case MONO_TYPE_I4:
2326                 case MONO_TYPE_U4:
2327                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR)
2328                                 return 1;
2329                         continue;
2330                 case MONO_TYPE_I:
2331                 case MONO_TYPE_U:
2332                 case MONO_TYPE_PTR:
2333                 case MONO_TYPE_FNPTR:
2334                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR && args [i]->type != STACK_MP && args [i]->type != STACK_OBJ)
2335                                 return 1;
2336                         continue;
2337                 case MONO_TYPE_CLASS:
2338                 case MONO_TYPE_STRING:
2339                 case MONO_TYPE_OBJECT:
2340                 case MONO_TYPE_SZARRAY:
2341                 case MONO_TYPE_ARRAY:    
2342                         if (args [i]->type != STACK_OBJ)
2343                                 return 1;
2344                         continue;
2345                 case MONO_TYPE_I8:
2346                 case MONO_TYPE_U8:
2347                         if (args [i]->type != STACK_I8)
2348                                 return 1;
2349                         continue;
2350                 case MONO_TYPE_R4:
2351                         if (args [i]->type != cfg->r4_stack_type)
2352                                 return 1;
2353                         continue;
2354                 case MONO_TYPE_R8:
2355                         if (args [i]->type != STACK_R8)
2356                                 return 1;
2357                         continue;
2358                 case MONO_TYPE_VALUETYPE:
2359                         if (simple_type->data.klass->enumtype) {
2360                                 simple_type = mono_class_enum_basetype (simple_type->data.klass);
2361                                 goto handle_enum;
2362                         }
2363                         if (args [i]->type != STACK_VTYPE)
2364                                 return 1;
2365                         continue;
2366                 case MONO_TYPE_TYPEDBYREF:
2367                         if (args [i]->type != STACK_VTYPE)
2368                                 return 1;
2369                         continue;
2370                 case MONO_TYPE_GENERICINST:
2371                         simple_type = &simple_type->data.generic_class->container_class->byval_arg;
2372                         goto handle_enum;
2373                 case MONO_TYPE_VAR:
2374                 case MONO_TYPE_MVAR:
2375                         /* gsharedvt */
2376                         if (args [i]->type != STACK_VTYPE)
2377                                 return 1;
2378                         continue;
2379                 default:
2380                         g_error ("unknown type 0x%02x in check_call_signature",
2381                                  simple_type->type);
2382                 }
2383         }
2384         return 0;
2385 }
2386
2387 static int
2388 callvirt_to_call (int opcode)
2389 {
2390         switch (opcode) {
2391         case OP_CALL_MEMBASE:
2392                 return OP_CALL;
2393         case OP_VOIDCALL_MEMBASE:
2394                 return OP_VOIDCALL;
2395         case OP_FCALL_MEMBASE:
2396                 return OP_FCALL;
2397         case OP_RCALL_MEMBASE:
2398                 return OP_RCALL;
2399         case OP_VCALL_MEMBASE:
2400                 return OP_VCALL;
2401         case OP_LCALL_MEMBASE:
2402                 return OP_LCALL;
2403         default:
2404                 g_assert_not_reached ();
2405         }
2406
2407         return -1;
2408 }
2409
2410 /* Either METHOD or IMT_ARG needs to be set */
2411 static void
2412 emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoMethod *method, MonoInst *imt_arg)
2413 {
2414         int method_reg;
2415
2416         if (COMPILE_LLVM (cfg)) {
2417                 method_reg = alloc_preg (cfg);
2418
2419                 if (imt_arg) {
2420                         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2421                 } else if (cfg->compile_aot) {
2422                         MONO_EMIT_NEW_AOTCONST (cfg, method_reg, method, MONO_PATCH_INFO_METHODCONST);
2423                 } else {
2424                         MonoInst *ins;
2425                         MONO_INST_NEW (cfg, ins, OP_PCONST);
2426                         ins->inst_p0 = method;
2427                         ins->dreg = method_reg;
2428                         MONO_ADD_INS (cfg->cbb, ins);
2429                 }
2430
2431 #ifdef ENABLE_LLVM
2432                 call->imt_arg_reg = method_reg;
2433 #endif
2434         mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2435                 return;
2436         }
2437
2438         method_reg = alloc_preg (cfg);
2439
2440         if (imt_arg) {
2441                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2442         } else if (cfg->compile_aot) {
2443                 MONO_EMIT_NEW_AOTCONST (cfg, method_reg, method, MONO_PATCH_INFO_METHODCONST);
2444         } else {
2445                 MonoInst *ins;
2446                 MONO_INST_NEW (cfg, ins, OP_PCONST);
2447                 ins->inst_p0 = method;
2448                 ins->dreg = method_reg;
2449                 MONO_ADD_INS (cfg->cbb, ins);
2450         }
2451
2452         mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2453 }
2454
2455 static MonoJumpInfo *
2456 mono_patch_info_new (MonoMemPool *mp, int ip, MonoJumpInfoType type, gconstpointer target)
2457 {
2458         MonoJumpInfo *ji = mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
2459
2460         ji->ip.i = ip;
2461         ji->type = type;
2462         ji->data.target = target;
2463
2464         return ji;
2465 }
2466
2467 static int
2468 mini_class_check_context_used (MonoCompile *cfg, MonoClass *klass)
2469 {
2470         if (cfg->gshared)
2471                 return mono_class_check_context_used (klass);
2472         else
2473                 return 0;
2474 }
2475
2476 static int
2477 mini_method_check_context_used (MonoCompile *cfg, MonoMethod *method)
2478 {
2479         if (cfg->gshared)
2480                 return mono_method_check_context_used (method);
2481         else
2482                 return 0;
2483 }
2484
2485 /*
2486  * check_method_sharing:
2487  *
2488  *   Check whenever the vtable or an mrgctx needs to be passed when calling CMETHOD.
2489  */
2490 static void
2491 check_method_sharing (MonoCompile *cfg, MonoMethod *cmethod, gboolean *out_pass_vtable, gboolean *out_pass_mrgctx)
2492 {
2493         gboolean pass_vtable = FALSE;
2494         gboolean pass_mrgctx = FALSE;
2495
2496         if (((cmethod->flags & METHOD_ATTRIBUTE_STATIC) || cmethod->klass->valuetype) &&
2497                 (cmethod->klass->generic_class || cmethod->klass->generic_container)) {
2498                 gboolean sharable = FALSE;
2499
2500                 if (mono_method_is_generic_sharable_full (cmethod, TRUE, TRUE, TRUE))
2501                         sharable = TRUE;
2502
2503                 /*
2504                  * Pass vtable iff target method might
2505                  * be shared, which means that sharing
2506                  * is enabled for its class and its
2507                  * context is sharable (and it's not a
2508                  * generic method).
2509                  */
2510                 if (sharable && !(mini_method_get_context (cmethod) && mini_method_get_context (cmethod)->method_inst))
2511                         pass_vtable = TRUE;
2512         }
2513
2514         if (mini_method_get_context (cmethod) &&
2515                 mini_method_get_context (cmethod)->method_inst) {
2516                 g_assert (!pass_vtable);
2517
2518                 if (mono_method_is_generic_sharable_full (cmethod, TRUE, TRUE, TRUE)) {
2519                         pass_mrgctx = TRUE;
2520                 } else {
2521                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (mono_method_signature (cmethod)))
2522                                 pass_mrgctx = TRUE;
2523                 }
2524         }
2525
2526         if (out_pass_vtable)
2527                 *out_pass_vtable = pass_vtable;
2528         if (out_pass_mrgctx)
2529                 *out_pass_mrgctx = pass_mrgctx;
2530 }
2531
2532 inline static MonoCallInst *
2533 mono_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig, 
2534                                          MonoInst **args, int calli, int virtual, int tail, int rgctx, int unbox_trampoline)
2535 {
2536         MonoType *sig_ret;
2537         MonoCallInst *call;
2538 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2539         int i;
2540 #endif
2541
2542         if (tail) {
2543                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
2544
2545                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
2546         } else
2547                 MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (cfg, sig->ret, calli, virtual));
2548
2549         call->args = args;
2550         call->signature = sig;
2551         call->rgctx_reg = rgctx;
2552         sig_ret = mini_get_underlying_type (sig->ret);
2553
2554         type_to_eval_stack_type ((cfg), sig_ret, &call->inst);
2555
2556         if (tail) {
2557                 if (mini_type_is_vtype (sig_ret)) {
2558                         call->vret_var = cfg->vret_addr;
2559                         //g_assert_not_reached ();
2560                 }
2561         } else if (mini_type_is_vtype (sig_ret)) {
2562                 MonoInst *temp = mono_compile_create_var (cfg, sig_ret, OP_LOCAL);
2563                 MonoInst *loada;
2564
2565                 temp->backend.is_pinvoke = sig->pinvoke;
2566
2567                 /*
2568                  * We use a new opcode OP_OUTARG_VTRETADDR instead of LDADDR for emitting the
2569                  * address of return value to increase optimization opportunities.
2570                  * Before vtype decomposition, the dreg of the call ins itself represents the
2571                  * fact the call modifies the return value. After decomposition, the call will
2572                  * be transformed into one of the OP_VOIDCALL opcodes, and the VTRETADDR opcode
2573                  * will be transformed into an LDADDR.
2574                  */
2575                 MONO_INST_NEW (cfg, loada, OP_OUTARG_VTRETADDR);
2576                 loada->dreg = alloc_preg (cfg);
2577                 loada->inst_p0 = temp;
2578                 /* We reference the call too since call->dreg could change during optimization */
2579                 loada->inst_p1 = call;
2580                 MONO_ADD_INS (cfg->cbb, loada);
2581
2582                 call->inst.dreg = temp->dreg;
2583
2584                 call->vret_var = loada;
2585         } else if (!MONO_TYPE_IS_VOID (sig_ret))
2586                 call->inst.dreg = alloc_dreg (cfg, call->inst.type);
2587
2588 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2589         if (COMPILE_SOFT_FLOAT (cfg)) {
2590                 /* 
2591                  * If the call has a float argument, we would need to do an r8->r4 conversion using 
2592                  * an icall, but that cannot be done during the call sequence since it would clobber
2593                  * the call registers + the stack. So we do it before emitting the call.
2594                  */
2595                 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2596                         MonoType *t;
2597                         MonoInst *in = call->args [i];
2598
2599                         if (i >= sig->hasthis)
2600                                 t = sig->params [i - sig->hasthis];
2601                         else
2602                                 t = &mono_defaults.int_class->byval_arg;
2603                         t = mono_type_get_underlying_type (t);
2604
2605                         if (!t->byref && t->type == MONO_TYPE_R4) {
2606                                 MonoInst *iargs [1];
2607                                 MonoInst *conv;
2608
2609                                 iargs [0] = in;
2610                                 conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
2611
2612                                 /* The result will be in an int vreg */
2613                                 call->args [i] = conv;
2614                         }
2615                 }
2616         }
2617 #endif
2618
2619         call->need_unbox_trampoline = unbox_trampoline;
2620
2621 #ifdef ENABLE_LLVM
2622         if (COMPILE_LLVM (cfg))
2623                 mono_llvm_emit_call (cfg, call);
2624         else
2625                 mono_arch_emit_call (cfg, call);
2626 #else
2627         mono_arch_emit_call (cfg, call);
2628 #endif
2629
2630         cfg->param_area = MAX (cfg->param_area, call->stack_usage);
2631         cfg->flags |= MONO_CFG_HAS_CALLS;
2632         
2633         return call;
2634 }
2635
2636 static void
2637 set_rgctx_arg (MonoCompile *cfg, MonoCallInst *call, int rgctx_reg, MonoInst *rgctx_arg)
2638 {
2639 #ifdef MONO_ARCH_RGCTX_REG
2640         mono_call_inst_add_outarg_reg (cfg, call, rgctx_reg, MONO_ARCH_RGCTX_REG, FALSE);
2641         cfg->uses_rgctx_reg = TRUE;
2642         call->rgctx_reg = TRUE;
2643 #ifdef ENABLE_LLVM
2644         call->rgctx_arg_reg = rgctx_reg;
2645 #endif
2646 #else
2647         NOT_IMPLEMENTED;
2648 #endif
2649 }       
2650
2651 inline static MonoInst*
2652 mono_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr, MonoInst *imt_arg, MonoInst *rgctx_arg)
2653 {
2654         MonoCallInst *call;
2655         MonoInst *ins;
2656         int rgctx_reg = -1;
2657         gboolean check_sp = FALSE;
2658
2659         if (cfg->check_pinvoke_callconv && cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
2660                 WrapperInfo *info = mono_marshal_get_wrapper_info (cfg->method);
2661
2662                 if (info && info->subtype == WRAPPER_SUBTYPE_PINVOKE)
2663                         check_sp = TRUE;
2664         }
2665
2666         if (rgctx_arg) {
2667                 rgctx_reg = mono_alloc_preg (cfg);
2668                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2669         }
2670
2671         if (check_sp) {
2672                 if (!cfg->stack_inbalance_var)
2673                         cfg->stack_inbalance_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2674
2675                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2676                 ins->dreg = cfg->stack_inbalance_var->dreg;
2677                 MONO_ADD_INS (cfg->cbb, ins);
2678         }
2679
2680         call = mono_emit_call_args (cfg, sig, args, TRUE, FALSE, FALSE, rgctx_arg ? TRUE : FALSE, FALSE);
2681
2682         call->inst.sreg1 = addr->dreg;
2683
2684         if (imt_arg)
2685                 emit_imt_argument (cfg, call, NULL, imt_arg);
2686
2687         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2688
2689         if (check_sp) {
2690                 int sp_reg;
2691
2692                 sp_reg = mono_alloc_preg (cfg);
2693
2694                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2695                 ins->dreg = sp_reg;
2696                 MONO_ADD_INS (cfg->cbb, ins);
2697
2698                 /* Restore the stack so we don't crash when throwing the exception */
2699                 MONO_INST_NEW (cfg, ins, OP_SET_SP);
2700                 ins->sreg1 = cfg->stack_inbalance_var->dreg;
2701                 MONO_ADD_INS (cfg->cbb, ins);
2702
2703                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, cfg->stack_inbalance_var->dreg, sp_reg);
2704                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ExecutionEngineException");
2705         }
2706
2707         if (rgctx_arg)
2708                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2709
2710         return (MonoInst*)call;
2711 }
2712
2713 static MonoInst*
2714 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2715
2716 static MonoInst*
2717 emit_get_rgctx_method (MonoCompile *cfg, int context_used, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type);
2718 static MonoInst*
2719 emit_get_rgctx_klass (MonoCompile *cfg, int context_used, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2720
2721 static MonoInst*
2722 mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSignature *sig, gboolean tail,
2723                                                         MonoInst **args, MonoInst *this_ins, MonoInst *imt_arg, MonoInst *rgctx_arg)
2724 {
2725 #ifndef DISABLE_REMOTING
2726         gboolean might_be_remote = FALSE;
2727 #endif
2728         gboolean virtual = this_ins != NULL;
2729         gboolean enable_for_aot = TRUE;
2730         int context_used;
2731         MonoCallInst *call;
2732         int rgctx_reg = 0;
2733         gboolean need_unbox_trampoline;
2734
2735         if (!sig)
2736                 sig = mono_method_signature (method);
2737
2738         if (rgctx_arg) {
2739                 rgctx_reg = mono_alloc_preg (cfg);
2740                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2741         }
2742
2743         if (method->string_ctor) {
2744                 /* Create the real signature */
2745                 /* FIXME: Cache these */
2746                 MonoMethodSignature *ctor_sig = mono_metadata_signature_dup_mempool (cfg->mempool, sig);
2747                 ctor_sig->ret = &mono_defaults.string_class->byval_arg;
2748
2749                 sig = ctor_sig;
2750         }
2751
2752         context_used = mini_method_check_context_used (cfg, method);
2753
2754 #ifndef DISABLE_REMOTING
2755         might_be_remote = this_ins && sig->hasthis &&
2756                 (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) &&
2757                 !(method->flags & METHOD_ATTRIBUTE_VIRTUAL) && (!MONO_CHECK_THIS (this_ins) || context_used);
2758
2759         if (might_be_remote && context_used) {
2760                 MonoInst *addr;
2761
2762                 g_assert (cfg->gshared);
2763
2764                 addr = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK);
2765
2766                 return mono_emit_calli (cfg, sig, args, addr, NULL, NULL);
2767         }
2768 #endif
2769
2770         need_unbox_trampoline = method->klass == mono_defaults.object_class || (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE);
2771
2772         call = mono_emit_call_args (cfg, sig, args, FALSE, virtual, tail, rgctx_arg ? TRUE : FALSE, need_unbox_trampoline);
2773
2774 #ifndef DISABLE_REMOTING
2775         if (might_be_remote)
2776                 call->method = mono_marshal_get_remoting_invoke_with_check (method);
2777         else
2778 #endif
2779                 call->method = method;
2780         call->inst.flags |= MONO_INST_HAS_METHOD;
2781         call->inst.inst_left = this_ins;
2782         call->tail_call = tail;
2783
2784         if (virtual) {
2785                 int vtable_reg, slot_reg, this_reg;
2786                 int offset;
2787
2788                 this_reg = this_ins->dreg;
2789
2790                 if ((method->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (method->name, "Invoke")) {
2791                         MonoInst *dummy_use;
2792
2793                         MONO_EMIT_NULL_CHECK (cfg, this_reg);
2794
2795                         /* Make a call to delegate->invoke_impl */
2796                         call->inst.inst_basereg = this_reg;
2797                         call->inst.inst_offset = MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl);
2798                         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2799
2800                         /* We must emit a dummy use here because the delegate trampoline will
2801                         replace the 'this' argument with the delegate target making this activation
2802                         no longer a root for the delegate.
2803                         This is an issue for delegates that target collectible code such as dynamic
2804                         methods of GC'able assemblies.
2805
2806                         For a test case look into #667921.
2807
2808                         FIXME: a dummy use is not the best way to do it as the local register allocator
2809                         will put it on a caller save register and spil it around the call. 
2810                         Ideally, we would either put it on a callee save register or only do the store part.  
2811                          */
2812                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, args [0]);
2813
2814                         return (MonoInst*)call;
2815                 }
2816
2817                 if ((!cfg->compile_aot || enable_for_aot) && 
2818                         (!(method->flags & METHOD_ATTRIBUTE_VIRTUAL) || 
2819                          (MONO_METHOD_IS_FINAL (method) &&
2820                           method->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)) &&
2821                         !(mono_class_is_marshalbyref (method->klass) && context_used)) {
2822                         /* 
2823                          * the method is not virtual, we just need to ensure this is not null
2824                          * and then we can call the method directly.
2825                          */
2826 #ifndef DISABLE_REMOTING
2827                         if (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) {
2828                                 /* 
2829                                  * The check above ensures method is not gshared, this is needed since
2830                                  * gshared methods can't have wrappers.
2831                                  */
2832                                 method = call->method = mono_marshal_get_remoting_invoke_with_check (method);
2833                         }
2834 #endif
2835
2836                         if (!method->string_ctor)
2837                                 MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2838
2839                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2840                 } else if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && MONO_METHOD_IS_FINAL (method)) {
2841                         /*
2842                          * the method is virtual, but we can statically dispatch since either
2843                          * it's class or the method itself are sealed.
2844                          * But first we need to ensure it's not a null reference.
2845                          */
2846                         MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2847
2848                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2849                 } else {
2850                         vtable_reg = alloc_preg (cfg);
2851                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
2852                         if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2853                                 guint32 imt_slot = mono_method_get_imt_slot (method);
2854                                 emit_imt_argument (cfg, call, call->method, imt_arg);
2855                                 slot_reg = vtable_reg;
2856                                 offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
2857                         } else {
2858                                 slot_reg = vtable_reg;
2859                                 offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) +
2860                                         ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
2861                                 if (imt_arg) {
2862                                         g_assert (mono_method_signature (method)->generic_param_count);
2863                                         emit_imt_argument (cfg, call, call->method, imt_arg);
2864                                 }
2865                         }
2866
2867                         call->inst.sreg1 = slot_reg;
2868                         call->inst.inst_offset = offset;
2869                         call->virtual = TRUE;
2870                 }
2871         }
2872
2873         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2874
2875         if (rgctx_arg)
2876                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2877
2878         return (MonoInst*)call;
2879 }
2880
2881 MonoInst*
2882 mono_emit_method_call (MonoCompile *cfg, MonoMethod *method, MonoInst **args, MonoInst *this_ins)
2883 {
2884         return mono_emit_method_call_full (cfg, method, mono_method_signature (method), FALSE, args, this_ins, NULL, NULL);
2885 }
2886
2887 MonoInst*
2888 mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig,
2889                                            MonoInst **args)
2890 {
2891         MonoCallInst *call;
2892
2893         g_assert (sig);
2894
2895         call = mono_emit_call_args (cfg, sig, args, FALSE, FALSE, FALSE, FALSE, FALSE);
2896         call->fptr = func;
2897
2898         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2899
2900         return (MonoInst*)call;
2901 }
2902
2903 MonoInst*
2904 mono_emit_jit_icall (MonoCompile *cfg, gconstpointer func, MonoInst **args)
2905 {
2906         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (func);
2907
2908         g_assert (info);
2909
2910         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
2911 }
2912
2913 /*
2914  * mono_emit_abs_call:
2915  *
2916  *   Emit a call to the runtime function described by PATCH_TYPE and DATA.
2917  */
2918 inline static MonoInst*
2919 mono_emit_abs_call (MonoCompile *cfg, MonoJumpInfoType patch_type, gconstpointer data, 
2920                                         MonoMethodSignature *sig, MonoInst **args)
2921 {
2922         MonoJumpInfo *ji = mono_patch_info_new (cfg->mempool, 0, patch_type, data);
2923         MonoInst *ins;
2924
2925         /* 
2926          * We pass ji as the call address, the PATCH_INFO_ABS resolving code will
2927          * handle it.
2928          */
2929         if (cfg->abs_patches == NULL)
2930                 cfg->abs_patches = g_hash_table_new (NULL, NULL);
2931         g_hash_table_insert (cfg->abs_patches, ji, ji);
2932         ins = mono_emit_native_call (cfg, ji, sig, args);
2933         ((MonoCallInst*)ins)->fptr_is_patch = TRUE;
2934         return ins;
2935 }
2936
2937 static gboolean
2938 direct_icalls_enabled (MonoCompile *cfg)
2939 {
2940         /* LLVM on amd64 can't handle calls to non-32 bit addresses */
2941 #ifdef TARGET_AMD64
2942         if (cfg->compile_llvm)
2943                 return FALSE;
2944 #endif
2945         if (cfg->gen_sdb_seq_points || cfg->disable_direct_icalls)
2946                 return FALSE;
2947         return TRUE;
2948 }
2949
2950 MonoInst*
2951 mono_emit_jit_icall_by_info (MonoCompile *cfg, MonoJitICallInfo *info, MonoInst **args)
2952 {
2953         /*
2954          * Call the jit icall without a wrapper if possible.
2955          * The wrapper is needed for the following reasons:
2956          * - to handle exceptions thrown using mono_raise_exceptions () from the
2957          *   icall function. The EH code needs the lmf frame pushed by the
2958          *   wrapper to be able to unwind back to managed code.
2959          * - to be able to do stack walks for asynchronously suspended
2960          *   threads when debugging.
2961          */
2962         if (info->no_raise && direct_icalls_enabled (cfg)) {
2963                 char *name;
2964                 int costs;
2965
2966                 if (!info->wrapper_method) {
2967                         name = g_strdup_printf ("__icall_wrapper_%s", info->name);
2968                         info->wrapper_method = mono_marshal_get_icall_wrapper (info->sig, name, info->func, TRUE);
2969                         g_free (name);
2970                         mono_memory_barrier ();
2971                 }
2972
2973                 /*
2974                  * Inline the wrapper method, which is basically a call to the C icall, and
2975                  * an exception check.
2976                  */
2977                 costs = inline_method (cfg, info->wrapper_method, NULL,
2978                                                            args, NULL, cfg->real_offset, TRUE);
2979                 g_assert (costs > 0);
2980                 g_assert (!MONO_TYPE_IS_VOID (info->sig->ret));
2981
2982                 return args [0];
2983         } else {
2984                 return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
2985         }
2986 }
2987  
2988 static MonoInst*
2989 mono_emit_widen_call_res (MonoCompile *cfg, MonoInst *ins, MonoMethodSignature *fsig)
2990 {
2991         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
2992                 if ((fsig->pinvoke || LLVM_ENABLED) && !fsig->ret->byref) {
2993                         int widen_op = -1;
2994
2995                         /* 
2996                          * Native code might return non register sized integers 
2997                          * without initializing the upper bits.
2998                          */
2999                         switch (mono_type_to_load_membase (cfg, fsig->ret)) {
3000                         case OP_LOADI1_MEMBASE:
3001                                 widen_op = OP_ICONV_TO_I1;
3002                                 break;
3003                         case OP_LOADU1_MEMBASE:
3004                                 widen_op = OP_ICONV_TO_U1;
3005                                 break;
3006                         case OP_LOADI2_MEMBASE:
3007                                 widen_op = OP_ICONV_TO_I2;
3008                                 break;
3009                         case OP_LOADU2_MEMBASE:
3010                                 widen_op = OP_ICONV_TO_U2;
3011                                 break;
3012                         default:
3013                                 break;
3014                         }
3015
3016                         if (widen_op != -1) {
3017                                 int dreg = alloc_preg (cfg);
3018                                 MonoInst *widen;
3019
3020                                 EMIT_NEW_UNALU (cfg, widen, widen_op, dreg, ins->dreg);
3021                                 widen->type = ins->type;
3022                                 ins = widen;
3023                         }
3024                 }
3025         }
3026
3027         return ins;
3028 }
3029
3030 static MonoMethod*
3031 get_memcpy_method (void)
3032 {
3033         static MonoMethod *memcpy_method = NULL;
3034         if (!memcpy_method) {
3035                 memcpy_method = mono_class_get_method_from_name (mono_defaults.string_class, "memcpy", 3);
3036                 if (!memcpy_method)
3037                         g_error ("Old corlib found. Install a new one");
3038         }
3039         return memcpy_method;
3040 }
3041
3042 static void
3043 create_write_barrier_bitmap (MonoCompile *cfg, MonoClass *klass, unsigned *wb_bitmap, int offset)
3044 {
3045         MonoClassField *field;
3046         gpointer iter = NULL;
3047
3048         while ((field = mono_class_get_fields (klass, &iter))) {
3049                 int foffset;
3050
3051                 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
3052                         continue;
3053                 foffset = klass->valuetype ? field->offset - sizeof (MonoObject): field->offset;
3054                 if (mini_type_is_reference (mono_field_get_type (field))) {
3055                         g_assert ((foffset % SIZEOF_VOID_P) == 0);
3056                         *wb_bitmap |= 1 << ((offset + foffset) / SIZEOF_VOID_P);
3057                 } else {
3058                         MonoClass *field_class = mono_class_from_mono_type (field->type);
3059                         if (field_class->has_references)
3060                                 create_write_barrier_bitmap (cfg, field_class, wb_bitmap, offset + foffset);
3061                 }
3062         }
3063 }
3064
3065 static void
3066 emit_write_barrier (MonoCompile *cfg, MonoInst *ptr, MonoInst *value)
3067 {
3068         int card_table_shift_bits;
3069         gpointer card_table_mask;
3070         guint8 *card_table;
3071         MonoInst *dummy_use;
3072         int nursery_shift_bits;
3073         size_t nursery_size;
3074         gboolean has_card_table_wb = FALSE;
3075
3076         if (!cfg->gen_write_barriers)
3077                 return;
3078
3079         card_table = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
3080
3081         mono_gc_get_nursery (&nursery_shift_bits, &nursery_size);
3082
3083 #ifdef MONO_ARCH_HAVE_CARD_TABLE_WBARRIER
3084         has_card_table_wb = TRUE;
3085 #endif
3086
3087         if (has_card_table_wb && !cfg->compile_aot && card_table && nursery_shift_bits > 0 && !COMPILE_LLVM (cfg)) {
3088                 MonoInst *wbarrier;
3089
3090                 MONO_INST_NEW (cfg, wbarrier, OP_CARD_TABLE_WBARRIER);
3091                 wbarrier->sreg1 = ptr->dreg;
3092                 wbarrier->sreg2 = value->dreg;
3093                 MONO_ADD_INS (cfg->cbb, wbarrier);
3094         } else if (card_table && !cfg->compile_aot && !mono_gc_card_table_nursery_check ()) {
3095                 int offset_reg = alloc_preg (cfg);
3096                 int card_reg  = alloc_preg (cfg);
3097                 MonoInst *ins;
3098
3099                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, offset_reg, ptr->dreg, card_table_shift_bits);
3100                 if (card_table_mask)
3101                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, offset_reg, offset_reg, card_table_mask);
3102
3103                 /*We can't use PADD_IMM since the cardtable might end up in high addresses and amd64 doesn't support
3104                  * IMM's larger than 32bits.
3105                  */
3106                 if (cfg->compile_aot) {
3107                         MONO_EMIT_NEW_AOTCONST (cfg, card_reg, NULL, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR);
3108                 } else {
3109                         MONO_INST_NEW (cfg, ins, OP_PCONST);
3110                         ins->inst_p0 = card_table;
3111                         ins->dreg = card_reg;
3112                         MONO_ADD_INS (cfg->cbb, ins);
3113                 }
3114
3115                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, offset_reg, offset_reg, card_reg);
3116                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, offset_reg, 0, 1);
3117         } else {
3118                 MonoMethod *write_barrier = mono_gc_get_write_barrier ();
3119                 mono_emit_method_call (cfg, write_barrier, &ptr, NULL);
3120         }
3121
3122         EMIT_NEW_DUMMY_USE (cfg, dummy_use, value);
3123 }
3124
3125 static gboolean
3126 mono_emit_wb_aware_memcpy (MonoCompile *cfg, MonoClass *klass, MonoInst *iargs[4], int size, int align)
3127 {
3128         int dest_ptr_reg, tmp_reg, destreg, srcreg, offset;
3129         unsigned need_wb = 0;
3130
3131         if (align == 0)
3132                 align = 4;
3133
3134         /*types with references can't have alignment smaller than sizeof(void*) */
3135         if (align < SIZEOF_VOID_P)
3136                 return FALSE;
3137
3138         /*This value cannot be bigger than 32 due to the way we calculate the required wb bitmap.*/
3139         if (size > 32 * SIZEOF_VOID_P)
3140                 return FALSE;
3141
3142         create_write_barrier_bitmap (cfg, klass, &need_wb, 0);
3143
3144         /* We don't unroll more than 5 stores to avoid code bloat. */
3145         if (size > 5 * SIZEOF_VOID_P) {
3146                 /*This is harmless and simplify mono_gc_wbarrier_value_copy_bitmap */
3147                 size += (SIZEOF_VOID_P - 1);
3148                 size &= ~(SIZEOF_VOID_P - 1);
3149
3150                 EMIT_NEW_ICONST (cfg, iargs [2], size);
3151                 EMIT_NEW_ICONST (cfg, iargs [3], need_wb);
3152                 mono_emit_jit_icall (cfg, mono_gc_wbarrier_value_copy_bitmap, iargs);
3153                 return TRUE;
3154         }
3155
3156         destreg = iargs [0]->dreg;
3157         srcreg = iargs [1]->dreg;
3158         offset = 0;
3159
3160         dest_ptr_reg = alloc_preg (cfg);
3161         tmp_reg = alloc_preg (cfg);
3162
3163         /*tmp = dreg*/
3164         EMIT_NEW_UNALU (cfg, iargs [0], OP_MOVE, dest_ptr_reg, destreg);
3165
3166         while (size >= SIZEOF_VOID_P) {
3167                 MonoInst *load_inst;
3168                 MONO_INST_NEW (cfg, load_inst, OP_LOAD_MEMBASE);
3169                 load_inst->dreg = tmp_reg;
3170                 load_inst->inst_basereg = srcreg;
3171                 load_inst->inst_offset = offset;
3172                 MONO_ADD_INS (cfg->cbb, load_inst);
3173
3174                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, dest_ptr_reg, 0, tmp_reg);
3175
3176                 if (need_wb & 0x1)
3177                         emit_write_barrier (cfg, iargs [0], load_inst);
3178
3179                 offset += SIZEOF_VOID_P;
3180                 size -= SIZEOF_VOID_P;
3181                 need_wb >>= 1;
3182
3183                 /*tmp += sizeof (void*)*/
3184                 if (size >= SIZEOF_VOID_P) {
3185                         NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, dest_ptr_reg, dest_ptr_reg, SIZEOF_VOID_P);
3186                         MONO_ADD_INS (cfg->cbb, iargs [0]);
3187                 }
3188         }
3189
3190         /* Those cannot be references since size < sizeof (void*) */
3191         while (size >= 4) {
3192                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tmp_reg, srcreg, offset);
3193                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, tmp_reg);
3194                 offset += 4;
3195                 size -= 4;
3196         }
3197
3198         while (size >= 2) {
3199                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmp_reg, srcreg, offset);
3200                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, tmp_reg);
3201                 offset += 2;
3202                 size -= 2;
3203         }
3204
3205         while (size >= 1) {
3206                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmp_reg, srcreg, offset);
3207                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, tmp_reg);
3208                 offset += 1;
3209                 size -= 1;
3210         }
3211
3212         return TRUE;
3213 }
3214
3215 /*
3216  * Emit code to copy a valuetype of type @klass whose address is stored in
3217  * @src->dreg to memory whose address is stored at @dest->dreg.
3218  */
3219 void
3220 mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native)
3221 {
3222         MonoInst *iargs [4];
3223         int n;
3224         guint32 align = 0;
3225         MonoMethod *memcpy_method;
3226         MonoInst *size_ins = NULL;
3227         MonoInst *memcpy_ins = NULL;
3228
3229         g_assert (klass);
3230         if (cfg->gshared)
3231                 klass = mono_class_from_mono_type (mini_get_underlying_type (&klass->byval_arg));
3232
3233         /*
3234          * This check breaks with spilled vars... need to handle it during verification anyway.
3235          * g_assert (klass && klass == src->klass && klass == dest->klass);
3236          */
3237
3238         if (mini_is_gsharedvt_klass (klass)) {
3239                 g_assert (!native);
3240                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3241                 memcpy_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_MEMCPY);
3242         }
3243
3244         if (native)
3245                 n = mono_class_native_size (klass, &align);
3246         else
3247                 n = mono_class_value_size (klass, &align);
3248
3249         /* if native is true there should be no references in the struct */
3250         if (cfg->gen_write_barriers && (klass->has_references || size_ins) && !native) {
3251                 /* Avoid barriers when storing to the stack */
3252                 if (!((dest->opcode == OP_ADD_IMM && dest->sreg1 == cfg->frame_reg) ||
3253                           (dest->opcode == OP_LDADDR))) {
3254                         int context_used;
3255
3256                         iargs [0] = dest;
3257                         iargs [1] = src;
3258
3259                         context_used = mini_class_check_context_used (cfg, klass);
3260
3261                         /* It's ok to intrinsify under gsharing since shared code types are layout stable. */
3262                         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && mono_emit_wb_aware_memcpy (cfg, klass, iargs, n, align)) {
3263                                 return;
3264                         } else if (context_used) {
3265                                 iargs [2] = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3266                         }  else {
3267                                 if (cfg->compile_aot) {
3268                                         EMIT_NEW_CLASSCONST (cfg, iargs [2], klass);
3269                                 } else {
3270                                         EMIT_NEW_PCONST (cfg, iargs [2], klass);
3271                                         mono_class_compute_gc_descriptor (klass);
3272                                 }
3273                         }
3274
3275                         if (size_ins)
3276                                 mono_emit_jit_icall (cfg, mono_gsharedvt_value_copy, iargs);
3277                         else
3278                                 mono_emit_jit_icall (cfg, mono_value_copy, iargs);
3279                         return;
3280                 }
3281         }
3282
3283         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 8) {
3284                 /* FIXME: Optimize the case when src/dest is OP_LDADDR */
3285                 mini_emit_memcpy (cfg, dest->dreg, 0, src->dreg, 0, n, align);
3286         } else {
3287                 iargs [0] = dest;
3288                 iargs [1] = src;
3289                 if (size_ins)
3290                         iargs [2] = size_ins;
3291                 else
3292                         EMIT_NEW_ICONST (cfg, iargs [2], n);
3293                 
3294                 memcpy_method = get_memcpy_method ();
3295                 if (memcpy_ins)
3296                         mono_emit_calli (cfg, mono_method_signature (memcpy_method), iargs, memcpy_ins, NULL, NULL);
3297                 else
3298                         mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
3299         }
3300 }
3301
3302 static MonoMethod*
3303 get_memset_method (void)
3304 {
3305         static MonoMethod *memset_method = NULL;
3306         if (!memset_method) {
3307                 memset_method = mono_class_get_method_from_name (mono_defaults.string_class, "memset", 3);
3308                 if (!memset_method)
3309                         g_error ("Old corlib found. Install a new one");
3310         }
3311         return memset_method;
3312 }
3313
3314 void
3315 mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass)
3316 {
3317         MonoInst *iargs [3];
3318         int n;
3319         guint32 align;
3320         MonoMethod *memset_method;
3321         MonoInst *size_ins = NULL;
3322         MonoInst *bzero_ins = NULL;
3323         static MonoMethod *bzero_method;
3324
3325         /* FIXME: Optimize this for the case when dest is an LDADDR */
3326         mono_class_init (klass);
3327         if (mini_is_gsharedvt_klass (klass)) {
3328                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3329                 bzero_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_BZERO);
3330                 if (!bzero_method)
3331                         bzero_method = mono_class_get_method_from_name (mono_defaults.string_class, "bzero_aligned_1", 2);
3332                 g_assert (bzero_method);
3333                 iargs [0] = dest;
3334                 iargs [1] = size_ins;
3335                 mono_emit_calli (cfg, mono_method_signature (bzero_method), iargs, bzero_ins, NULL, NULL);
3336                 return;
3337         }
3338
3339         n = mono_class_value_size (klass, &align);
3340
3341         if (n <= sizeof (gpointer) * 8) {
3342                 mini_emit_memset (cfg, dest->dreg, 0, n, 0, align);
3343         }
3344         else {
3345                 memset_method = get_memset_method ();
3346                 iargs [0] = dest;
3347                 EMIT_NEW_ICONST (cfg, iargs [1], 0);
3348                 EMIT_NEW_ICONST (cfg, iargs [2], n);
3349                 mono_emit_method_call (cfg, memset_method, iargs, NULL);
3350         }
3351 }
3352
3353 /*
3354  * emit_get_rgctx:
3355  *
3356  *   Emit IR to return either the this pointer for instance method,
3357  * or the mrgctx for static methods.
3358  */
3359 static MonoInst*
3360 emit_get_rgctx (MonoCompile *cfg, MonoMethod *method, int context_used)
3361 {
3362         MonoInst *this_ins = NULL;
3363
3364         g_assert (cfg->gshared);
3365
3366         if (!(method->flags & METHOD_ATTRIBUTE_STATIC) &&
3367                         !(context_used & MONO_GENERIC_CONTEXT_USED_METHOD) &&
3368                         !method->klass->valuetype)
3369                 EMIT_NEW_ARGLOAD (cfg, this_ins, 0);
3370
3371         if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD) {
3372                 MonoInst *mrgctx_loc, *mrgctx_var;
3373
3374                 g_assert (!this_ins);
3375                 g_assert (method->is_inflated && mono_method_get_context (method)->method_inst);
3376
3377                 mrgctx_loc = mono_get_vtable_var (cfg);
3378                 EMIT_NEW_TEMPLOAD (cfg, mrgctx_var, mrgctx_loc->inst_c0);
3379
3380                 return mrgctx_var;
3381         } else if (method->flags & METHOD_ATTRIBUTE_STATIC || method->klass->valuetype) {
3382                 MonoInst *vtable_loc, *vtable_var;
3383
3384                 g_assert (!this_ins);
3385
3386                 vtable_loc = mono_get_vtable_var (cfg);
3387                 EMIT_NEW_TEMPLOAD (cfg, vtable_var, vtable_loc->inst_c0);
3388
3389                 if (method->is_inflated && mono_method_get_context (method)->method_inst) {
3390                         MonoInst *mrgctx_var = vtable_var;
3391                         int vtable_reg;
3392
3393                         vtable_reg = alloc_preg (cfg);
3394                         EMIT_NEW_LOAD_MEMBASE (cfg, vtable_var, OP_LOAD_MEMBASE, vtable_reg, mrgctx_var->dreg, MONO_STRUCT_OFFSET (MonoMethodRuntimeGenericContext, class_vtable));
3395                         vtable_var->type = STACK_PTR;
3396                 }
3397
3398                 return vtable_var;
3399         } else {
3400                 MonoInst *ins;
3401                 int vtable_reg;
3402         
3403                 vtable_reg = alloc_preg (cfg);
3404                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, vtable_reg, this_ins->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3405                 return ins;
3406         }
3407 }
3408
3409 static MonoJumpInfoRgctxEntry *
3410 mono_patch_info_rgctx_entry_new (MonoMemPool *mp, MonoMethod *method, gboolean in_mrgctx, MonoJumpInfoType patch_type, gconstpointer patch_data, MonoRgctxInfoType info_type)
3411 {
3412         MonoJumpInfoRgctxEntry *res = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoRgctxEntry));
3413         res->method = method;
3414         res->in_mrgctx = in_mrgctx;
3415         res->data = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo));
3416         res->data->type = patch_type;
3417         res->data->data.target = patch_data;
3418         res->info_type = info_type;
3419
3420         return res;
3421 }
3422
3423 /*
3424  * emit_rgctx_fetch:
3425  *
3426  *   Emit IR to load the value of the rgctx entry ENTRY from the rgctx
3427  * given by RGCTX.
3428  */
3429 static inline MonoInst*
3430 emit_rgctx_fetch (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
3431 {
3432         /* Inline version, not currently used */
3433         // FIXME: This can be called from mono_decompose_vtype_opts (), which can't create new bblocks
3434 #if 0
3435         int i, slot, depth, index, rgctx_reg, val_reg, res_reg;
3436         gboolean mrgctx;
3437         MonoBasicBlock *is_null_bb, *end_bb;
3438         MonoInst *res, *ins, *call;
3439         MonoInst *args[16];
3440
3441         slot = mini_get_rgctx_entry_slot (entry);
3442
3443         mrgctx = MONO_RGCTX_SLOT_IS_MRGCTX (slot);
3444         index = MONO_RGCTX_SLOT_INDEX (slot);
3445         if (mrgctx)
3446                 index += MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
3447         for (depth = 0; ; ++depth) {
3448                 int size = mono_class_rgctx_get_array_size (depth, mrgctx);
3449
3450                 if (index < size - 1)
3451                         break;
3452                 index -= size - 1;
3453         }
3454
3455         NEW_BBLOCK (cfg, end_bb);
3456         NEW_BBLOCK (cfg, is_null_bb);
3457
3458         if (mrgctx) {
3459                 rgctx_reg = rgctx->dreg;
3460         } else {
3461                 rgctx_reg = alloc_preg (cfg);
3462
3463                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, rgctx_reg, rgctx->dreg, MONO_STRUCT_OFFSET (MonoVTable, runtime_generic_context));
3464                 // FIXME: Avoid this check by allocating the table when the vtable is created etc.
3465                 NEW_BBLOCK (cfg, is_null_bb);
3466
3467                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rgctx_reg, 0);
3468                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3469         }
3470
3471         for (i = 0; i < depth; ++i) {
3472                 int array_reg = alloc_preg (cfg);
3473
3474                 /* load ptr to next array */
3475                 if (mrgctx && i == 0)
3476                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, rgctx_reg, MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT);
3477                 else
3478                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, rgctx_reg, 0);
3479                 rgctx_reg = array_reg;
3480                 /* is the ptr null? */
3481                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rgctx_reg, 0);
3482                 /* if yes, jump to actual trampoline */
3483                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3484         }
3485
3486         /* fetch slot */
3487         val_reg = alloc_preg (cfg);
3488         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, val_reg, rgctx_reg, (index + 1) * sizeof (gpointer));
3489         /* is the slot null? */
3490         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, val_reg, 0);
3491         /* if yes, jump to actual trampoline */
3492         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3493
3494         /* Fastpath */
3495         res_reg = alloc_preg (cfg);
3496         MONO_INST_NEW (cfg, ins, OP_MOVE);
3497         ins->dreg = res_reg;
3498         ins->sreg1 = val_reg;
3499         MONO_ADD_INS (cfg->cbb, ins);
3500         res = ins;
3501         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3502
3503         /* Slowpath */
3504         MONO_START_BB (cfg, is_null_bb);
3505         args [0] = rgctx;
3506         EMIT_NEW_ICONST (cfg, args [1], index);
3507         if (mrgctx)
3508                 call = mono_emit_jit_icall (cfg, mono_fill_method_rgctx, args);
3509         else
3510                 call = mono_emit_jit_icall (cfg, mono_fill_class_rgctx, args);
3511         MONO_INST_NEW (cfg, ins, OP_MOVE);
3512         ins->dreg = res_reg;
3513         ins->sreg1 = call->dreg;
3514         MONO_ADD_INS (cfg->cbb, ins);
3515         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3516
3517         MONO_START_BB (cfg, end_bb);
3518
3519         return res;
3520 #else
3521         return mono_emit_abs_call (cfg, MONO_PATCH_INFO_RGCTX_FETCH, entry, helper_sig_rgctx_lazy_fetch_trampoline, &rgctx);
3522 #endif
3523 }
3524
3525 static MonoInst*
3526 emit_get_rgctx_klass (MonoCompile *cfg, int context_used,
3527                                           MonoClass *klass, MonoRgctxInfoType rgctx_type)
3528 {
3529         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);
3530         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3531
3532         return emit_rgctx_fetch (cfg, rgctx, entry);
3533 }
3534
3535 static MonoInst*
3536 emit_get_rgctx_sig (MonoCompile *cfg, int context_used,
3537                                         MonoMethodSignature *sig, MonoRgctxInfoType rgctx_type)
3538 {
3539         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);
3540         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3541
3542         return emit_rgctx_fetch (cfg, rgctx, entry);
3543 }
3544
3545 static MonoInst*
3546 emit_get_rgctx_gsharedvt_call (MonoCompile *cfg, int context_used,
3547                                                            MonoMethodSignature *sig, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3548 {
3549         MonoJumpInfoGSharedVtCall *call_info;
3550         MonoJumpInfoRgctxEntry *entry;
3551         MonoInst *rgctx;
3552
3553         call_info = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoGSharedVtCall));
3554         call_info->sig = sig;
3555         call_info->method = cmethod;
3556
3557         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);
3558         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3559
3560         return emit_rgctx_fetch (cfg, rgctx, entry);
3561 }
3562
3563 /*
3564  * emit_get_rgctx_virt_method:
3565  *
3566  *   Return data for method VIRT_METHOD for a receiver of type KLASS.
3567  */
3568 static MonoInst*
3569 emit_get_rgctx_virt_method (MonoCompile *cfg, int context_used,
3570                                                         MonoClass *klass, MonoMethod *virt_method, MonoRgctxInfoType rgctx_type)
3571 {
3572         MonoJumpInfoVirtMethod *info;
3573         MonoJumpInfoRgctxEntry *entry;
3574         MonoInst *rgctx;
3575
3576         info = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoVirtMethod));
3577         info->klass = klass;
3578         info->method = virt_method;
3579
3580         entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->current_method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_VIRT_METHOD, info, rgctx_type);
3581         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3582
3583         return emit_rgctx_fetch (cfg, rgctx, entry);
3584 }
3585
3586 static MonoInst*
3587 emit_get_rgctx_gsharedvt_method (MonoCompile *cfg, int context_used,
3588                                                                  MonoMethod *cmethod, MonoGSharedVtMethodInfo *info)
3589 {
3590         MonoJumpInfoRgctxEntry *entry;
3591         MonoInst *rgctx;
3592
3593         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);
3594         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3595
3596         return emit_rgctx_fetch (cfg, rgctx, entry);
3597 }
3598
3599 /*
3600  * emit_get_rgctx_method:
3601  *
3602  *   Emit IR to load the property RGCTX_TYPE of CMETHOD. If context_used is 0, emit
3603  * normal constants, else emit a load from the rgctx.
3604  */
3605 static MonoInst*
3606 emit_get_rgctx_method (MonoCompile *cfg, int context_used,
3607                                            MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3608 {
3609         if (!context_used) {
3610                 MonoInst *ins;
3611
3612                 switch (rgctx_type) {
3613                 case MONO_RGCTX_INFO_METHOD:
3614                         EMIT_NEW_METHODCONST (cfg, ins, cmethod);
3615                         return ins;
3616                 case MONO_RGCTX_INFO_METHOD_RGCTX:
3617                         EMIT_NEW_METHOD_RGCTX_CONST (cfg, ins, cmethod);
3618                         return ins;
3619                 default:
3620                         g_assert_not_reached ();
3621                 }
3622         } else {
3623                 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);
3624                 MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3625
3626                 return emit_rgctx_fetch (cfg, rgctx, entry);
3627         }
3628 }
3629
3630 static MonoInst*
3631 emit_get_rgctx_field (MonoCompile *cfg, int context_used,
3632                                           MonoClassField *field, MonoRgctxInfoType rgctx_type)
3633 {
3634         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);
3635         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3636
3637         return emit_rgctx_fetch (cfg, rgctx, entry);
3638 }
3639
3640 static int
3641 get_gsharedvt_info_slot (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3642 {
3643         MonoGSharedVtMethodInfo *info = cfg->gsharedvt_info;
3644         MonoRuntimeGenericContextInfoTemplate *template;
3645         int i, idx;
3646
3647         g_assert (info);
3648
3649         for (i = 0; i < info->num_entries; ++i) {
3650                 MonoRuntimeGenericContextInfoTemplate *otemplate = &info->entries [i];
3651
3652                 if (otemplate->info_type == rgctx_type && otemplate->data == data && rgctx_type != MONO_RGCTX_INFO_LOCAL_OFFSET)
3653                         return i;
3654         }
3655
3656         if (info->num_entries == info->count_entries) {
3657                 MonoRuntimeGenericContextInfoTemplate *new_entries;
3658                 int new_count_entries = info->count_entries ? info->count_entries * 2 : 16;
3659
3660                 new_entries = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * new_count_entries);
3661
3662                 memcpy (new_entries, info->entries, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
3663                 info->entries = new_entries;
3664                 info->count_entries = new_count_entries;
3665         }
3666
3667         idx = info->num_entries;
3668         template = &info->entries [idx];
3669         template->info_type = rgctx_type;
3670         template->data = data;
3671
3672         info->num_entries ++;
3673
3674         return idx;
3675 }
3676
3677 /*
3678  * emit_get_gsharedvt_info:
3679  *
3680  *   This is similar to emit_get_rgctx_.., but loads the data from the gsharedvt info var instead of calling an rgctx fetch trampoline.
3681  */
3682 static MonoInst*
3683 emit_get_gsharedvt_info (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3684 {
3685         MonoInst *ins;
3686         int idx, dreg;
3687
3688         idx = get_gsharedvt_info_slot (cfg, data, rgctx_type);
3689         /* Load info->entries [idx] */
3690         dreg = alloc_preg (cfg);
3691         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, cfg->gsharedvt_info_var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
3692
3693         return ins;
3694 }
3695
3696 static MonoInst*
3697 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type)
3698 {
3699         return emit_get_gsharedvt_info (cfg, &klass->byval_arg, rgctx_type);
3700 }
3701
3702 /*
3703  * On return the caller must check @klass for load errors.
3704  */
3705 static void
3706 emit_class_init (MonoCompile *cfg, MonoClass *klass)
3707 {
3708         MonoInst *vtable_arg;
3709         int context_used;
3710         gboolean use_op_generic_class_init = FALSE;
3711
3712         context_used = mini_class_check_context_used (cfg, klass);
3713
3714         if (context_used) {
3715                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
3716                                                                                    klass, MONO_RGCTX_INFO_VTABLE);
3717         } else {
3718                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
3719
3720                 if (!vtable)
3721                         return;
3722                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
3723         }
3724
3725 #ifdef MONO_ARCH_HAVE_OP_GENERIC_CLASS_INIT
3726         if (!COMPILE_LLVM (cfg))
3727                 use_op_generic_class_init = TRUE;
3728 #endif
3729
3730         if (use_op_generic_class_init) {
3731                 MonoInst *ins;
3732
3733                 /*
3734                  * Using an opcode instead of emitting IR here allows the hiding of the call inside the opcode,
3735                  * so this doesn't have to clobber any regs and it doesn't break basic blocks.
3736                  */
3737                 MONO_INST_NEW (cfg, ins, OP_GENERIC_CLASS_INIT);
3738                 ins->sreg1 = vtable_arg->dreg;
3739                 MONO_ADD_INS (cfg->cbb, ins);
3740         } else {
3741                 static int byte_offset = -1;
3742                 static guint8 bitmask;
3743                 int bits_reg, inited_reg;
3744                 MonoBasicBlock *inited_bb;
3745                 MonoInst *args [16];
3746
3747                 if (byte_offset < 0)
3748                         mono_marshal_find_bitfield_offset (MonoVTable, initialized, &byte_offset, &bitmask);
3749
3750                 bits_reg = alloc_ireg (cfg);
3751                 inited_reg = alloc_ireg (cfg);
3752
3753                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, bits_reg, vtable_arg->dreg, byte_offset);
3754                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, inited_reg, bits_reg, bitmask);
3755
3756                 NEW_BBLOCK (cfg, inited_bb);
3757
3758                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, inited_reg, 0);
3759                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, inited_bb);
3760
3761                 args [0] = vtable_arg;
3762                 mono_emit_jit_icall (cfg, mono_generic_class_init, args);
3763
3764                 MONO_START_BB (cfg, inited_bb);
3765         }
3766 }
3767
3768 static void
3769 emit_seq_point (MonoCompile *cfg, MonoMethod *method, guint8* ip, gboolean intr_loc, gboolean nonempty_stack)
3770 {
3771         MonoInst *ins;
3772
3773         if (cfg->gen_seq_points && cfg->method == method) {
3774                 NEW_SEQ_POINT (cfg, ins, ip - cfg->header->code, intr_loc);
3775                 if (nonempty_stack)
3776                         ins->flags |= MONO_INST_NONEMPTY_STACK;
3777                 MONO_ADD_INS (cfg->cbb, ins);
3778         }
3779 }
3780
3781 static void
3782 save_cast_details (MonoCompile *cfg, MonoClass *klass, int obj_reg, gboolean null_check)
3783 {
3784         if (mini_get_debug_options ()->better_cast_details) {
3785                 int vtable_reg = alloc_preg (cfg);
3786                 int klass_reg = alloc_preg (cfg);
3787                 MonoBasicBlock *is_null_bb = NULL;
3788                 MonoInst *tls_get;
3789                 int to_klass_reg, context_used;
3790
3791                 if (null_check) {
3792                         NEW_BBLOCK (cfg, is_null_bb);
3793
3794                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
3795                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3796                 }
3797
3798                 tls_get = mono_get_jit_tls_intrinsic (cfg);
3799                 if (!tls_get) {
3800                         fprintf (stderr, "error: --debug=casts not supported on this platform.\n.");
3801                         exit (1);
3802                 }
3803
3804                 MONO_ADD_INS (cfg->cbb, tls_get);
3805                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3806                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3807
3808                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), klass_reg);
3809
3810                 context_used = mini_class_check_context_used (cfg, klass);
3811                 if (context_used) {
3812                         MonoInst *class_ins;
3813
3814                         class_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3815                         to_klass_reg = class_ins->dreg;
3816                 } else {
3817                         to_klass_reg = alloc_preg (cfg);
3818                         MONO_EMIT_NEW_CLASSCONST (cfg, to_klass_reg, klass);
3819                 }
3820                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_to), to_klass_reg);
3821
3822                 if (null_check)
3823                         MONO_START_BB (cfg, is_null_bb);
3824         }
3825 }
3826
3827 static void
3828 reset_cast_details (MonoCompile *cfg)
3829 {
3830         /* Reset the variables holding the cast details */
3831         if (mini_get_debug_options ()->better_cast_details) {
3832                 MonoInst *tls_get = mono_get_jit_tls_intrinsic (cfg);
3833
3834                 MONO_ADD_INS (cfg->cbb, tls_get);
3835                 /* It is enough to reset the from field */
3836                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), 0);
3837         }
3838 }
3839
3840 /*
3841  * On return the caller must check @array_class for load errors
3842  */
3843 static void
3844 mini_emit_check_array_type (MonoCompile *cfg, MonoInst *obj, MonoClass *array_class)
3845 {
3846         int vtable_reg = alloc_preg (cfg);
3847         int context_used;
3848
3849         context_used = mini_class_check_context_used (cfg, array_class);
3850
3851         save_cast_details (cfg, array_class, obj->dreg, FALSE);
3852
3853         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3854
3855         if (cfg->opt & MONO_OPT_SHARED) {
3856                 int class_reg = alloc_preg (cfg);
3857                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, class_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3858                 if (cfg->compile_aot) {
3859                         int klass_reg = alloc_preg (cfg);
3860                         MONO_EMIT_NEW_CLASSCONST (cfg, klass_reg, array_class);
3861                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, class_reg, klass_reg);
3862                 } else {
3863                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, class_reg, array_class);
3864                 }
3865         } else if (context_used) {
3866                 MonoInst *vtable_ins;
3867
3868                 vtable_ins = emit_get_rgctx_klass (cfg, context_used, array_class, MONO_RGCTX_INFO_VTABLE);
3869                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vtable_ins->dreg);
3870         } else {
3871                 if (cfg->compile_aot) {
3872                         int vt_reg;
3873                         MonoVTable *vtable;
3874
3875                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3876                                 return;
3877                         vt_reg = alloc_preg (cfg);
3878                         MONO_EMIT_NEW_VTABLECONST (cfg, vt_reg, vtable);
3879                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vt_reg);
3880                 } else {
3881                         MonoVTable *vtable;
3882                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3883                                 return;
3884                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vtable);
3885                 }
3886         }
3887         
3888         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ArrayTypeMismatchException");
3889
3890         reset_cast_details (cfg);
3891 }
3892
3893 /**
3894  * Handles unbox of a Nullable<T>. If context_used is non zero, then shared 
3895  * generic code is generated.
3896  */
3897 static MonoInst*
3898 handle_unbox_nullable (MonoCompile* cfg, MonoInst* val, MonoClass* klass, int context_used)
3899 {
3900         MonoMethod* method = mono_class_get_method_from_name (klass, "Unbox", 1);
3901
3902         if (context_used) {
3903                 MonoInst *rgctx, *addr;
3904
3905                 /* FIXME: What if the class is shared?  We might not
3906                    have to get the address of the method from the
3907                    RGCTX. */
3908                 addr = emit_get_rgctx_method (cfg, context_used, method,
3909                                                                           MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
3910
3911                 rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3912
3913                 return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
3914         } else {
3915                 gboolean pass_vtable, pass_mrgctx;
3916                 MonoInst *rgctx_arg = NULL;
3917
3918                 check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
3919                 g_assert (!pass_mrgctx);
3920
3921                 if (pass_vtable) {
3922                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
3923
3924                         g_assert (vtable);
3925                         EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
3926                 }
3927
3928                 return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
3929         }
3930 }
3931
3932 static MonoInst*
3933 handle_unbox (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, int context_used)
3934 {
3935         MonoInst *add;
3936         int obj_reg;
3937         int vtable_reg = alloc_dreg (cfg ,STACK_PTR);
3938         int klass_reg = alloc_dreg (cfg ,STACK_PTR);
3939         int eclass_reg = alloc_dreg (cfg ,STACK_PTR);
3940         int rank_reg = alloc_dreg (cfg ,STACK_I4);
3941
3942         obj_reg = sp [0]->dreg;
3943         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3944         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
3945
3946         /* FIXME: generics */
3947         g_assert (klass->rank == 0);
3948                         
3949         // Check rank == 0
3950         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, 0);
3951         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
3952
3953         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3954         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, element_class));
3955
3956         if (context_used) {
3957                 MonoInst *element_class;
3958
3959                 /* This assertion is from the unboxcast insn */
3960                 g_assert (klass->rank == 0);
3961
3962                 element_class = emit_get_rgctx_klass (cfg, context_used,
3963                                 klass, MONO_RGCTX_INFO_ELEMENT_KLASS);
3964
3965                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, eclass_reg, element_class->dreg);
3966                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
3967         } else {
3968                 save_cast_details (cfg, klass->element_class, obj_reg, FALSE);
3969                 mini_emit_class_check (cfg, eclass_reg, klass->element_class);
3970                 reset_cast_details (cfg);
3971         }
3972
3973         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), obj_reg, sizeof (MonoObject));
3974         MONO_ADD_INS (cfg->cbb, add);
3975         add->type = STACK_MP;
3976         add->klass = klass;
3977
3978         return add;
3979 }
3980
3981 static MonoInst*
3982 handle_unbox_gsharedvt (MonoCompile *cfg, MonoClass *klass, MonoInst *obj)
3983 {
3984         MonoInst *addr, *klass_inst, *is_ref, *args[16];
3985         MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
3986         MonoInst *ins;
3987         int dreg, addr_reg;
3988
3989         klass_inst = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_KLASS);
3990
3991         /* obj */
3992         args [0] = obj;
3993
3994         /* klass */
3995         args [1] = klass_inst;
3996
3997         /* CASTCLASS */
3998         obj = mono_emit_jit_icall (cfg, mono_object_castclass_unbox, args);
3999
4000         NEW_BBLOCK (cfg, is_ref_bb);
4001         NEW_BBLOCK (cfg, is_nullable_bb);
4002         NEW_BBLOCK (cfg, end_bb);
4003         is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
4004         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 1);
4005         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
4006
4007         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 2);
4008         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
4009
4010         /* This will contain either the address of the unboxed vtype, or an address of the temporary where the ref is stored */
4011         addr_reg = alloc_dreg (cfg, STACK_MP);
4012
4013         /* Non-ref case */
4014         /* UNBOX */
4015         NEW_BIALU_IMM (cfg, addr, OP_ADD_IMM, addr_reg, obj->dreg, sizeof (MonoObject));
4016         MONO_ADD_INS (cfg->cbb, addr);
4017
4018         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4019
4020         /* Ref case */
4021         MONO_START_BB (cfg, is_ref_bb);
4022
4023         /* Save the ref to a temporary */
4024         dreg = alloc_ireg (cfg);
4025         EMIT_NEW_VARLOADA_VREG (cfg, addr, dreg, &klass->byval_arg);
4026         addr->dreg = addr_reg;
4027         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, obj->dreg);
4028         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4029
4030         /* Nullable case */
4031         MONO_START_BB (cfg, is_nullable_bb);
4032
4033         {
4034                 MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX);
4035                 MonoInst *unbox_call;
4036                 MonoMethodSignature *unbox_sig;
4037
4038                 unbox_sig = mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
4039                 unbox_sig->ret = &klass->byval_arg;
4040                 unbox_sig->param_count = 1;
4041                 unbox_sig->params [0] = &mono_defaults.object_class->byval_arg;
4042                 unbox_call = mono_emit_calli (cfg, unbox_sig, &obj, addr, NULL, NULL);
4043
4044                 EMIT_NEW_VARLOADA_VREG (cfg, addr, unbox_call->dreg, &klass->byval_arg);
4045                 addr->dreg = addr_reg;
4046         }
4047
4048         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4049
4050         /* End */
4051         MONO_START_BB (cfg, end_bb);
4052
4053         /* LDOBJ */
4054         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr_reg, 0);
4055
4056         return ins;
4057 }
4058
4059 /*
4060  * Returns NULL and set the cfg exception on error.
4061  */
4062 static MonoInst*
4063 handle_alloc (MonoCompile *cfg, MonoClass *klass, gboolean for_box, int context_used)
4064 {
4065         MonoInst *iargs [2];
4066         void *alloc_ftn;
4067
4068         if (context_used) {
4069                 MonoInst *data;
4070                 int rgctx_info;
4071                 MonoInst *iargs [2];
4072                 gboolean known_instance_size = !mini_is_gsharedvt_klass (klass);
4073
4074                 MonoMethod *managed_alloc = mono_gc_get_managed_allocator (klass, for_box, known_instance_size);
4075
4076                 if (cfg->opt & MONO_OPT_SHARED)
4077                         rgctx_info = MONO_RGCTX_INFO_KLASS;
4078                 else
4079                         rgctx_info = MONO_RGCTX_INFO_VTABLE;
4080                 data = emit_get_rgctx_klass (cfg, context_used, klass, rgctx_info);
4081
4082                 if (cfg->opt & MONO_OPT_SHARED) {
4083                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
4084                         iargs [1] = data;
4085                         alloc_ftn = mono_object_new;
4086                 } else {
4087                         iargs [0] = data;
4088                         alloc_ftn = mono_object_new_specific;
4089                 }
4090
4091                 if (managed_alloc && !(cfg->opt & MONO_OPT_SHARED)) {
4092                         if (known_instance_size) {
4093                                 int size = mono_class_instance_size (klass);
4094                                 if (size < sizeof (MonoObject))
4095                                         g_error ("Invalid size %d for class %s", size, mono_type_get_full_name (klass));
4096
4097                                 EMIT_NEW_ICONST (cfg, iargs [1], mono_gc_get_aligned_size_for_allocator (size));
4098                         }
4099                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
4100                 }
4101
4102                 return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
4103         }
4104
4105         if (cfg->opt & MONO_OPT_SHARED) {
4106                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
4107                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
4108
4109                 alloc_ftn = mono_object_new;
4110         } else if (cfg->compile_aot && cfg->cbb->out_of_line && klass->type_token && klass->image == mono_defaults.corlib && !klass->generic_class) {
4111                 /* This happens often in argument checking code, eg. throw new FooException... */
4112                 /* Avoid relocations and save some space by calling a helper function specialized to mscorlib */
4113                 EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (klass->type_token));
4114                 return mono_emit_jit_icall (cfg, mono_helper_newobj_mscorlib, iargs);
4115         } else {
4116                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
4117                 MonoMethod *managed_alloc = NULL;
4118                 gboolean pass_lw;
4119
4120                 if (!vtable) {
4121                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4122                         cfg->exception_ptr = klass;
4123                         return NULL;
4124                 }
4125
4126                 managed_alloc = mono_gc_get_managed_allocator (klass, for_box, TRUE);
4127
4128                 if (managed_alloc) {
4129                         int size = mono_class_instance_size (klass);
4130                         if (size < sizeof (MonoObject))
4131                                 g_error ("Invalid size %d for class %s", size, mono_type_get_full_name (klass));
4132
4133                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
4134                         EMIT_NEW_ICONST (cfg, iargs [1], mono_gc_get_aligned_size_for_allocator (size));
4135                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
4136                 }
4137                 alloc_ftn = mono_class_get_allocation_ftn (vtable, for_box, &pass_lw);
4138                 if (pass_lw) {
4139                         guint32 lw = vtable->klass->instance_size;
4140                         lw = ((lw + (sizeof (gpointer) - 1)) & ~(sizeof (gpointer) - 1)) / sizeof (gpointer);
4141                         EMIT_NEW_ICONST (cfg, iargs [0], lw);
4142                         EMIT_NEW_VTABLECONST (cfg, iargs [1], vtable);
4143                 }
4144                 else {
4145                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
4146                 }
4147         }
4148
4149         return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
4150 }
4151         
4152 /*
4153  * Returns NULL and set the cfg exception on error.
4154  */     
4155 static MonoInst*
4156 handle_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_used)
4157 {
4158         MonoInst *alloc, *ins;
4159
4160         if (mono_class_is_nullable (klass)) {
4161                 MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
4162
4163                 if (context_used) {
4164                         /* FIXME: What if the class is shared?  We might not
4165                            have to get the method address from the RGCTX. */
4166                         MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
4167                                                                                                         MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
4168                         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
4169
4170                         return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
4171                 } else {
4172                         gboolean pass_vtable, pass_mrgctx;
4173                         MonoInst *rgctx_arg = NULL;
4174
4175                         check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
4176                         g_assert (!pass_mrgctx);
4177
4178                         if (pass_vtable) {
4179                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
4180
4181                                 g_assert (vtable);
4182                                 EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
4183                         }
4184
4185                         return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
4186                 }
4187         }
4188
4189         if (mini_is_gsharedvt_klass (klass)) {
4190                 MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
4191                 MonoInst *res, *is_ref, *src_var, *addr;
4192                 int dreg;
4193
4194                 dreg = alloc_ireg (cfg);
4195
4196                 NEW_BBLOCK (cfg, is_ref_bb);
4197                 NEW_BBLOCK (cfg, is_nullable_bb);
4198                 NEW_BBLOCK (cfg, end_bb);
4199                 is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
4200                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 1);
4201                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
4202
4203                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 2);
4204                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
4205
4206                 /* Non-ref case */
4207                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4208                 if (!alloc)
4209                         return NULL;
4210                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4211                 ins->opcode = OP_STOREV_MEMBASE;
4212
4213                 EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, alloc->dreg);
4214                 res->type = STACK_OBJ;
4215                 res->klass = klass;
4216                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4217                 
4218                 /* Ref case */
4219                 MONO_START_BB (cfg, is_ref_bb);
4220
4221                 /* val is a vtype, so has to load the value manually */
4222                 src_var = get_vreg_to_inst (cfg, val->dreg);
4223                 if (!src_var)
4224                         src_var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, val->dreg);
4225                 EMIT_NEW_VARLOADA (cfg, addr, src_var, src_var->inst_vtype);
4226                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, addr->dreg, 0);
4227                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4228
4229                 /* Nullable case */
4230                 MONO_START_BB (cfg, is_nullable_bb);
4231
4232                 {
4233                         MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass,
4234                                                                                                         MONO_RGCTX_INFO_NULLABLE_CLASS_BOX);
4235                         MonoInst *box_call;
4236                         MonoMethodSignature *box_sig;
4237
4238                         /*
4239                          * klass is Nullable<T>, need to call Nullable<T>.Box () using a gsharedvt signature, but we cannot
4240                          * construct that method at JIT time, so have to do things by hand.
4241                          */
4242                         box_sig = mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
4243                         box_sig->ret = &mono_defaults.object_class->byval_arg;
4244                         box_sig->param_count = 1;
4245                         box_sig->params [0] = &klass->byval_arg;
4246                         box_call = mono_emit_calli (cfg, box_sig, &val, addr, NULL, NULL);
4247                         EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, box_call->dreg);
4248                         res->type = STACK_OBJ;
4249                         res->klass = klass;
4250                 }
4251
4252                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4253
4254                 MONO_START_BB (cfg, end_bb);
4255
4256                 return res;
4257         } else {
4258                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4259                 if (!alloc)
4260                         return NULL;
4261
4262                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4263                 return alloc;
4264         }
4265 }
4266
4267 static gboolean
4268 mini_class_has_reference_variant_generic_argument (MonoCompile *cfg, MonoClass *klass, int context_used)
4269 {
4270         int i;
4271         MonoGenericContainer *container;
4272         MonoGenericInst *ginst;
4273
4274         if (klass->generic_class) {
4275                 container = klass->generic_class->container_class->generic_container;
4276                 ginst = klass->generic_class->context.class_inst;
4277         } else if (klass->generic_container && context_used) {
4278                 container = klass->generic_container;
4279                 ginst = container->context.class_inst;
4280         } else {
4281                 return FALSE;
4282         }
4283
4284         for (i = 0; i < container->type_argc; ++i) {
4285                 MonoType *type;
4286                 if (!(mono_generic_container_get_param_info (container, i)->flags & (MONO_GEN_PARAM_VARIANT|MONO_GEN_PARAM_COVARIANT)))
4287                         continue;
4288                 type = ginst->type_argv [i];
4289                 if (mini_type_is_reference (type))
4290                         return TRUE;
4291         }
4292         return FALSE;
4293 }
4294
4295 static GHashTable* direct_icall_type_hash;
4296
4297 static gboolean
4298 icall_is_direct_callable (MonoCompile *cfg, MonoMethod *cmethod)
4299 {
4300         /* LLVM on amd64 can't handle calls to non-32 bit addresses */
4301         if (!direct_icalls_enabled (cfg))
4302                 return FALSE;
4303
4304         /*
4305          * An icall is directly callable if it doesn't directly or indirectly call mono_raise_exception ().
4306          * Whitelist a few icalls for now.
4307          */
4308         if (!direct_icall_type_hash) {
4309                 GHashTable *h = g_hash_table_new (g_str_hash, g_str_equal);
4310
4311                 g_hash_table_insert (h, (char*)"Decimal", GUINT_TO_POINTER (1));
4312                 g_hash_table_insert (h, (char*)"Number", GUINT_TO_POINTER (1));
4313                 g_hash_table_insert (h, (char*)"Buffer", GUINT_TO_POINTER (1));
4314                 g_hash_table_insert (h, (char*)"Monitor", GUINT_TO_POINTER (1));
4315                 mono_memory_barrier ();
4316                 direct_icall_type_hash = h;
4317         }
4318
4319         if (cmethod->klass == mono_defaults.math_class)
4320                 return TRUE;
4321         /* No locking needed */
4322         if (cmethod->klass->image == mono_defaults.corlib && g_hash_table_lookup (direct_icall_type_hash, cmethod->klass->name))
4323                 return TRUE;
4324         return FALSE;
4325 }
4326
4327 #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)
4328
4329 static MonoInst*
4330 emit_castclass_with_cache (MonoCompile *cfg, MonoClass *klass, MonoInst **args)
4331 {
4332         MonoMethod *mono_castclass;
4333         MonoInst *res;
4334
4335         mono_castclass = mono_marshal_get_castclass_with_cache ();
4336
4337         save_cast_details (cfg, klass, args [0]->dreg, TRUE);
4338         res = mono_emit_method_call (cfg, mono_castclass, args, NULL);
4339         reset_cast_details (cfg);
4340
4341         return res;
4342 }
4343
4344 static int
4345 get_castclass_cache_idx (MonoCompile *cfg)
4346 {
4347         /* Each CASTCLASS_CACHE patch needs a unique index which identifies the call site */
4348         cfg->castclass_cache_index ++;
4349         return (cfg->method_index << 16) | cfg->castclass_cache_index;
4350 }
4351
4352 static MonoInst*
4353 emit_castclass_with_cache_nonshared (MonoCompile *cfg, MonoInst *obj, MonoClass *klass)
4354 {
4355         MonoInst *args [3];
4356         int idx;
4357
4358         /* obj */
4359         args [0] = obj;
4360
4361         /* klass */
4362         EMIT_NEW_CLASSCONST (cfg, args [1], klass);
4363
4364         /* inline cache*/
4365         if (cfg->compile_aot) {
4366                 idx = get_castclass_cache_idx (cfg);
4367                 EMIT_NEW_AOTCONST (cfg, args [2], MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
4368         } else {
4369                 EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));
4370         }
4371
4372         /*The wrapper doesn't inline well so the bloat of inlining doesn't pay off.*/
4373         return emit_castclass_with_cache (cfg, klass, args);
4374 }
4375
4376 /*
4377  * Returns NULL and set the cfg exception on error.
4378  */
4379 static MonoInst*
4380 handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, guint8 *ip, int *inline_costs)
4381 {
4382         MonoBasicBlock *is_null_bb;
4383         int obj_reg = src->dreg;
4384         int vtable_reg = alloc_preg (cfg);
4385         int context_used;
4386         MonoInst *klass_inst = NULL, *res;
4387
4388         context_used = mini_class_check_context_used (cfg, klass);
4389
4390         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
4391                 res = emit_castclass_with_cache_nonshared (cfg, src, klass);
4392                 (*inline_costs) += 2;
4393                 return res;
4394         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
4395                 MonoMethod *mono_castclass;
4396                 MonoInst *iargs [1];
4397                 int costs;
4398
4399                 mono_castclass = mono_marshal_get_castclass (klass); 
4400                 iargs [0] = src;
4401                                 
4402                 save_cast_details (cfg, klass, src->dreg, TRUE);
4403                 costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), 
4404                                                            iargs, ip, cfg->real_offset, TRUE);
4405                 reset_cast_details (cfg);
4406                 CHECK_CFG_EXCEPTION;
4407                 g_assert (costs > 0);
4408                                 
4409                 cfg->real_offset += 5;
4410
4411                 (*inline_costs) += costs;
4412
4413                 return src;
4414         }
4415
4416         if (context_used) {
4417                 MonoInst *args [3];
4418
4419                 if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
4420                         MonoInst *cache_ins;
4421
4422                         cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
4423
4424                         /* obj */
4425                         args [0] = src;
4426
4427                         /* klass - it's the second element of the cache entry*/
4428                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
4429
4430                         /* cache */
4431                         args [2] = cache_ins;
4432
4433                         return emit_castclass_with_cache (cfg, klass, args);
4434                 }
4435
4436                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
4437         }
4438
4439         NEW_BBLOCK (cfg, is_null_bb);
4440
4441         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4442         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
4443
4444         save_cast_details (cfg, klass, obj_reg, FALSE);
4445
4446         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4447                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4448                 mini_emit_iface_cast (cfg, vtable_reg, klass, NULL, NULL);
4449         } else {
4450                 int klass_reg = alloc_preg (cfg);
4451
4452                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4453
4454                 if (!klass->rank && !cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
4455                         /* the remoting code is broken, access the class for now */
4456                         if (0) { /*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4457                                 MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4458                                 if (!vt) {
4459                                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4460                                         cfg->exception_ptr = klass;
4461                                         return NULL;
4462                                 }
4463                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4464                         } else {
4465                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4466                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4467                         }
4468                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4469                 } else {
4470                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4471                         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, klass_inst, is_null_bb);
4472                 }
4473         }
4474
4475         MONO_START_BB (cfg, is_null_bb);
4476
4477         reset_cast_details (cfg);
4478
4479         return src;
4480
4481 exception_exit:
4482         return NULL;
4483 }
4484
4485 /*
4486  * Returns NULL and set the cfg exception on error.
4487  */
4488 static MonoInst*
4489 handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
4490 {
4491         MonoInst *ins;
4492         MonoBasicBlock *is_null_bb, *false_bb, *end_bb;
4493         int obj_reg = src->dreg;
4494         int vtable_reg = alloc_preg (cfg);
4495         int res_reg = alloc_ireg_ref (cfg);
4496         MonoInst *klass_inst = NULL;
4497
4498         if (context_used) {
4499                 MonoInst *args [3];
4500
4501                 if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
4502                         MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
4503                         MonoInst *cache_ins;
4504
4505                         cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
4506
4507                         /* obj */
4508                         args [0] = src;
4509
4510                         /* klass - it's the second element of the cache entry*/
4511                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
4512
4513                         /* cache */
4514                         args [2] = cache_ins;
4515
4516                         return mono_emit_method_call (cfg, mono_isinst, args, NULL);
4517                 }
4518
4519                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
4520         }
4521
4522         NEW_BBLOCK (cfg, is_null_bb);
4523         NEW_BBLOCK (cfg, false_bb);
4524         NEW_BBLOCK (cfg, end_bb);
4525
4526         /* Do the assignment at the beginning, so the other assignment can be if converted */
4527         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, res_reg, obj_reg);
4528         ins->type = STACK_OBJ;
4529         ins->klass = klass;
4530
4531         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4532         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_null_bb);
4533
4534         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4535
4536         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4537                 g_assert (!context_used);
4538                 /* the is_null_bb target simply copies the input register to the output */
4539                 mini_emit_iface_cast (cfg, vtable_reg, klass, false_bb, is_null_bb);
4540         } else {
4541                 int klass_reg = alloc_preg (cfg);
4542
4543                 if (klass->rank) {
4544                         int rank_reg = alloc_preg (cfg);
4545                         int eclass_reg = alloc_preg (cfg);
4546
4547                         g_assert (!context_used);
4548                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
4549                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
4550                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4551                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4552                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
4553                         if (klass->cast_class == mono_defaults.object_class) {
4554                                 int parent_reg = alloc_preg (cfg);
4555                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
4556                                 mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, is_null_bb);
4557                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4558                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4559                         } else if (klass->cast_class == mono_defaults.enum_class->parent) {
4560                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, is_null_bb);
4561                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);                          
4562                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4563                         } else if (klass->cast_class == mono_defaults.enum_class) {
4564                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4565                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4566                         } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
4567                                 mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4568                         } else {
4569                                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY)) {
4570                                         /* Check that the object is a vector too */
4571                                         int bounds_reg = alloc_preg (cfg);
4572                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
4573                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
4574                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4575                                 }
4576
4577                                 /* the is_null_bb target simply copies the input register to the output */
4578                                 mini_emit_isninst_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4579                         }
4580                 } else if (mono_class_is_nullable (klass)) {
4581                         g_assert (!context_used);
4582                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4583                         /* the is_null_bb target simply copies the input register to the output */
4584                         mini_emit_isninst_cast (cfg, klass_reg, klass->cast_class, false_bb, is_null_bb);
4585                 } else {
4586                         if (!cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
4587                                 g_assert (!context_used);
4588                                 /* the remoting code is broken, access the class for now */
4589                                 if (0) {/*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4590                                         MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4591                                         if (!vt) {
4592                                                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4593                                                 cfg->exception_ptr = klass;
4594                                                 return NULL;
4595                                         }
4596                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4597                                 } else {
4598                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4599                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4600                                 }
4601                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4602                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, is_null_bb);
4603                         } else {
4604                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4605                                 /* the is_null_bb target simply copies the input register to the output */
4606                                 mini_emit_isninst_cast_inst (cfg, klass_reg, klass, klass_inst, false_bb, is_null_bb);
4607                         }
4608                 }
4609         }
4610
4611         MONO_START_BB (cfg, false_bb);
4612
4613         MONO_EMIT_NEW_PCONST (cfg, res_reg, 0);
4614         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4615
4616         MONO_START_BB (cfg, is_null_bb);
4617
4618         MONO_START_BB (cfg, end_bb);
4619
4620         return ins;
4621 }
4622
4623 static MonoInst*
4624 handle_cisinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4625 {
4626         /* This opcode takes as input an object reference and a class, and returns:
4627         0) if the object is an instance of the class,
4628         1) if the object is not instance of the class,
4629         2) if the object is a proxy whose type cannot be determined */
4630
4631         MonoInst *ins;
4632 #ifndef DISABLE_REMOTING
4633         MonoBasicBlock *true_bb, *false_bb, *false2_bb, *end_bb, *no_proxy_bb, *interface_fail_bb;
4634 #else
4635         MonoBasicBlock *true_bb, *false_bb, *end_bb;
4636 #endif
4637         int obj_reg = src->dreg;
4638         int dreg = alloc_ireg (cfg);
4639         int tmp_reg;
4640 #ifndef DISABLE_REMOTING
4641         int klass_reg = alloc_preg (cfg);
4642 #endif
4643
4644         NEW_BBLOCK (cfg, true_bb);
4645         NEW_BBLOCK (cfg, false_bb);
4646         NEW_BBLOCK (cfg, end_bb);
4647 #ifndef DISABLE_REMOTING
4648         NEW_BBLOCK (cfg, false2_bb);
4649         NEW_BBLOCK (cfg, no_proxy_bb);
4650 #endif
4651
4652         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4653         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, false_bb);
4654
4655         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4656 #ifndef DISABLE_REMOTING
4657                 NEW_BBLOCK (cfg, interface_fail_bb);
4658 #endif
4659
4660                 tmp_reg = alloc_preg (cfg);
4661                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4662 #ifndef DISABLE_REMOTING
4663                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, true_bb);
4664                 MONO_START_BB (cfg, interface_fail_bb);
4665                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4666                 
4667                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, false_bb);
4668
4669                 tmp_reg = alloc_preg (cfg);
4670                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4671                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4672                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false2_bb);                
4673 #else
4674                 mini_emit_iface_cast (cfg, tmp_reg, klass, false_bb, true_bb);
4675 #endif
4676         } else {
4677 #ifndef DISABLE_REMOTING
4678                 tmp_reg = alloc_preg (cfg);
4679                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4680                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4681
4682                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4683                 tmp_reg = alloc_preg (cfg);
4684                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4685                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4686
4687                 tmp_reg = alloc_preg (cfg);             
4688                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4689                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4690                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4691                 
4692                 mini_emit_isninst_cast (cfg, klass_reg, klass, false2_bb, true_bb);
4693                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false2_bb);
4694
4695                 MONO_START_BB (cfg, no_proxy_bb);
4696
4697                 mini_emit_isninst_cast (cfg, klass_reg, klass, false_bb, true_bb);
4698 #else
4699                 g_error ("transparent proxy support is disabled while trying to JIT code that uses it");
4700 #endif
4701         }
4702
4703         MONO_START_BB (cfg, false_bb);
4704
4705         MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4706         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4707
4708 #ifndef DISABLE_REMOTING
4709         MONO_START_BB (cfg, false2_bb);
4710
4711         MONO_EMIT_NEW_ICONST (cfg, dreg, 2);
4712         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4713 #endif
4714
4715         MONO_START_BB (cfg, true_bb);
4716
4717         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4718
4719         MONO_START_BB (cfg, end_bb);
4720
4721         /* FIXME: */
4722         MONO_INST_NEW (cfg, ins, OP_ICONST);
4723         ins->dreg = dreg;
4724         ins->type = STACK_I4;
4725
4726         return ins;
4727 }
4728
4729 static MonoInst*
4730 handle_ccastclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4731 {
4732         /* This opcode takes as input an object reference and a class, and returns:
4733         0) if the object is an instance of the class,
4734         1) if the object is a proxy whose type cannot be determined
4735         an InvalidCastException exception is thrown otherwhise*/
4736         
4737         MonoInst *ins;
4738 #ifndef DISABLE_REMOTING
4739         MonoBasicBlock *end_bb, *ok_result_bb, *no_proxy_bb, *interface_fail_bb, *fail_1_bb;
4740 #else
4741         MonoBasicBlock *ok_result_bb;
4742 #endif
4743         int obj_reg = src->dreg;
4744         int dreg = alloc_ireg (cfg);
4745         int tmp_reg = alloc_preg (cfg);
4746
4747 #ifndef DISABLE_REMOTING
4748         int klass_reg = alloc_preg (cfg);
4749         NEW_BBLOCK (cfg, end_bb);
4750 #endif
4751
4752         NEW_BBLOCK (cfg, ok_result_bb);
4753
4754         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4755         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, ok_result_bb);
4756
4757         save_cast_details (cfg, klass, obj_reg, FALSE);
4758
4759         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4760 #ifndef DISABLE_REMOTING
4761                 NEW_BBLOCK (cfg, interface_fail_bb);
4762         
4763                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4764                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, ok_result_bb);
4765                 MONO_START_BB (cfg, interface_fail_bb);
4766                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4767
4768                 mini_emit_class_check (cfg, klass_reg, mono_defaults.transparent_proxy_class);
4769
4770                 tmp_reg = alloc_preg (cfg);             
4771                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4772                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4773                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
4774                 
4775                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4776                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4777 #else
4778                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4779                 mini_emit_iface_cast (cfg, tmp_reg, klass, NULL, NULL);
4780                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, ok_result_bb);
4781 #endif
4782         } else {
4783 #ifndef DISABLE_REMOTING
4784                 NEW_BBLOCK (cfg, no_proxy_bb);
4785
4786                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4787                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4788                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4789
4790                 tmp_reg = alloc_preg (cfg);
4791                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4792                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4793
4794                 tmp_reg = alloc_preg (cfg);
4795                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4796                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4797                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4798
4799                 NEW_BBLOCK (cfg, fail_1_bb);
4800                 
4801                 mini_emit_isninst_cast (cfg, klass_reg, klass, fail_1_bb, ok_result_bb);
4802
4803                 MONO_START_BB (cfg, fail_1_bb);
4804
4805                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4806                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4807
4808                 MONO_START_BB (cfg, no_proxy_bb);
4809
4810                 mini_emit_castclass (cfg, obj_reg, klass_reg, klass, ok_result_bb);
4811 #else
4812                 g_error ("Transparent proxy support is disabled while trying to JIT code that uses it");
4813 #endif
4814         }
4815
4816         MONO_START_BB (cfg, ok_result_bb);
4817
4818         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4819
4820 #ifndef DISABLE_REMOTING
4821         MONO_START_BB (cfg, end_bb);
4822 #endif
4823
4824         /* FIXME: */
4825         MONO_INST_NEW (cfg, ins, OP_ICONST);
4826         ins->dreg = dreg;
4827         ins->type = STACK_I4;
4828
4829         return ins;
4830 }
4831
4832 static G_GNUC_UNUSED MonoInst*
4833 handle_enum_has_flag (MonoCompile *cfg, MonoClass *klass, MonoInst *enum_this, MonoInst *enum_flag)
4834 {
4835         MonoType *enum_type = mono_type_get_underlying_type (&klass->byval_arg);
4836         guint32 load_opc = mono_type_to_load_membase (cfg, enum_type);
4837         gboolean is_i4;
4838
4839         switch (enum_type->type) {
4840         case MONO_TYPE_I8:
4841         case MONO_TYPE_U8:
4842 #if SIZEOF_REGISTER == 8
4843         case MONO_TYPE_I:
4844         case MONO_TYPE_U:
4845 #endif
4846                 is_i4 = FALSE;
4847                 break;
4848         default:
4849                 is_i4 = TRUE;
4850                 break;
4851         }
4852
4853         {
4854                 MonoInst *load, *and, *cmp, *ceq;
4855                 int enum_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
4856                 int and_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
4857                 int dest_reg = alloc_ireg (cfg);
4858
4859                 EMIT_NEW_LOAD_MEMBASE (cfg, load, load_opc, enum_reg, enum_this->dreg, 0);
4860                 EMIT_NEW_BIALU (cfg, and, is_i4 ? OP_IAND : OP_LAND, and_reg, enum_reg, enum_flag->dreg);
4861                 EMIT_NEW_BIALU (cfg, cmp, is_i4 ? OP_ICOMPARE : OP_LCOMPARE, -1, and_reg, enum_flag->dreg);
4862                 EMIT_NEW_UNALU (cfg, ceq, is_i4 ? OP_ICEQ : OP_LCEQ, dest_reg, -1);
4863
4864                 ceq->type = STACK_I4;
4865
4866                 if (!is_i4) {
4867                         load = mono_decompose_opcode (cfg, load);
4868                         and = mono_decompose_opcode (cfg, and);
4869                         cmp = mono_decompose_opcode (cfg, cmp);
4870                         ceq = mono_decompose_opcode (cfg, ceq);
4871                 }
4872
4873                 return ceq;
4874         }
4875 }
4876
4877 /*
4878  * Returns NULL and set the cfg exception on error.
4879  */
4880 static G_GNUC_UNUSED MonoInst*
4881 handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, MonoMethod *method, int context_used, gboolean virtual)
4882 {
4883         MonoInst *ptr;
4884         int dreg;
4885         gpointer trampoline;
4886         MonoInst *obj, *method_ins, *tramp_ins;
4887         MonoDomain *domain;
4888         guint8 **code_slot;
4889
4890         if (virtual) {
4891                 MonoMethod *invoke = mono_get_delegate_invoke (klass);
4892                 g_assert (invoke);
4893
4894                 if (!mono_get_delegate_virtual_invoke_impl (mono_method_signature (invoke), context_used ? NULL : method))
4895                         return NULL;
4896         }
4897
4898         obj = handle_alloc (cfg, klass, FALSE, 0);
4899         if (!obj)
4900                 return NULL;
4901
4902         /* Inline the contents of mono_delegate_ctor */
4903
4904         /* Set target field */
4905         /* Optimize away setting of NULL target */
4906         if (!(target->opcode == OP_PCONST && target->inst_p0 == 0)) {
4907                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target), target->dreg);
4908                 if (cfg->gen_write_barriers) {
4909                         dreg = alloc_preg (cfg);
4910                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target));
4911                         emit_write_barrier (cfg, ptr, target);
4912                 }
4913         }
4914
4915         /* Set method field */
4916         method_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
4917         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method), method_ins->dreg);
4918
4919         /* 
4920          * To avoid looking up the compiled code belonging to the target method
4921          * in mono_delegate_trampoline (), we allocate a per-domain memory slot to
4922          * store it, and we fill it after the method has been compiled.
4923          */
4924         if (!method->dynamic && !(cfg->opt & MONO_OPT_SHARED)) {
4925                 MonoInst *code_slot_ins;
4926
4927                 if (context_used) {
4928                         code_slot_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD_DELEGATE_CODE);
4929                 } else {
4930                         domain = mono_domain_get ();
4931                         mono_domain_lock (domain);
4932                         if (!domain_jit_info (domain)->method_code_hash)
4933                                 domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
4934                         code_slot = g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, method);
4935                         if (!code_slot) {
4936                                 code_slot = mono_domain_alloc0 (domain, sizeof (gpointer));
4937                                 g_hash_table_insert (domain_jit_info (domain)->method_code_hash, method, code_slot);
4938                         }
4939                         mono_domain_unlock (domain);
4940
4941                         if (cfg->compile_aot)
4942                                 EMIT_NEW_AOTCONST (cfg, code_slot_ins, MONO_PATCH_INFO_METHOD_CODE_SLOT, method);
4943                         else
4944                                 EMIT_NEW_PCONST (cfg, code_slot_ins, code_slot);
4945                 }
4946                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_code), code_slot_ins->dreg);                
4947         }
4948
4949         if (cfg->compile_aot) {
4950                 MonoDelegateClassMethodPair *del_tramp;
4951
4952                 del_tramp = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoDelegateClassMethodPair));
4953                 del_tramp->klass = klass;
4954                 del_tramp->method = context_used ? NULL : method;
4955                 del_tramp->virtual = virtual;
4956                 EMIT_NEW_AOTCONST (cfg, tramp_ins, MONO_PATCH_INFO_DELEGATE_TRAMPOLINE, del_tramp);
4957         } else {
4958                 if (virtual)
4959                         trampoline = mono_create_delegate_virtual_trampoline (cfg->domain, klass, context_used ? NULL : method);
4960                 else
4961                         trampoline = mono_create_delegate_trampoline_info (cfg->domain, klass, context_used ? NULL : method);
4962                 EMIT_NEW_PCONST (cfg, tramp_ins, trampoline);
4963         }
4964
4965         /* Set invoke_impl field */
4966         if (virtual) {
4967                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), tramp_ins->dreg);
4968         } else {
4969                 dreg = alloc_preg (cfg);
4970                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, invoke_impl));
4971                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), dreg);
4972
4973                 dreg = alloc_preg (cfg);
4974                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, method_ptr));
4975                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr), dreg);
4976         }
4977
4978         /* All the checks which are in mono_delegate_ctor () are done by the delegate trampoline */
4979
4980         return obj;
4981 }
4982
4983 static MonoInst*
4984 handle_array_new (MonoCompile *cfg, int rank, MonoInst **sp, unsigned char *ip)
4985 {
4986         MonoJitICallInfo *info;
4987
4988         /* Need to register the icall so it gets an icall wrapper */
4989         info = mono_get_array_new_va_icall (rank);
4990
4991         cfg->flags |= MONO_CFG_HAS_VARARGS;
4992
4993         /* mono_array_new_va () needs a vararg calling convention */
4994         cfg->disable_llvm = TRUE;
4995
4996         /* FIXME: This uses info->sig, but it should use the signature of the wrapper */
4997         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, sp);
4998 }
4999
5000 /*
5001  * handle_constrained_gsharedvt_call:
5002  *
5003  *   Handle constrained calls where the receiver is a gsharedvt type.
5004  * Return the instruction representing the call. Set the cfg exception on failure.
5005  */
5006 static MonoInst*
5007 handle_constrained_gsharedvt_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp, MonoClass *constrained_class,
5008                                                                    gboolean *ref_emit_widen)
5009 {
5010         MonoInst *ins = NULL;
5011         gboolean emit_widen = *ref_emit_widen;
5012
5013         /*
5014          * Constrained calls need to behave differently at runtime dependending on whenever the receiver is instantiated as ref type or as a vtype.
5015          * 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
5016          * pack the arguments into an array, and do the rest of the work in in an icall.
5017          */
5018         if (((cmethod->klass == mono_defaults.object_class) || (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) || (!cmethod->klass->valuetype && cmethod->klass->image != mono_defaults.corlib)) &&
5019                 (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 (fsig->ret)) &&
5020                 (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 (fsig->params [0]))))) {
5021                 MonoInst *args [16];
5022
5023                 /*
5024                  * This case handles calls to
5025                  * - object:ToString()/Equals()/GetHashCode(),
5026                  * - System.IComparable<T>:CompareTo()
5027                  * - System.IEquatable<T>:Equals ()
5028                  * plus some simple interface calls enough to support AsyncTaskMethodBuilder.
5029                  */
5030
5031                 args [0] = sp [0];
5032                 if (mono_method_check_context_used (cmethod))
5033                         args [1] = emit_get_rgctx_method (cfg, mono_method_check_context_used (cmethod), cmethod, MONO_RGCTX_INFO_METHOD);
5034                 else
5035                         EMIT_NEW_METHODCONST (cfg, args [1], cmethod);
5036                 args [2] = emit_get_rgctx_klass (cfg, mono_class_check_context_used (constrained_class), constrained_class, MONO_RGCTX_INFO_KLASS);
5037
5038                 /* !fsig->hasthis is for the wrapper for the Object.GetType () icall */
5039                 if (fsig->hasthis && fsig->param_count) {
5040                         /* Pass the arguments using a localloc-ed array using the format expected by runtime_invoke () */
5041                         MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
5042                         ins->dreg = alloc_preg (cfg);
5043                         ins->inst_imm = fsig->param_count * sizeof (mgreg_t);
5044                         MONO_ADD_INS (cfg->cbb, ins);
5045                         args [4] = ins;
5046
5047                         if (mini_is_gsharedvt_type (fsig->params [0])) {
5048                                 int addr_reg;
5049
5050                                 args [3] = emit_get_gsharedvt_info_klass (cfg, mono_class_from_mono_type (fsig->params [0]), MONO_RGCTX_INFO_CLASS_BOX_TYPE);
5051
5052                                 EMIT_NEW_VARLOADA_VREG (cfg, ins, sp [1]->dreg, fsig->params [0]);
5053                                 addr_reg = ins->dreg;
5054                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, addr_reg);
5055                         } else {
5056                                 EMIT_NEW_ICONST (cfg, args [3], 0);
5057                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, sp [1]->dreg);
5058                         }
5059                 } else {
5060                         EMIT_NEW_ICONST (cfg, args [3], 0);
5061                         EMIT_NEW_ICONST (cfg, args [4], 0);
5062                 }
5063                 ins = mono_emit_jit_icall (cfg, mono_gsharedvt_constrained_call, args);
5064                 emit_widen = FALSE;
5065
5066                 if (mini_is_gsharedvt_type (fsig->ret)) {
5067                         ins = handle_unbox_gsharedvt (cfg, mono_class_from_mono_type (fsig->ret), ins);
5068                 } else if (MONO_TYPE_IS_PRIMITIVE (fsig->ret) || MONO_TYPE_ISSTRUCT (fsig->ret)) {
5069                         MonoInst *add;
5070
5071                         /* Unbox */
5072                         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), ins->dreg, sizeof (MonoObject));
5073                         MONO_ADD_INS (cfg->cbb, add);
5074                         /* Load value */
5075                         NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, add->dreg, 0);
5076                         MONO_ADD_INS (cfg->cbb, ins);
5077                         /* ins represents the call result */
5078                 }
5079         } else {
5080                 GSHAREDVT_FAILURE (CEE_CALLVIRT);
5081         }
5082
5083         *ref_emit_widen = emit_widen;
5084
5085         return ins;
5086
5087  exception_exit:
5088         return NULL;
5089 }
5090
5091 static void
5092 mono_emit_load_got_addr (MonoCompile *cfg)
5093 {
5094         MonoInst *getaddr, *dummy_use;
5095
5096         if (!cfg->got_var || cfg->got_var_allocated)
5097                 return;
5098
5099         MONO_INST_NEW (cfg, getaddr, OP_LOAD_GOTADDR);
5100         getaddr->cil_code = cfg->header->code;
5101         getaddr->dreg = cfg->got_var->dreg;
5102
5103         /* Add it to the start of the first bblock */
5104         if (cfg->bb_entry->code) {
5105                 getaddr->next = cfg->bb_entry->code;
5106                 cfg->bb_entry->code = getaddr;
5107         }
5108         else
5109                 MONO_ADD_INS (cfg->bb_entry, getaddr);
5110
5111         cfg->got_var_allocated = TRUE;
5112
5113         /* 
5114          * Add a dummy use to keep the got_var alive, since real uses might
5115          * only be generated by the back ends.
5116          * Add it to end_bblock, so the variable's lifetime covers the whole
5117          * method.
5118          * It would be better to make the usage of the got var explicit in all
5119          * cases when the backend needs it (i.e. calls, throw etc.), so this
5120          * wouldn't be needed.
5121          */
5122         NEW_DUMMY_USE (cfg, dummy_use, cfg->got_var);
5123         MONO_ADD_INS (cfg->bb_exit, dummy_use);
5124 }
5125
5126 static int inline_limit;
5127 static gboolean inline_limit_inited;
5128
5129 static gboolean
5130 mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
5131 {
5132         MonoMethodHeaderSummary header;
5133         MonoVTable *vtable;
5134 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
5135         MonoMethodSignature *sig = mono_method_signature (method);
5136         int i;
5137 #endif
5138
5139         if (cfg->disable_inline)
5140                 return FALSE;
5141         if (cfg->gshared)
5142                 return FALSE;
5143
5144         if (cfg->inline_depth > 10)
5145                 return FALSE;
5146
5147 #ifdef MONO_ARCH_HAVE_LMF_OPS
5148         if (((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
5149                  (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) &&
5150             !MONO_TYPE_ISSTRUCT (signature->ret) && !mini_class_is_system_array (method->klass))
5151                 return TRUE;
5152 #endif
5153
5154
5155         if (!mono_method_get_header_summary (method, &header))
5156                 return FALSE;
5157
5158         /*runtime, icall and pinvoke are checked by summary call*/
5159         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
5160             (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
5161             (mono_class_is_marshalbyref (method->klass)) ||
5162             header.has_clauses)
5163                 return FALSE;
5164
5165         /* also consider num_locals? */
5166         /* Do the size check early to avoid creating vtables */
5167         if (!inline_limit_inited) {
5168                 if (g_getenv ("MONO_INLINELIMIT"))
5169                         inline_limit = atoi (g_getenv ("MONO_INLINELIMIT"));
5170                 else
5171                         inline_limit = INLINE_LENGTH_LIMIT;
5172                 inline_limit_inited = TRUE;
5173         }
5174         if (header.code_size >= inline_limit && !(method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))
5175                 return FALSE;
5176
5177         /*
5178          * if we can initialize the class of the method right away, we do,
5179          * otherwise we don't allow inlining if the class needs initialization,
5180          * since it would mean inserting a call to mono_runtime_class_init()
5181          * inside the inlined code
5182          */
5183         if (!(cfg->opt & MONO_OPT_SHARED)) {
5184                 /* The AggressiveInlining hint is a good excuse to force that cctor to run. */
5185                 if (method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING) {
5186                         vtable = mono_class_vtable (cfg->domain, method->klass);
5187                         if (!vtable)
5188                                 return FALSE;
5189                         if (!cfg->compile_aot)
5190                                 mono_runtime_class_init (vtable);
5191                 } else if (method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
5192                         if (cfg->run_cctors && method->klass->has_cctor) {
5193                                 /*FIXME it would easier and lazier to just use mono_class_try_get_vtable */
5194                                 if (!method->klass->runtime_info)
5195                                         /* No vtable created yet */
5196                                         return FALSE;
5197                                 vtable = mono_class_vtable (cfg->domain, method->klass);
5198                                 if (!vtable)
5199                                         return FALSE;
5200                                 /* This makes so that inline cannot trigger */
5201                                 /* .cctors: too many apps depend on them */
5202                                 /* running with a specific order... */
5203                                 if (! vtable->initialized)
5204                                         return FALSE;
5205                                 mono_runtime_class_init (vtable);
5206                         }
5207                 } else if (mono_class_needs_cctor_run (method->klass, NULL)) {
5208                         if (!method->klass->runtime_info)
5209                                 /* No vtable created yet */
5210                                 return FALSE;
5211                         vtable = mono_class_vtable (cfg->domain, method->klass);
5212                         if (!vtable)
5213                                 return FALSE;
5214                         if (!vtable->initialized)
5215                                 return FALSE;
5216                 }
5217         } else {
5218                 /* 
5219                  * If we're compiling for shared code
5220                  * the cctor will need to be run at aot method load time, for example,
5221                  * or at the end of the compilation of the inlining method.
5222                  */
5223                 if (mono_class_needs_cctor_run (method->klass, NULL) && !((method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)))
5224                         return FALSE;
5225         }
5226
5227 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
5228         if (mono_arch_is_soft_float ()) {
5229                 /* FIXME: */
5230                 if (sig->ret && sig->ret->type == MONO_TYPE_R4)
5231                         return FALSE;
5232                 for (i = 0; i < sig->param_count; ++i)
5233                         if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_R4)
5234                                 return FALSE;
5235         }
5236 #endif
5237
5238         if (g_list_find (cfg->dont_inline, method))
5239                 return FALSE;
5240
5241         return TRUE;
5242 }
5243
5244 static gboolean
5245 mini_field_access_needs_cctor_run (MonoCompile *cfg, MonoMethod *method, MonoClass *klass, MonoVTable *vtable)
5246 {
5247         if (!cfg->compile_aot) {
5248                 g_assert (vtable);
5249                 if (vtable->initialized)
5250                         return FALSE;
5251         }
5252
5253         if (klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
5254                 if (cfg->method == method)
5255                         return FALSE;
5256         }
5257
5258         if (!mono_class_needs_cctor_run (klass, method))
5259                 return FALSE;
5260
5261         if (! (method->flags & METHOD_ATTRIBUTE_STATIC) && (klass == method->klass))
5262                 /* The initialization is already done before the method is called */
5263                 return FALSE;
5264
5265         return TRUE;
5266 }
5267
5268 static MonoInst*
5269 mini_emit_ldelema_1_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index, gboolean bcheck)
5270 {
5271         MonoInst *ins;
5272         guint32 size;
5273         int mult_reg, add_reg, array_reg, index_reg, index2_reg;
5274         int context_used;
5275
5276         if (mini_is_gsharedvt_variable_klass (klass)) {
5277                 size = -1;
5278         } else {
5279                 mono_class_init (klass);
5280                 size = mono_class_array_element_size (klass);
5281         }
5282
5283         mult_reg = alloc_preg (cfg);
5284         array_reg = arr->dreg;
5285         index_reg = index->dreg;
5286
5287 #if SIZEOF_REGISTER == 8
5288         /* The array reg is 64 bits but the index reg is only 32 */
5289         if (COMPILE_LLVM (cfg)) {
5290                 /* Not needed */
5291                 index2_reg = index_reg;
5292         } else {
5293                 index2_reg = alloc_preg (cfg);
5294                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index2_reg, index_reg);
5295         }
5296 #else
5297         if (index->type == STACK_I8) {
5298                 index2_reg = alloc_preg (cfg);
5299                 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I4, index2_reg, index_reg);
5300         } else {
5301                 index2_reg = index_reg;
5302         }
5303 #endif
5304
5305         if (bcheck)
5306                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index2_reg);
5307
5308 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5309         if (size == 1 || size == 2 || size == 4 || size == 8) {
5310                 static const int fast_log2 [] = { 1, 0, 1, -1, 2, -1, -1, -1, 3 };
5311
5312                 EMIT_NEW_X86_LEA (cfg, ins, array_reg, index2_reg, fast_log2 [size], MONO_STRUCT_OFFSET (MonoArray, vector));
5313                 ins->klass = mono_class_get_element_class (klass);
5314                 ins->type = STACK_MP;
5315
5316                 return ins;
5317         }
5318 #endif          
5319
5320         add_reg = alloc_ireg_mp (cfg);
5321
5322         if (size == -1) {
5323                 MonoInst *rgctx_ins;
5324
5325                 /* gsharedvt */
5326                 g_assert (cfg->gshared);
5327                 context_used = mini_class_check_context_used (cfg, klass);
5328                 g_assert (context_used);
5329                 rgctx_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE);
5330                 MONO_EMIT_NEW_BIALU (cfg, OP_IMUL, mult_reg, index2_reg, rgctx_ins->dreg);
5331         } else {
5332                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MUL_IMM, mult_reg, index2_reg, size);
5333         }
5334         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, array_reg, mult_reg);
5335         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
5336         ins->klass = mono_class_get_element_class (klass);
5337         ins->type = STACK_MP;
5338         MONO_ADD_INS (cfg->cbb, ins);
5339
5340         return ins;
5341 }
5342
5343 #ifndef MONO_ARCH_EMULATE_MUL_DIV
5344 static MonoInst*
5345 mini_emit_ldelema_2_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index_ins1, MonoInst *index_ins2)
5346 {
5347         int bounds_reg = alloc_preg (cfg);
5348         int add_reg = alloc_ireg_mp (cfg);
5349         int mult_reg = alloc_preg (cfg);
5350         int mult2_reg = alloc_preg (cfg);
5351         int low1_reg = alloc_preg (cfg);
5352         int low2_reg = alloc_preg (cfg);
5353         int high1_reg = alloc_preg (cfg);
5354         int high2_reg = alloc_preg (cfg);
5355         int realidx1_reg = alloc_preg (cfg);
5356         int realidx2_reg = alloc_preg (cfg);
5357         int sum_reg = alloc_preg (cfg);
5358         int index1, index2, tmpreg;
5359         MonoInst *ins;
5360         guint32 size;
5361
5362         mono_class_init (klass);
5363         size = mono_class_array_element_size (klass);
5364
5365         index1 = index_ins1->dreg;
5366         index2 = index_ins2->dreg;
5367
5368 #if SIZEOF_REGISTER == 8
5369         /* The array reg is 64 bits but the index reg is only 32 */
5370         if (COMPILE_LLVM (cfg)) {
5371                 /* Not needed */
5372         } else {
5373                 tmpreg = alloc_preg (cfg);
5374                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index1);
5375                 index1 = tmpreg;
5376                 tmpreg = alloc_preg (cfg);
5377                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index2);
5378                 index2 = tmpreg;
5379         }
5380 #else
5381         // FIXME: Do we need to do something here for i8 indexes, like in ldelema_1_ins ?
5382         tmpreg = -1;
5383 #endif
5384
5385         /* range checking */
5386         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, 
5387                                        arr->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
5388
5389         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low1_reg, 
5390                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5391         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx1_reg, index1, low1_reg);
5392         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high1_reg, 
5393                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5394         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high1_reg, realidx1_reg);
5395         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
5396
5397         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low2_reg, 
5398                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5399         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx2_reg, index2, low2_reg);
5400         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high2_reg, 
5401                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5402         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high2_reg, realidx2_reg);
5403         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
5404
5405         MONO_EMIT_NEW_BIALU (cfg, OP_PMUL, mult_reg, high2_reg, realidx1_reg);
5406         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, mult_reg, realidx2_reg);
5407         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PMUL_IMM, mult2_reg, sum_reg, size);
5408         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult2_reg, arr->dreg);
5409         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
5410
5411         ins->type = STACK_MP;
5412         ins->klass = klass;
5413         MONO_ADD_INS (cfg->cbb, ins);
5414
5415         return ins;
5416 }
5417 #endif
5418
5419 static MonoInst*
5420 mini_emit_ldelema_ins (MonoCompile *cfg, MonoMethod *cmethod, MonoInst **sp, unsigned char *ip, gboolean is_set)
5421 {
5422         int rank;
5423         MonoInst *addr;
5424         MonoMethod *addr_method;
5425         int element_size;
5426         MonoClass *eclass = cmethod->klass->element_class;
5427
5428         rank = mono_method_signature (cmethod)->param_count - (is_set? 1: 0);
5429
5430         if (rank == 1)
5431                 return mini_emit_ldelema_1_ins (cfg, eclass, sp [0], sp [1], TRUE);
5432
5433 #ifndef MONO_ARCH_EMULATE_MUL_DIV
5434         /* emit_ldelema_2 depends on OP_LMUL */
5435         if (rank == 2 && (cfg->opt & MONO_OPT_INTRINS) && !mini_is_gsharedvt_variable_klass (eclass)) {
5436                 return mini_emit_ldelema_2_ins (cfg, eclass, sp [0], sp [1], sp [2]);
5437         }
5438 #endif
5439
5440         if (mini_is_gsharedvt_variable_klass (eclass))
5441                 element_size = 0;
5442         else
5443                 element_size = mono_class_array_element_size (eclass);
5444         addr_method = mono_marshal_get_array_address (rank, element_size);
5445         addr = mono_emit_method_call (cfg, addr_method, sp, NULL);
5446
5447         return addr;
5448 }
5449
5450 static MonoBreakPolicy
5451 always_insert_breakpoint (MonoMethod *method)
5452 {
5453         return MONO_BREAK_POLICY_ALWAYS;
5454 }
5455
5456 static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
5457
5458 /**
5459  * mono_set_break_policy:
5460  * policy_callback: the new callback function
5461  *
5462  * Allow embedders to decide wherther to actually obey breakpoint instructions
5463  * (both break IL instructions and Debugger.Break () method calls), for example
5464  * to not allow an app to be aborted by a perfectly valid IL opcode when executing
5465  * untrusted or semi-trusted code.
5466  *
5467  * @policy_callback will be called every time a break point instruction needs to
5468  * be inserted with the method argument being the method that calls Debugger.Break()
5469  * or has the IL break instruction. The callback should return #MONO_BREAK_POLICY_NEVER
5470  * if it wants the breakpoint to not be effective in the given method.
5471  * #MONO_BREAK_POLICY_ALWAYS is the default.
5472  */
5473 void
5474 mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
5475 {
5476         if (policy_callback)
5477                 break_policy_func = policy_callback;
5478         else
5479                 break_policy_func = always_insert_breakpoint;
5480 }
5481
5482 static gboolean
5483 should_insert_brekpoint (MonoMethod *method) {
5484         switch (break_policy_func (method)) {
5485         case MONO_BREAK_POLICY_ALWAYS:
5486                 return TRUE;
5487         case MONO_BREAK_POLICY_NEVER:
5488                 return FALSE;
5489         case MONO_BREAK_POLICY_ON_DBG:
5490                 g_warning ("mdb no longer supported");
5491                 return FALSE;
5492         default:
5493                 g_warning ("Incorrect value returned from break policy callback");
5494                 return FALSE;
5495         }
5496 }
5497
5498 /* optimize the simple GetGenericValueImpl/SetGenericValueImpl generic icalls */
5499 static MonoInst*
5500 emit_array_generic_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
5501 {
5502         MonoInst *addr, *store, *load;
5503         MonoClass *eklass = mono_class_from_mono_type (fsig->params [2]);
5504
5505         /* the bounds check is already done by the callers */
5506         addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
5507         if (is_set) {
5508                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, args [2]->dreg, 0);
5509                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, addr->dreg, 0, load->dreg);
5510                 if (mini_type_is_reference (fsig->params [2]))
5511                         emit_write_barrier (cfg, addr, load);
5512         } else {
5513                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, addr->dreg, 0);
5514                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, args [2]->dreg, 0, load->dreg);
5515         }
5516         return store;
5517 }
5518
5519
5520 static gboolean
5521 generic_class_is_reference_type (MonoCompile *cfg, MonoClass *klass)
5522 {
5523         return mini_type_is_reference (&klass->byval_arg);
5524 }
5525
5526 static MonoInst*
5527 emit_array_store (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, gboolean safety_checks)
5528 {
5529         if (safety_checks && generic_class_is_reference_type (cfg, klass) &&
5530                 !(sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL)) {
5531                 MonoClass *obj_array = mono_array_class_get_cached (mono_defaults.object_class, 1);
5532                 MonoMethod *helper = mono_marshal_get_virtual_stelemref (obj_array);
5533                 MonoInst *iargs [3];
5534
5535                 if (!helper->slot)
5536                         mono_class_setup_vtable (obj_array);
5537                 g_assert (helper->slot);
5538
5539                 if (sp [0]->type != STACK_OBJ)
5540                         return NULL;
5541                 if (sp [2]->type != STACK_OBJ)
5542                         return NULL;
5543
5544                 iargs [2] = sp [2];
5545                 iargs [1] = sp [1];
5546                 iargs [0] = sp [0];
5547
5548                 return mono_emit_method_call (cfg, helper, iargs, sp [0]);
5549         } else {
5550                 MonoInst *ins;
5551
5552                 if (mini_is_gsharedvt_variable_klass (klass)) {
5553                         MonoInst *addr;
5554
5555                         // FIXME-VT: OP_ICONST optimization
5556                         addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
5557                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5558                         ins->opcode = OP_STOREV_MEMBASE;
5559                 } else if (sp [1]->opcode == OP_ICONST) {
5560                         int array_reg = sp [0]->dreg;
5561                         int index_reg = sp [1]->dreg;
5562                         int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
5563
5564                         if (safety_checks)
5565                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
5566                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset, sp [2]->dreg);
5567                 } else {
5568                         MonoInst *addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], safety_checks);
5569                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5570                         if (generic_class_is_reference_type (cfg, klass))
5571                                 emit_write_barrier (cfg, addr, sp [2]);
5572                 }
5573                 return ins;
5574         }
5575 }
5576
5577 static MonoInst*
5578 emit_array_unsafe_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
5579 {
5580         MonoClass *eklass;
5581         
5582         if (is_set)
5583                 eklass = mono_class_from_mono_type (fsig->params [2]);
5584         else
5585                 eklass = mono_class_from_mono_type (fsig->ret);
5586
5587         if (is_set) {
5588                 return emit_array_store (cfg, eklass, args, FALSE);
5589         } else {
5590                 MonoInst *ins, *addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
5591                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &eklass->byval_arg, addr->dreg, 0);
5592                 return ins;
5593         }
5594 }
5595
5596 static gboolean
5597 is_unsafe_mov_compatible (MonoCompile *cfg, MonoClass *param_klass, MonoClass *return_klass)
5598 {
5599         uint32_t align;
5600
5601         param_klass = mono_class_from_mono_type (mini_get_underlying_type (&param_klass->byval_arg));
5602
5603         //Only allow for valuetypes
5604         if (!param_klass->valuetype || !return_klass->valuetype)
5605                 return FALSE;
5606
5607         //That are blitable
5608         if (param_klass->has_references || return_klass->has_references)
5609                 return FALSE;
5610
5611         /* Avoid mixing structs and primitive types/enums, they need to be handled differently in the JIT */
5612         if ((MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && !MONO_TYPE_ISSTRUCT (&return_klass->byval_arg)) ||
5613                 (!MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && MONO_TYPE_ISSTRUCT (&return_klass->byval_arg)))
5614                 return FALSE;
5615
5616         if (param_klass->byval_arg.type == MONO_TYPE_R4 || param_klass->byval_arg.type == MONO_TYPE_R8 ||
5617                 return_klass->byval_arg.type == MONO_TYPE_R4 || return_klass->byval_arg.type == MONO_TYPE_R8)
5618                 return FALSE;
5619
5620         //And have the same size
5621         if (mono_class_value_size (param_klass, &align) != mono_class_value_size (return_klass, &align))
5622                 return FALSE;
5623         return TRUE;
5624 }
5625
5626 static MonoInst*
5627 emit_array_unsafe_mov (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args)
5628 {
5629         MonoClass *param_klass = mono_class_from_mono_type (fsig->params [0]);
5630         MonoClass *return_klass = mono_class_from_mono_type (fsig->ret);
5631
5632         //Valuetypes that are semantically equivalent
5633         if (is_unsafe_mov_compatible (cfg, param_klass, return_klass))
5634                 return args [0];
5635
5636         //Arrays of valuetypes that are semantically equivalent
5637         if (param_klass->rank == 1 && return_klass->rank == 1 && is_unsafe_mov_compatible (cfg, param_klass->element_class, return_klass->element_class))
5638                 return args [0];
5639
5640         return NULL;
5641 }
5642
5643 static MonoInst*
5644 mini_emit_inst_for_ctor (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5645 {
5646 #ifdef MONO_ARCH_SIMD_INTRINSICS
5647         MonoInst *ins = NULL;
5648
5649         if (cfg->opt & MONO_OPT_SIMD) {
5650                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
5651                 if (ins)
5652                         return ins;
5653         }
5654 #endif
5655
5656         return mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
5657 }
5658
5659 static MonoInst*
5660 emit_memory_barrier (MonoCompile *cfg, int kind)
5661 {
5662         MonoInst *ins = NULL;
5663         MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
5664         MONO_ADD_INS (cfg->cbb, ins);
5665         ins->backend.memory_barrier_kind = kind;
5666
5667         return ins;
5668 }
5669
5670 static MonoInst*
5671 llvm_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5672 {
5673         MonoInst *ins = NULL;
5674         int opcode = 0;
5675
5676         /* The LLVM backend supports these intrinsics */
5677         if (cmethod->klass == mono_defaults.math_class) {
5678                 if (strcmp (cmethod->name, "Sin") == 0) {
5679                         opcode = OP_SIN;
5680                 } else if (strcmp (cmethod->name, "Cos") == 0) {
5681                         opcode = OP_COS;
5682                 } else if (strcmp (cmethod->name, "Sqrt") == 0) {
5683                         opcode = OP_SQRT;
5684                 } else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8) {
5685                         opcode = OP_ABS;
5686                 }
5687
5688                 if (opcode && fsig->param_count == 1) {
5689                         MONO_INST_NEW (cfg, ins, opcode);
5690                         ins->type = STACK_R8;
5691                         ins->dreg = mono_alloc_freg (cfg);
5692                         ins->sreg1 = args [0]->dreg;
5693                         MONO_ADD_INS (cfg->cbb, ins);
5694                 }
5695
5696                 opcode = 0;
5697                 if (cfg->opt & MONO_OPT_CMOV) {
5698                         if (strcmp (cmethod->name, "Min") == 0) {
5699                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5700                                         opcode = OP_IMIN;
5701                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5702                                         opcode = OP_IMIN_UN;
5703                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5704                                         opcode = OP_LMIN;
5705                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5706                                         opcode = OP_LMIN_UN;
5707                         } else if (strcmp (cmethod->name, "Max") == 0) {
5708                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5709                                         opcode = OP_IMAX;
5710                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5711                                         opcode = OP_IMAX_UN;
5712                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5713                                         opcode = OP_LMAX;
5714                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5715                                         opcode = OP_LMAX_UN;
5716                         }
5717                 }
5718
5719                 if (opcode && fsig->param_count == 2) {
5720                         MONO_INST_NEW (cfg, ins, opcode);
5721                         ins->type = fsig->params [0]->type == MONO_TYPE_I4 ? STACK_I4 : STACK_I8;
5722                         ins->dreg = mono_alloc_ireg (cfg);
5723                         ins->sreg1 = args [0]->dreg;
5724                         ins->sreg2 = args [1]->dreg;
5725                         MONO_ADD_INS (cfg->cbb, ins);
5726                 }
5727         }
5728
5729         return ins;
5730 }
5731
5732 static MonoInst*
5733 mini_emit_inst_for_sharable_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5734 {
5735         if (cmethod->klass == mono_defaults.array_class) {
5736                 if (strcmp (cmethod->name, "UnsafeStore") == 0)
5737                         return emit_array_unsafe_access (cfg, fsig, args, TRUE);
5738                 else if (strcmp (cmethod->name, "UnsafeLoad") == 0)
5739                         return emit_array_unsafe_access (cfg, fsig, args, FALSE);
5740                 else if (strcmp (cmethod->name, "UnsafeMov") == 0)
5741                         return emit_array_unsafe_mov (cfg, fsig, args);
5742         }
5743
5744         return NULL;
5745 }
5746
5747 static MonoInst*
5748 mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5749 {
5750         MonoInst *ins = NULL;
5751
5752         static MonoClass *runtime_helpers_class = NULL;
5753         if (! runtime_helpers_class)
5754                 runtime_helpers_class = mono_class_from_name (mono_defaults.corlib,
5755                         "System.Runtime.CompilerServices", "RuntimeHelpers");
5756
5757         if (cmethod->klass == mono_defaults.string_class) {
5758                 if (strcmp (cmethod->name, "get_Chars") == 0 && fsig->param_count + fsig->hasthis == 2) {
5759                         int dreg = alloc_ireg (cfg);
5760                         int index_reg = alloc_preg (cfg);
5761                         int add_reg = alloc_preg (cfg);
5762
5763 #if SIZEOF_REGISTER == 8
5764                         /* The array reg is 64 bits but the index reg is only 32 */
5765                         MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index_reg, args [1]->dreg);
5766 #else
5767                         index_reg = args [1]->dreg;
5768 #endif  
5769                         MONO_EMIT_BOUNDS_CHECK (cfg, args [0]->dreg, MonoString, length, index_reg);
5770
5771 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5772                         EMIT_NEW_X86_LEA (cfg, ins, args [0]->dreg, index_reg, 1, MONO_STRUCT_OFFSET (MonoString, chars));
5773                         add_reg = ins->dreg;
5774                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5775                                                                    add_reg, 0);
5776 #else
5777                         int mult_reg = alloc_preg (cfg);
5778                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, index_reg, 1);
5779                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
5780                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5781                                                                    add_reg, MONO_STRUCT_OFFSET (MonoString, chars));
5782 #endif
5783                         type_from_op (cfg, ins, NULL, NULL);
5784                         return ins;
5785                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count + fsig->hasthis == 1) {
5786                         int dreg = alloc_ireg (cfg);
5787                         /* Decompose later to allow more optimizations */
5788                         EMIT_NEW_UNALU (cfg, ins, OP_STRLEN, dreg, args [0]->dreg);
5789                         ins->type = STACK_I4;
5790                         ins->flags |= MONO_INST_FAULT;
5791                         cfg->cbb->has_array_access = TRUE;
5792                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
5793
5794                         return ins;
5795                 } else 
5796                         return NULL;
5797         } else if (cmethod->klass == mono_defaults.object_class) {
5798
5799                 if (strcmp (cmethod->name, "GetType") == 0 && fsig->param_count + fsig->hasthis == 1) {
5800                         int dreg = alloc_ireg_ref (cfg);
5801                         int vt_reg = alloc_preg (cfg);
5802                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vt_reg, args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
5803                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, vt_reg, MONO_STRUCT_OFFSET (MonoVTable, type));
5804                         type_from_op (cfg, ins, NULL, NULL);
5805
5806                         return ins;
5807 #if !defined(MONO_ARCH_EMULATE_MUL_DIV)
5808                 } else if (strcmp (cmethod->name, "InternalGetHashCode") == 0 && fsig->param_count == 1 && !mono_gc_is_moving ()) {
5809                         int dreg = alloc_ireg (cfg);
5810                         int t1 = alloc_ireg (cfg);
5811         
5812                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, t1, args [0]->dreg, 3);
5813                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_MUL_IMM, dreg, t1, 2654435761u);
5814                         ins->type = STACK_I4;
5815
5816                         return ins;
5817 #endif
5818                 } else if (strcmp (cmethod->name, ".ctor") == 0 && fsig->param_count == 0) {
5819                         MONO_INST_NEW (cfg, ins, OP_NOP);
5820                         MONO_ADD_INS (cfg->cbb, ins);
5821                         return ins;
5822                 } else
5823                         return NULL;
5824         } else if (cmethod->klass == mono_defaults.array_class) {
5825                 if (strcmp (cmethod->name, "GetGenericValueImpl") == 0 && fsig->param_count + fsig->hasthis == 3 && !cfg->gsharedvt)
5826                         return emit_array_generic_access (cfg, fsig, args, FALSE);
5827                 else if (strcmp (cmethod->name, "SetGenericValueImpl") == 0 && fsig->param_count + fsig->hasthis == 3 && !cfg->gsharedvt)
5828                         return emit_array_generic_access (cfg, fsig, args, TRUE);
5829
5830 #ifndef MONO_BIG_ARRAYS
5831                 /*
5832                  * This is an inline version of GetLength/GetLowerBound(0) used frequently in
5833                  * Array methods.
5834                  */
5835                 else if (((strcmp (cmethod->name, "GetLength") == 0 && fsig->param_count + fsig->hasthis == 2) ||
5836                          (strcmp (cmethod->name, "GetLowerBound") == 0 && fsig->param_count + fsig->hasthis == 2)) &&
5837                          args [1]->opcode == OP_ICONST && args [1]->inst_c0 == 0) {
5838                         int dreg = alloc_ireg (cfg);
5839                         int bounds_reg = alloc_ireg_mp (cfg);
5840                         MonoBasicBlock *end_bb, *szarray_bb;
5841                         gboolean get_length = strcmp (cmethod->name, "GetLength") == 0;
5842
5843                         NEW_BBLOCK (cfg, end_bb);
5844                         NEW_BBLOCK (cfg, szarray_bb);
5845
5846                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOAD_MEMBASE, bounds_reg,
5847                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
5848                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
5849                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, szarray_bb);
5850                         /* Non-szarray case */
5851                         if (get_length)
5852                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5853                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5854                         else
5855                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5856                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5857                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
5858                         MONO_START_BB (cfg, szarray_bb);
5859                         /* Szarray case */
5860                         if (get_length)
5861                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5862                                                                            args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
5863                         else
5864                                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
5865                         MONO_START_BB (cfg, end_bb);
5866
5867                         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, dreg, dreg);
5868                         ins->type = STACK_I4;
5869                         
5870                         return ins;
5871                 }
5872 #endif
5873
5874                 if (cmethod->name [0] != 'g')
5875                         return NULL;
5876
5877                 if (strcmp (cmethod->name, "get_Rank") == 0 && fsig->param_count + fsig->hasthis == 1) {
5878                         int dreg = alloc_ireg (cfg);
5879                         int vtable_reg = alloc_preg (cfg);
5880                         MONO_EMIT_NEW_LOAD_MEMBASE_OP_FAULT (cfg, OP_LOAD_MEMBASE, vtable_reg, 
5881                                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
5882                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU1_MEMBASE, dreg,
5883                                                                    vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
5884                         type_from_op (cfg, ins, NULL, NULL);
5885
5886                         return ins;
5887                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count + fsig->hasthis == 1) {
5888                         int dreg = alloc_ireg (cfg);
5889
5890                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOADI4_MEMBASE, dreg, 
5891                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
5892                         type_from_op (cfg, ins, NULL, NULL);
5893
5894                         return ins;
5895                 } else
5896                         return NULL;
5897         } else if (cmethod->klass == runtime_helpers_class) {
5898
5899                 if (strcmp (cmethod->name, "get_OffsetToStringData") == 0 && fsig->param_count == 0) {
5900                         EMIT_NEW_ICONST (cfg, ins, MONO_STRUCT_OFFSET (MonoString, chars));
5901                         return ins;
5902                 } else
5903                         return NULL;
5904         } else if (cmethod->klass == mono_defaults.thread_class) {
5905                 if (strcmp (cmethod->name, "SpinWait_nop") == 0 && fsig->param_count == 0) {
5906                         MONO_INST_NEW (cfg, ins, OP_RELAXED_NOP);
5907                         MONO_ADD_INS (cfg->cbb, ins);
5908                         return ins;
5909                 } else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0) {
5910                         return emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
5911                 } else if (!strcmp (cmethod->name, "VolatileRead") && fsig->param_count == 1) {
5912                         guint32 opcode = 0;
5913                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
5914
5915                         if (fsig->params [0]->type == MONO_TYPE_I1)
5916                                 opcode = OP_LOADI1_MEMBASE;
5917                         else if (fsig->params [0]->type == MONO_TYPE_U1)
5918                                 opcode = OP_LOADU1_MEMBASE;
5919                         else if (fsig->params [0]->type == MONO_TYPE_I2)
5920                                 opcode = OP_LOADI2_MEMBASE;
5921                         else if (fsig->params [0]->type == MONO_TYPE_U2)
5922                                 opcode = OP_LOADU2_MEMBASE;
5923                         else if (fsig->params [0]->type == MONO_TYPE_I4)
5924                                 opcode = OP_LOADI4_MEMBASE;
5925                         else if (fsig->params [0]->type == MONO_TYPE_U4)
5926                                 opcode = OP_LOADU4_MEMBASE;
5927                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
5928                                 opcode = OP_LOADI8_MEMBASE;
5929                         else if (fsig->params [0]->type == MONO_TYPE_R4)
5930                                 opcode = OP_LOADR4_MEMBASE;
5931                         else if (fsig->params [0]->type == MONO_TYPE_R8)
5932                                 opcode = OP_LOADR8_MEMBASE;
5933                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
5934                                 opcode = OP_LOAD_MEMBASE;
5935
5936                         if (opcode) {
5937                                 MONO_INST_NEW (cfg, ins, opcode);
5938                                 ins->inst_basereg = args [0]->dreg;
5939                                 ins->inst_offset = 0;
5940                                 MONO_ADD_INS (cfg->cbb, ins);
5941
5942                                 switch (fsig->params [0]->type) {
5943                                 case MONO_TYPE_I1:
5944                                 case MONO_TYPE_U1:
5945                                 case MONO_TYPE_I2:
5946                                 case MONO_TYPE_U2:
5947                                 case MONO_TYPE_I4:
5948                                 case MONO_TYPE_U4:
5949                                         ins->dreg = mono_alloc_ireg (cfg);
5950                                         ins->type = STACK_I4;
5951                                         break;
5952                                 case MONO_TYPE_I8:
5953                                 case MONO_TYPE_U8:
5954                                         ins->dreg = mono_alloc_lreg (cfg);
5955                                         ins->type = STACK_I8;
5956                                         break;
5957                                 case MONO_TYPE_I:
5958                                 case MONO_TYPE_U:
5959                                         ins->dreg = mono_alloc_ireg (cfg);
5960 #if SIZEOF_REGISTER == 8
5961                                         ins->type = STACK_I8;
5962 #else
5963                                         ins->type = STACK_I4;
5964 #endif
5965                                         break;
5966                                 case MONO_TYPE_R4:
5967                                 case MONO_TYPE_R8:
5968                                         ins->dreg = mono_alloc_freg (cfg);
5969                                         ins->type = STACK_R8;
5970                                         break;
5971                                 default:
5972                                         g_assert (mini_type_is_reference (fsig->params [0]));
5973                                         ins->dreg = mono_alloc_ireg_ref (cfg);
5974                                         ins->type = STACK_OBJ;
5975                                         break;
5976                                 }
5977
5978                                 if (opcode == OP_LOADI8_MEMBASE)
5979                                         ins = mono_decompose_opcode (cfg, ins);
5980
5981                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
5982
5983                                 return ins;
5984                         }
5985                 } else if (!strcmp (cmethod->name, "VolatileWrite") && fsig->param_count == 2) {
5986                         guint32 opcode = 0;
5987                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
5988
5989                         if (fsig->params [0]->type == MONO_TYPE_I1 || fsig->params [0]->type == MONO_TYPE_U1)
5990                                 opcode = OP_STOREI1_MEMBASE_REG;
5991                         else if (fsig->params [0]->type == MONO_TYPE_I2 || fsig->params [0]->type == MONO_TYPE_U2)
5992                                 opcode = OP_STOREI2_MEMBASE_REG;
5993                         else if (fsig->params [0]->type == MONO_TYPE_I4 || fsig->params [0]->type == MONO_TYPE_U4)
5994                                 opcode = OP_STOREI4_MEMBASE_REG;
5995                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
5996                                 opcode = OP_STOREI8_MEMBASE_REG;
5997                         else if (fsig->params [0]->type == MONO_TYPE_R4)
5998                                 opcode = OP_STORER4_MEMBASE_REG;
5999                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6000                                 opcode = OP_STORER8_MEMBASE_REG;
6001                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
6002                                 opcode = OP_STORE_MEMBASE_REG;
6003
6004                         if (opcode) {
6005                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
6006
6007                                 MONO_INST_NEW (cfg, ins, opcode);
6008                                 ins->sreg1 = args [1]->dreg;
6009                                 ins->inst_destbasereg = args [0]->dreg;
6010                                 ins->inst_offset = 0;
6011                                 MONO_ADD_INS (cfg->cbb, ins);
6012
6013                                 if (opcode == OP_STOREI8_MEMBASE_REG)
6014                                         ins = mono_decompose_opcode (cfg, ins);
6015
6016                                 return ins;
6017                         }
6018                 }
6019         } else if (cmethod->klass->image == mono_defaults.corlib &&
6020                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
6021                            (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
6022                 ins = NULL;
6023
6024 #if SIZEOF_REGISTER == 8
6025                 if (strcmp (cmethod->name, "Read") == 0 && fsig->param_count == 1 && (fsig->params [0]->type == MONO_TYPE_I8)) {
6026                         if (mono_arch_opcode_supported (OP_ATOMIC_LOAD_I8)) {
6027                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_LOAD_I8);
6028                                 ins->dreg = mono_alloc_preg (cfg);
6029                                 ins->sreg1 = args [0]->dreg;
6030                                 ins->type = STACK_I8;
6031                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_SEQ;
6032                                 MONO_ADD_INS (cfg->cbb, ins);
6033                         } else {
6034                                 MonoInst *load_ins;
6035
6036                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6037
6038                                 /* 64 bit reads are already atomic */
6039                                 MONO_INST_NEW (cfg, load_ins, OP_LOADI8_MEMBASE);
6040                                 load_ins->dreg = mono_alloc_preg (cfg);
6041                                 load_ins->inst_basereg = args [0]->dreg;
6042                                 load_ins->inst_offset = 0;
6043                                 load_ins->type = STACK_I8;
6044                                 MONO_ADD_INS (cfg->cbb, load_ins);
6045
6046                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6047
6048                                 ins = load_ins;
6049                         }
6050                 }
6051 #endif
6052
6053                 if (strcmp (cmethod->name, "Increment") == 0 && fsig->param_count == 1) {
6054                         MonoInst *ins_iconst;
6055                         guint32 opcode = 0;
6056
6057                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6058                                 opcode = OP_ATOMIC_ADD_I4;
6059                                 cfg->has_atomic_add_i4 = TRUE;
6060                         }
6061 #if SIZEOF_REGISTER == 8
6062                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6063                                 opcode = OP_ATOMIC_ADD_I8;
6064 #endif
6065                         if (opcode) {
6066                                 if (!mono_arch_opcode_supported (opcode))
6067                                         return NULL;
6068                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
6069                                 ins_iconst->inst_c0 = 1;
6070                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
6071                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
6072
6073                                 MONO_INST_NEW (cfg, ins, opcode);
6074                                 ins->dreg = mono_alloc_ireg (cfg);
6075                                 ins->inst_basereg = args [0]->dreg;
6076                                 ins->inst_offset = 0;
6077                                 ins->sreg2 = ins_iconst->dreg;
6078                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6079                                 MONO_ADD_INS (cfg->cbb, ins);
6080                         }
6081                 } else if (strcmp (cmethod->name, "Decrement") == 0 && fsig->param_count == 1) {
6082                         MonoInst *ins_iconst;
6083                         guint32 opcode = 0;
6084
6085                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6086                                 opcode = OP_ATOMIC_ADD_I4;
6087                                 cfg->has_atomic_add_i4 = TRUE;
6088                         }
6089 #if SIZEOF_REGISTER == 8
6090                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6091                                 opcode = OP_ATOMIC_ADD_I8;
6092 #endif
6093                         if (opcode) {
6094                                 if (!mono_arch_opcode_supported (opcode))
6095                                         return NULL;
6096                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
6097                                 ins_iconst->inst_c0 = -1;
6098                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
6099                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
6100
6101                                 MONO_INST_NEW (cfg, ins, opcode);
6102                                 ins->dreg = mono_alloc_ireg (cfg);
6103                                 ins->inst_basereg = args [0]->dreg;
6104                                 ins->inst_offset = 0;
6105                                 ins->sreg2 = ins_iconst->dreg;
6106                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6107                                 MONO_ADD_INS (cfg->cbb, ins);
6108                         }
6109                 } else if (strcmp (cmethod->name, "Add") == 0 && fsig->param_count == 2) {
6110                         guint32 opcode = 0;
6111
6112                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6113                                 opcode = OP_ATOMIC_ADD_I4;
6114                                 cfg->has_atomic_add_i4 = TRUE;
6115                         }
6116 #if SIZEOF_REGISTER == 8
6117                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6118                                 opcode = OP_ATOMIC_ADD_I8;
6119 #endif
6120                         if (opcode) {
6121                                 if (!mono_arch_opcode_supported (opcode))
6122                                         return NULL;
6123                                 MONO_INST_NEW (cfg, ins, opcode);
6124                                 ins->dreg = mono_alloc_ireg (cfg);
6125                                 ins->inst_basereg = args [0]->dreg;
6126                                 ins->inst_offset = 0;
6127                                 ins->sreg2 = args [1]->dreg;
6128                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6129                                 MONO_ADD_INS (cfg->cbb, ins);
6130                         }
6131                 }
6132                 else if (strcmp (cmethod->name, "Exchange") == 0 && fsig->param_count == 2) {
6133                         MonoInst *f2i = NULL, *i2f;
6134                         guint32 opcode, f2i_opcode, i2f_opcode;
6135                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6136                         gboolean is_float = fsig->params [0]->type == MONO_TYPE_R4 || fsig->params [0]->type == MONO_TYPE_R8;
6137
6138                         if (fsig->params [0]->type == MONO_TYPE_I4 ||
6139                             fsig->params [0]->type == MONO_TYPE_R4) {
6140                                 opcode = OP_ATOMIC_EXCHANGE_I4;
6141                                 f2i_opcode = OP_MOVE_F_TO_I4;
6142                                 i2f_opcode = OP_MOVE_I4_TO_F;
6143                                 cfg->has_atomic_exchange_i4 = TRUE;
6144                         }
6145 #if SIZEOF_REGISTER == 8
6146                         else if (is_ref ||
6147                                  fsig->params [0]->type == MONO_TYPE_I8 ||
6148                                  fsig->params [0]->type == MONO_TYPE_R8 ||
6149                                  fsig->params [0]->type == MONO_TYPE_I) {
6150                                 opcode = OP_ATOMIC_EXCHANGE_I8;
6151                                 f2i_opcode = OP_MOVE_F_TO_I8;
6152                                 i2f_opcode = OP_MOVE_I8_TO_F;
6153                         }
6154 #else
6155                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I) {
6156                                 opcode = OP_ATOMIC_EXCHANGE_I4;
6157                                 cfg->has_atomic_exchange_i4 = TRUE;
6158                         }
6159 #endif
6160                         else
6161                                 return NULL;
6162
6163                         if (!mono_arch_opcode_supported (opcode))
6164                                 return NULL;
6165
6166                         if (is_float) {
6167                                 /* TODO: Decompose these opcodes instead of bailing here. */
6168                                 if (COMPILE_SOFT_FLOAT (cfg))
6169                                         return NULL;
6170
6171                                 MONO_INST_NEW (cfg, f2i, f2i_opcode);
6172                                 f2i->dreg = mono_alloc_ireg (cfg);
6173                                 f2i->sreg1 = args [1]->dreg;
6174                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6175                                         f2i->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6176                                 MONO_ADD_INS (cfg->cbb, f2i);
6177                         }
6178
6179                         MONO_INST_NEW (cfg, ins, opcode);
6180                         ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : mono_alloc_ireg (cfg);
6181                         ins->inst_basereg = args [0]->dreg;
6182                         ins->inst_offset = 0;
6183                         ins->sreg2 = is_float ? f2i->dreg : args [1]->dreg;
6184                         MONO_ADD_INS (cfg->cbb, ins);
6185
6186                         switch (fsig->params [0]->type) {
6187                         case MONO_TYPE_I4:
6188                                 ins->type = STACK_I4;
6189                                 break;
6190                         case MONO_TYPE_I8:
6191                                 ins->type = STACK_I8;
6192                                 break;
6193                         case MONO_TYPE_I:
6194 #if SIZEOF_REGISTER == 8
6195                                 ins->type = STACK_I8;
6196 #else
6197                                 ins->type = STACK_I4;
6198 #endif
6199                                 break;
6200                         case MONO_TYPE_R4:
6201                         case MONO_TYPE_R8:
6202                                 ins->type = STACK_R8;
6203                                 break;
6204                         default:
6205                                 g_assert (mini_type_is_reference (fsig->params [0]));
6206                                 ins->type = STACK_OBJ;
6207                                 break;
6208                         }
6209
6210                         if (is_float) {
6211                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
6212                                 i2f->dreg = mono_alloc_freg (cfg);
6213                                 i2f->sreg1 = ins->dreg;
6214                                 i2f->type = STACK_R8;
6215                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
6216                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6217                                 MONO_ADD_INS (cfg->cbb, i2f);
6218
6219                                 ins = i2f;
6220                         }
6221
6222                         if (cfg->gen_write_barriers && is_ref)
6223                                 emit_write_barrier (cfg, args [0], args [1]);
6224                 }
6225                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 3) {
6226                         MonoInst *f2i_new = NULL, *f2i_cmp = NULL, *i2f;
6227                         guint32 opcode, f2i_opcode, i2f_opcode;
6228                         gboolean is_ref = mini_type_is_reference (fsig->params [1]);
6229                         gboolean is_float = fsig->params [1]->type == MONO_TYPE_R4 || fsig->params [1]->type == MONO_TYPE_R8;
6230
6231                         if (fsig->params [1]->type == MONO_TYPE_I4 ||
6232                             fsig->params [1]->type == MONO_TYPE_R4) {
6233                                 opcode = OP_ATOMIC_CAS_I4;
6234                                 f2i_opcode = OP_MOVE_F_TO_I4;
6235                                 i2f_opcode = OP_MOVE_I4_TO_F;
6236                                 cfg->has_atomic_cas_i4 = TRUE;
6237                         }
6238 #if SIZEOF_REGISTER == 8
6239                         else if (is_ref ||
6240                                  fsig->params [1]->type == MONO_TYPE_I8 ||
6241                                  fsig->params [1]->type == MONO_TYPE_R8 ||
6242                                  fsig->params [1]->type == MONO_TYPE_I) {
6243                                 opcode = OP_ATOMIC_CAS_I8;
6244                                 f2i_opcode = OP_MOVE_F_TO_I8;
6245                                 i2f_opcode = OP_MOVE_I8_TO_F;
6246                         }
6247 #else
6248                         else if (is_ref || fsig->params [1]->type == MONO_TYPE_I) {
6249                                 opcode = OP_ATOMIC_CAS_I4;
6250                                 cfg->has_atomic_cas_i4 = TRUE;
6251                         }
6252 #endif
6253                         else
6254                                 return NULL;
6255
6256                         if (!mono_arch_opcode_supported (opcode))
6257                                 return NULL;
6258
6259                         if (is_float) {
6260                                 /* TODO: Decompose these opcodes instead of bailing here. */
6261                                 if (COMPILE_SOFT_FLOAT (cfg))
6262                                         return NULL;
6263
6264                                 MONO_INST_NEW (cfg, f2i_new, f2i_opcode);
6265                                 f2i_new->dreg = mono_alloc_ireg (cfg);
6266                                 f2i_new->sreg1 = args [1]->dreg;
6267                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6268                                         f2i_new->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6269                                 MONO_ADD_INS (cfg->cbb, f2i_new);
6270
6271                                 MONO_INST_NEW (cfg, f2i_cmp, f2i_opcode);
6272                                 f2i_cmp->dreg = mono_alloc_ireg (cfg);
6273                                 f2i_cmp->sreg1 = args [2]->dreg;
6274                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6275                                         f2i_cmp->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6276                                 MONO_ADD_INS (cfg->cbb, f2i_cmp);
6277                         }
6278
6279                         MONO_INST_NEW (cfg, ins, opcode);
6280                         ins->dreg = is_ref ? alloc_ireg_ref (cfg) : alloc_ireg (cfg);
6281                         ins->sreg1 = args [0]->dreg;
6282                         ins->sreg2 = is_float ? f2i_new->dreg : args [1]->dreg;
6283                         ins->sreg3 = is_float ? f2i_cmp->dreg : args [2]->dreg;
6284                         MONO_ADD_INS (cfg->cbb, ins);
6285
6286                         switch (fsig->params [1]->type) {
6287                         case MONO_TYPE_I4:
6288                                 ins->type = STACK_I4;
6289                                 break;
6290                         case MONO_TYPE_I8:
6291                                 ins->type = STACK_I8;
6292                                 break;
6293                         case MONO_TYPE_I:
6294 #if SIZEOF_REGISTER == 8
6295                                 ins->type = STACK_I8;
6296 #else
6297                                 ins->type = STACK_I4;
6298 #endif
6299                                 break;
6300                         case MONO_TYPE_R4:
6301                                 ins->type = cfg->r4_stack_type;
6302                                 break;
6303                         case MONO_TYPE_R8:
6304                                 ins->type = STACK_R8;
6305                                 break;
6306                         default:
6307                                 g_assert (mini_type_is_reference (fsig->params [1]));
6308                                 ins->type = STACK_OBJ;
6309                                 break;
6310                         }
6311
6312                         if (is_float) {
6313                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
6314                                 i2f->dreg = mono_alloc_freg (cfg);
6315                                 i2f->sreg1 = ins->dreg;
6316                                 i2f->type = STACK_R8;
6317                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
6318                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6319                                 MONO_ADD_INS (cfg->cbb, i2f);
6320
6321                                 ins = i2f;
6322                         }
6323
6324                         if (cfg->gen_write_barriers && is_ref)
6325                                 emit_write_barrier (cfg, args [0], args [1]);
6326                 }
6327                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 4 &&
6328                          fsig->params [1]->type == MONO_TYPE_I4) {
6329                         MonoInst *cmp, *ceq;
6330
6331                         if (!mono_arch_opcode_supported (OP_ATOMIC_CAS_I4))
6332                                 return NULL;
6333
6334                         /* int32 r = CAS (location, value, comparand); */
6335                         MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I4);
6336                         ins->dreg = alloc_ireg (cfg);
6337                         ins->sreg1 = args [0]->dreg;
6338                         ins->sreg2 = args [1]->dreg;
6339                         ins->sreg3 = args [2]->dreg;
6340                         ins->type = STACK_I4;
6341                         MONO_ADD_INS (cfg->cbb, ins);
6342
6343                         /* bool result = r == comparand; */
6344                         MONO_INST_NEW (cfg, cmp, OP_ICOMPARE);
6345                         cmp->sreg1 = ins->dreg;
6346                         cmp->sreg2 = args [2]->dreg;
6347                         cmp->type = STACK_I4;
6348                         MONO_ADD_INS (cfg->cbb, cmp);
6349
6350                         MONO_INST_NEW (cfg, ceq, OP_ICEQ);
6351                         ceq->dreg = alloc_ireg (cfg);
6352                         ceq->type = STACK_I4;
6353                         MONO_ADD_INS (cfg->cbb, ceq);
6354
6355                         /* *success = result; */
6356                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, args [3]->dreg, 0, ceq->dreg);
6357
6358                         cfg->has_atomic_cas_i4 = TRUE;
6359                 }
6360                 else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0)
6361                         ins = emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6362
6363                 if (ins)
6364                         return ins;
6365         } else if (cmethod->klass->image == mono_defaults.corlib &&
6366                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
6367                            (strcmp (cmethod->klass->name, "Volatile") == 0)) {
6368                 ins = NULL;
6369
6370                 if (!strcmp (cmethod->name, "Read") && fsig->param_count == 1) {
6371                         guint32 opcode = 0;
6372                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6373                         gboolean is_float = fsig->params [0]->type == MONO_TYPE_R4 || fsig->params [0]->type == MONO_TYPE_R8;
6374
6375                         if (fsig->params [0]->type == MONO_TYPE_I1)
6376                                 opcode = OP_ATOMIC_LOAD_I1;
6377                         else if (fsig->params [0]->type == MONO_TYPE_U1 || fsig->params [0]->type == MONO_TYPE_BOOLEAN)
6378                                 opcode = OP_ATOMIC_LOAD_U1;
6379                         else if (fsig->params [0]->type == MONO_TYPE_I2)
6380                                 opcode = OP_ATOMIC_LOAD_I2;
6381                         else if (fsig->params [0]->type == MONO_TYPE_U2)
6382                                 opcode = OP_ATOMIC_LOAD_U2;
6383                         else if (fsig->params [0]->type == MONO_TYPE_I4)
6384                                 opcode = OP_ATOMIC_LOAD_I4;
6385                         else if (fsig->params [0]->type == MONO_TYPE_U4)
6386                                 opcode = OP_ATOMIC_LOAD_U4;
6387                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6388                                 opcode = OP_ATOMIC_LOAD_R4;
6389                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6390                                 opcode = OP_ATOMIC_LOAD_R8;
6391 #if SIZEOF_REGISTER == 8
6392                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_I)
6393                                 opcode = OP_ATOMIC_LOAD_I8;
6394                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_U8 || fsig->params [0]->type == MONO_TYPE_U)
6395                                 opcode = OP_ATOMIC_LOAD_U8;
6396 #else
6397                         else if (fsig->params [0]->type == MONO_TYPE_I)
6398                                 opcode = OP_ATOMIC_LOAD_I4;
6399                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_U)
6400                                 opcode = OP_ATOMIC_LOAD_U4;
6401 #endif
6402
6403                         if (opcode) {
6404                                 if (!mono_arch_opcode_supported (opcode))
6405                                         return NULL;
6406
6407                                 MONO_INST_NEW (cfg, ins, opcode);
6408                                 ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : (is_float ? mono_alloc_freg (cfg) : mono_alloc_ireg (cfg));
6409                                 ins->sreg1 = args [0]->dreg;
6410                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_ACQ;
6411                                 MONO_ADD_INS (cfg->cbb, ins);
6412
6413                                 switch (fsig->params [0]->type) {
6414                                 case MONO_TYPE_BOOLEAN:
6415                                 case MONO_TYPE_I1:
6416                                 case MONO_TYPE_U1:
6417                                 case MONO_TYPE_I2:
6418                                 case MONO_TYPE_U2:
6419                                 case MONO_TYPE_I4:
6420                                 case MONO_TYPE_U4:
6421                                         ins->type = STACK_I4;
6422                                         break;
6423                                 case MONO_TYPE_I8:
6424                                 case MONO_TYPE_U8:
6425                                         ins->type = STACK_I8;
6426                                         break;
6427                                 case MONO_TYPE_I:
6428                                 case MONO_TYPE_U:
6429 #if SIZEOF_REGISTER == 8
6430                                         ins->type = STACK_I8;
6431 #else
6432                                         ins->type = STACK_I4;
6433 #endif
6434                                         break;
6435                                 case MONO_TYPE_R4:
6436                                         ins->type = cfg->r4_stack_type;
6437                                         break;
6438                                 case MONO_TYPE_R8:
6439                                         ins->type = STACK_R8;
6440                                         break;
6441                                 default:
6442                                         g_assert (mini_type_is_reference (fsig->params [0]));
6443                                         ins->type = STACK_OBJ;
6444                                         break;
6445                                 }
6446                         }
6447                 }
6448
6449                 if (!strcmp (cmethod->name, "Write") && fsig->param_count == 2) {
6450                         guint32 opcode = 0;
6451                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6452
6453                         if (fsig->params [0]->type == MONO_TYPE_I1)
6454                                 opcode = OP_ATOMIC_STORE_I1;
6455                         else if (fsig->params [0]->type == MONO_TYPE_U1 || fsig->params [0]->type == MONO_TYPE_BOOLEAN)
6456                                 opcode = OP_ATOMIC_STORE_U1;
6457                         else if (fsig->params [0]->type == MONO_TYPE_I2)
6458                                 opcode = OP_ATOMIC_STORE_I2;
6459                         else if (fsig->params [0]->type == MONO_TYPE_U2)
6460                                 opcode = OP_ATOMIC_STORE_U2;
6461                         else if (fsig->params [0]->type == MONO_TYPE_I4)
6462                                 opcode = OP_ATOMIC_STORE_I4;
6463                         else if (fsig->params [0]->type == MONO_TYPE_U4)
6464                                 opcode = OP_ATOMIC_STORE_U4;
6465                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6466                                 opcode = OP_ATOMIC_STORE_R4;
6467                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6468                                 opcode = OP_ATOMIC_STORE_R8;
6469 #if SIZEOF_REGISTER == 8
6470                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_I)
6471                                 opcode = OP_ATOMIC_STORE_I8;
6472                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_U8 || fsig->params [0]->type == MONO_TYPE_U)
6473                                 opcode = OP_ATOMIC_STORE_U8;
6474 #else
6475                         else if (fsig->params [0]->type == MONO_TYPE_I)
6476                                 opcode = OP_ATOMIC_STORE_I4;
6477                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_U)
6478                                 opcode = OP_ATOMIC_STORE_U4;
6479 #endif
6480
6481                         if (opcode) {
6482                                 if (!mono_arch_opcode_supported (opcode))
6483                                         return NULL;
6484
6485                                 MONO_INST_NEW (cfg, ins, opcode);
6486                                 ins->dreg = args [0]->dreg;
6487                                 ins->sreg1 = args [1]->dreg;
6488                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_REL;
6489                                 MONO_ADD_INS (cfg->cbb, ins);
6490
6491                                 if (cfg->gen_write_barriers && is_ref)
6492                                         emit_write_barrier (cfg, args [0], args [1]);
6493                         }
6494                 }
6495
6496                 if (ins)
6497                         return ins;
6498         } else if (cmethod->klass->image == mono_defaults.corlib &&
6499                            (strcmp (cmethod->klass->name_space, "System.Diagnostics") == 0) &&
6500                            (strcmp (cmethod->klass->name, "Debugger") == 0)) {
6501                 if (!strcmp (cmethod->name, "Break") && fsig->param_count == 0) {
6502                         if (should_insert_brekpoint (cfg->method)) {
6503                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
6504                         } else {
6505                                 MONO_INST_NEW (cfg, ins, OP_NOP);
6506                                 MONO_ADD_INS (cfg->cbb, ins);
6507                         }
6508                         return ins;
6509                 }
6510         } else if (cmethod->klass->image == mono_defaults.corlib &&
6511                    (strcmp (cmethod->klass->name_space, "System") == 0) &&
6512                    (strcmp (cmethod->klass->name, "Environment") == 0)) {
6513                 if (!strcmp (cmethod->name, "get_IsRunningOnWindows") && fsig->param_count == 0) {
6514 #ifdef TARGET_WIN32
6515                         EMIT_NEW_ICONST (cfg, ins, 1);
6516 #else
6517                         EMIT_NEW_ICONST (cfg, ins, 0);
6518 #endif
6519                 }
6520         } else if (cmethod->klass == mono_defaults.math_class) {
6521                 /* 
6522                  * There is general branchless code for Min/Max, but it does not work for 
6523                  * all inputs:
6524                  * http://everything2.com/?node_id=1051618
6525                  */
6526         } else if (((!strcmp (cmethod->klass->image->assembly->aname.name, "MonoMac") ||
6527                     !strcmp (cmethod->klass->image->assembly->aname.name, "monotouch")) &&
6528                                 !strcmp (cmethod->klass->name_space, "XamCore.ObjCRuntime") &&
6529                                 !strcmp (cmethod->klass->name, "Selector")) ||
6530                            (!strcmp (cmethod->klass->image->assembly->aname.name, "Xamarin.iOS") &&
6531                                 !strcmp (cmethod->klass->name_space, "ObjCRuntime") &&
6532                                 !strcmp (cmethod->klass->name, "Selector"))
6533                            ) {
6534 #ifdef MONO_ARCH_HAVE_OBJC_GET_SELECTOR
6535                 if (!strcmp (cmethod->name, "GetHandle") && fsig->param_count == 1 &&
6536                     (args [0]->opcode == OP_GOT_ENTRY || args [0]->opcode == OP_AOTCONST) &&
6537                     cfg->compile_aot) {
6538                         MonoInst *pi;
6539                         MonoJumpInfoToken *ji;
6540                         MonoString *s;
6541
6542                         cfg->disable_llvm = TRUE;
6543
6544                         if (args [0]->opcode == OP_GOT_ENTRY) {
6545                                 pi = args [0]->inst_p1;
6546                                 g_assert (pi->opcode == OP_PATCH_INFO);
6547                                 g_assert (GPOINTER_TO_INT (pi->inst_p1) == MONO_PATCH_INFO_LDSTR);
6548                                 ji = pi->inst_p0;
6549                         } else {
6550                                 g_assert (GPOINTER_TO_INT (args [0]->inst_p1) == MONO_PATCH_INFO_LDSTR);
6551                                 ji = args [0]->inst_p0;
6552                         }
6553
6554                         NULLIFY_INS (args [0]);
6555
6556                         // FIXME: Ugly
6557                         s = mono_ldstr (cfg->domain, ji->image, mono_metadata_token_index (ji->token));
6558                         MONO_INST_NEW (cfg, ins, OP_OBJC_GET_SELECTOR);
6559                         ins->dreg = mono_alloc_ireg (cfg);
6560                         // FIXME: Leaks
6561                         ins->inst_p0 = mono_string_to_utf8 (s);
6562                         MONO_ADD_INS (cfg->cbb, ins);
6563                         return ins;
6564                 }
6565 #endif
6566         }
6567
6568 #ifdef MONO_ARCH_SIMD_INTRINSICS
6569         if (cfg->opt & MONO_OPT_SIMD) {
6570                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
6571                 if (ins)
6572                         return ins;
6573         }
6574 #endif
6575
6576         ins = mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
6577         if (ins)
6578                 return ins;
6579
6580         if (COMPILE_LLVM (cfg)) {
6581                 ins = llvm_emit_inst_for_method (cfg, cmethod, fsig, args);
6582                 if (ins)
6583                         return ins;
6584         }
6585
6586         return mono_arch_emit_inst_for_method (cfg, cmethod, fsig, args);
6587 }
6588
6589 /*
6590  * This entry point could be used later for arbitrary method
6591  * redirection.
6592  */
6593 inline static MonoInst*
6594 mini_redirect_call (MonoCompile *cfg, MonoMethod *method,  
6595                                         MonoMethodSignature *signature, MonoInst **args, MonoInst *this_ins)
6596 {
6597         if (method->klass == mono_defaults.string_class) {
6598                 /* managed string allocation support */
6599                 if (strcmp (method->name, "InternalAllocateStr") == 0 && !(mono_profiler_events & MONO_PROFILE_ALLOCATIONS) && !(cfg->opt & MONO_OPT_SHARED)) {
6600                         MonoInst *iargs [2];
6601                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
6602                         MonoMethod *managed_alloc = NULL;
6603
6604                         g_assert (vtable); /*Should not fail since it System.String*/
6605 #ifndef MONO_CROSS_COMPILE
6606                         managed_alloc = mono_gc_get_managed_allocator (method->klass, FALSE, FALSE);
6607 #endif
6608                         if (!managed_alloc)
6609                                 return NULL;
6610                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
6611                         iargs [1] = args [0];
6612                         return mono_emit_method_call (cfg, managed_alloc, iargs, this_ins);
6613                 }
6614         }
6615         return NULL;
6616 }
6617
6618 static void
6619 mono_save_args (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **sp)
6620 {
6621         MonoInst *store, *temp;
6622         int i;
6623
6624         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
6625                 MonoType *argtype = (sig->hasthis && (i == 0)) ? type_from_stack_type (*sp) : sig->params [i - sig->hasthis];
6626
6627                 /*
6628                  * FIXME: We should use *args++ = sp [0], but that would mean the arg
6629                  * would be different than the MonoInst's used to represent arguments, and
6630                  * the ldelema implementation can't deal with that.
6631                  * Solution: When ldelema is used on an inline argument, create a var for 
6632                  * it, emit ldelema on that var, and emit the saving code below in
6633                  * inline_method () if needed.
6634                  */
6635                 temp = mono_compile_create_var (cfg, argtype, OP_LOCAL);
6636                 cfg->args [i] = temp;
6637                 /* This uses cfg->args [i] which is set by the preceeding line */
6638                 EMIT_NEW_ARGSTORE (cfg, store, i, *sp);
6639                 store->cil_code = sp [0]->cil_code;
6640                 sp++;
6641         }
6642 }
6643
6644 #define MONO_INLINE_CALLED_LIMITED_METHODS 1
6645 #define MONO_INLINE_CALLER_LIMITED_METHODS 1
6646
6647 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
6648 static gboolean
6649 check_inline_called_method_name_limit (MonoMethod *called_method)
6650 {
6651         int strncmp_result;
6652         static const char *limit = NULL;
6653         
6654         if (limit == NULL) {
6655                 const char *limit_string = g_getenv ("MONO_INLINE_CALLED_METHOD_NAME_LIMIT");
6656
6657                 if (limit_string != NULL)
6658                         limit = limit_string;
6659                 else
6660                         limit = "";
6661         }
6662
6663         if (limit [0] != '\0') {
6664                 char *called_method_name = mono_method_full_name (called_method, TRUE);
6665
6666                 strncmp_result = strncmp (called_method_name, limit, strlen (limit));
6667                 g_free (called_method_name);
6668         
6669                 //return (strncmp_result <= 0);
6670                 return (strncmp_result == 0);
6671         } else {
6672                 return TRUE;
6673         }
6674 }
6675 #endif
6676
6677 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
6678 static gboolean
6679 check_inline_caller_method_name_limit (MonoMethod *caller_method)
6680 {
6681         int strncmp_result;
6682         static const char *limit = NULL;
6683         
6684         if (limit == NULL) {
6685                 const char *limit_string = g_getenv ("MONO_INLINE_CALLER_METHOD_NAME_LIMIT");
6686                 if (limit_string != NULL) {
6687                         limit = limit_string;
6688                 } else {
6689                         limit = "";
6690                 }
6691         }
6692
6693         if (limit [0] != '\0') {
6694                 char *caller_method_name = mono_method_full_name (caller_method, TRUE);
6695
6696                 strncmp_result = strncmp (caller_method_name, limit, strlen (limit));
6697                 g_free (caller_method_name);
6698         
6699                 //return (strncmp_result <= 0);
6700                 return (strncmp_result == 0);
6701         } else {
6702                 return TRUE;
6703         }
6704 }
6705 #endif
6706
6707 static void
6708 emit_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
6709 {
6710         static double r8_0 = 0.0;
6711         static float r4_0 = 0.0;
6712         MonoInst *ins;
6713         int t;
6714
6715         rtype = mini_get_underlying_type (rtype);
6716         t = rtype->type;
6717
6718         if (rtype->byref) {
6719                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
6720         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
6721                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
6722         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
6723                 MONO_EMIT_NEW_I8CONST (cfg, dreg, 0);
6724         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
6725                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
6726                 ins->type = STACK_R4;
6727                 ins->inst_p0 = (void*)&r4_0;
6728                 ins->dreg = dreg;
6729                 MONO_ADD_INS (cfg->cbb, ins);
6730         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
6731                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
6732                 ins->type = STACK_R8;
6733                 ins->inst_p0 = (void*)&r8_0;
6734                 ins->dreg = dreg;
6735                 MONO_ADD_INS (cfg->cbb, ins);
6736         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
6737                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
6738                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
6739         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (rtype)) {
6740                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
6741         } else {
6742                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
6743         }
6744 }
6745
6746 static void
6747 emit_dummy_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
6748 {
6749         int t;
6750
6751         rtype = mini_get_underlying_type (rtype);
6752         t = rtype->type;
6753
6754         if (rtype->byref) {
6755                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_PCONST);
6756         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
6757                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_ICONST);
6758         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
6759                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_I8CONST);
6760         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
6761                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R4CONST);
6762         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
6763                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R8CONST);
6764         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
6765                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
6766                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
6767         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (rtype)) {
6768                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
6769         } else {
6770                 emit_init_rvar (cfg, dreg, rtype);
6771         }
6772 }
6773
6774 /* If INIT is FALSE, emit dummy initialization statements to keep the IR valid */
6775 static void
6776 emit_init_local (MonoCompile *cfg, int local, MonoType *type, gboolean init)
6777 {
6778         MonoInst *var = cfg->locals [local];
6779         if (COMPILE_SOFT_FLOAT (cfg)) {
6780                 MonoInst *store;
6781                 int reg = alloc_dreg (cfg, var->type);
6782                 emit_init_rvar (cfg, reg, type);
6783                 EMIT_NEW_LOCSTORE (cfg, store, local, cfg->cbb->last_ins);
6784         } else {
6785                 if (init)
6786                         emit_init_rvar (cfg, var->dreg, type);
6787                 else
6788                         emit_dummy_init_rvar (cfg, var->dreg, type);
6789         }
6790 }
6791
6792 /*
6793  * inline_method:
6794  *
6795  *   Return the cost of inlining CMETHOD.
6796  */
6797 static int
6798 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
6799                            guchar *ip, guint real_offset, gboolean inline_always)
6800 {
6801         MonoInst *ins, *rvar = NULL;
6802         MonoMethodHeader *cheader;
6803         MonoBasicBlock *ebblock, *sbblock;
6804         int i, costs;
6805         MonoMethod *prev_inlined_method;
6806         MonoInst **prev_locals, **prev_args;
6807         MonoType **prev_arg_types;
6808         guint prev_real_offset;
6809         GHashTable *prev_cbb_hash;
6810         MonoBasicBlock **prev_cil_offset_to_bb;
6811         MonoBasicBlock *prev_cbb;
6812         unsigned char* prev_cil_start;
6813         guint32 prev_cil_offset_to_bb_len;
6814         MonoMethod *prev_current_method;
6815         MonoGenericContext *prev_generic_context;
6816         gboolean ret_var_set, prev_ret_var_set, prev_disable_inline, virtual = FALSE;
6817
6818         g_assert (cfg->exception_type == MONO_EXCEPTION_NONE);
6819
6820 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
6821         if ((! inline_always) && ! check_inline_called_method_name_limit (cmethod))
6822                 return 0;
6823 #endif
6824 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
6825         if ((! inline_always) && ! check_inline_caller_method_name_limit (cfg->method))
6826                 return 0;
6827 #endif
6828
6829         if (!fsig)
6830                 fsig = mono_method_signature (cmethod);
6831
6832         if (cfg->verbose_level > 2)
6833                 printf ("INLINE START %p %s -> %s\n", cmethod,  mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
6834
6835         if (!cmethod->inline_info) {
6836                 cfg->stat_inlineable_methods++;
6837                 cmethod->inline_info = 1;
6838         }
6839
6840         /* allocate local variables */
6841         cheader = mono_method_get_header (cmethod);
6842
6843         if (cheader == NULL || mono_loader_get_last_error ()) {
6844                 MonoLoaderError *error = mono_loader_get_last_error ();
6845
6846                 if (cheader)
6847                         mono_metadata_free_mh (cheader);
6848                 if (inline_always && error)
6849                         mono_cfg_set_exception (cfg, error->exception_type);
6850
6851                 mono_loader_clear_error ();
6852                 return 0;
6853         }
6854
6855         /*Must verify before creating locals as it can cause the JIT to assert.*/
6856         if (mono_compile_is_broken (cfg, cmethod, FALSE)) {
6857                 mono_metadata_free_mh (cheader);
6858                 return 0;
6859         }
6860
6861         /* allocate space to store the return value */
6862         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
6863                 rvar = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
6864         }
6865
6866         prev_locals = cfg->locals;
6867         cfg->locals = mono_mempool_alloc0 (cfg->mempool, cheader->num_locals * sizeof (MonoInst*));     
6868         for (i = 0; i < cheader->num_locals; ++i)
6869                 cfg->locals [i] = mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
6870
6871         /* allocate start and end blocks */
6872         /* This is needed so if the inline is aborted, we can clean up */
6873         NEW_BBLOCK (cfg, sbblock);
6874         sbblock->real_offset = real_offset;
6875
6876         NEW_BBLOCK (cfg, ebblock);
6877         ebblock->block_num = cfg->num_bblocks++;
6878         ebblock->real_offset = real_offset;
6879
6880         prev_args = cfg->args;
6881         prev_arg_types = cfg->arg_types;
6882         prev_inlined_method = cfg->inlined_method;
6883         cfg->inlined_method = cmethod;
6884         cfg->ret_var_set = FALSE;
6885         cfg->inline_depth ++;
6886         prev_real_offset = cfg->real_offset;
6887         prev_cbb_hash = cfg->cbb_hash;
6888         prev_cil_offset_to_bb = cfg->cil_offset_to_bb;
6889         prev_cil_offset_to_bb_len = cfg->cil_offset_to_bb_len;
6890         prev_cil_start = cfg->cil_start;
6891         prev_cbb = cfg->cbb;
6892         prev_current_method = cfg->current_method;
6893         prev_generic_context = cfg->generic_context;
6894         prev_ret_var_set = cfg->ret_var_set;
6895         prev_disable_inline = cfg->disable_inline;
6896
6897         if (ip && *ip == CEE_CALLVIRT && !(cmethod->flags & METHOD_ATTRIBUTE_STATIC))
6898                 virtual = TRUE;
6899
6900         costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, rvar, sp, real_offset, virtual);
6901
6902         ret_var_set = cfg->ret_var_set;
6903
6904         cfg->inlined_method = prev_inlined_method;
6905         cfg->real_offset = prev_real_offset;
6906         cfg->cbb_hash = prev_cbb_hash;
6907         cfg->cil_offset_to_bb = prev_cil_offset_to_bb;
6908         cfg->cil_offset_to_bb_len = prev_cil_offset_to_bb_len;
6909         cfg->cil_start = prev_cil_start;
6910         cfg->locals = prev_locals;
6911         cfg->args = prev_args;
6912         cfg->arg_types = prev_arg_types;
6913         cfg->current_method = prev_current_method;
6914         cfg->generic_context = prev_generic_context;
6915         cfg->ret_var_set = prev_ret_var_set;
6916         cfg->disable_inline = prev_disable_inline;
6917         cfg->inline_depth --;
6918
6919         if ((costs >= 0 && costs < 60) || inline_always || (costs >= 0 && (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))) {
6920                 if (cfg->verbose_level > 2)
6921                         printf ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
6922                 
6923                 cfg->stat_inlined_methods++;
6924
6925                 /* always add some code to avoid block split failures */
6926                 MONO_INST_NEW (cfg, ins, OP_NOP);
6927                 MONO_ADD_INS (prev_cbb, ins);
6928
6929                 prev_cbb->next_bb = sbblock;
6930                 link_bblock (cfg, prev_cbb, sbblock);
6931
6932                 /* 
6933                  * Get rid of the begin and end bblocks if possible to aid local
6934                  * optimizations.
6935                  */
6936                 mono_merge_basic_blocks (cfg, prev_cbb, sbblock);
6937
6938                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] != ebblock))
6939                         mono_merge_basic_blocks (cfg, prev_cbb, prev_cbb->out_bb [0]);
6940
6941                 if ((ebblock->in_count == 1) && ebblock->in_bb [0]->out_count == 1) {
6942                         MonoBasicBlock *prev = ebblock->in_bb [0];
6943                         mono_merge_basic_blocks (cfg, prev, ebblock);
6944                         cfg->cbb = prev;
6945                         if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] == prev)) {
6946                                 mono_merge_basic_blocks (cfg, prev_cbb, prev);
6947                                 cfg->cbb = prev_cbb;
6948                         }
6949                 } else {
6950                         /* 
6951                          * Its possible that the rvar is set in some prev bblock, but not in others.
6952                          * (#1835).
6953                          */
6954                         if (rvar) {
6955                                 MonoBasicBlock *bb;
6956
6957                                 for (i = 0; i < ebblock->in_count; ++i) {
6958                                         bb = ebblock->in_bb [i];
6959
6960                                         if (bb->last_ins && bb->last_ins->opcode == OP_NOT_REACHED) {
6961                                                 cfg->cbb = bb;
6962
6963                                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
6964                                         }
6965                                 }
6966                         }
6967
6968                         cfg->cbb = ebblock;
6969                 }
6970
6971                 if (rvar) {
6972                         /*
6973                          * If the inlined method contains only a throw, then the ret var is not 
6974                          * set, so set it to a dummy value.
6975                          */
6976                         if (!ret_var_set)
6977                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
6978
6979                         EMIT_NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
6980                         *sp++ = ins;
6981                 }
6982                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
6983                 return costs + 1;
6984         } else {
6985                 if (cfg->verbose_level > 2)
6986                         printf ("INLINE ABORTED %s (cost %d)\n", mono_method_full_name (cmethod, TRUE), costs);
6987                 cfg->exception_type = MONO_EXCEPTION_NONE;
6988                 mono_loader_clear_error ();
6989
6990                 /* This gets rid of the newly added bblocks */
6991                 cfg->cbb = prev_cbb;
6992         }
6993         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
6994         return 0;
6995 }
6996
6997 /*
6998  * Some of these comments may well be out-of-date.
6999  * Design decisions: we do a single pass over the IL code (and we do bblock 
7000  * splitting/merging in the few cases when it's required: a back jump to an IL
7001  * address that was not already seen as bblock starting point).
7002  * Code is validated as we go (full verification is still better left to metadata/verify.c).
7003  * Complex operations are decomposed in simpler ones right away. We need to let the 
7004  * arch-specific code peek and poke inside this process somehow (except when the 
7005  * optimizations can take advantage of the full semantic info of coarse opcodes).
7006  * All the opcodes of the form opcode.s are 'normalized' to opcode.
7007  * MonoInst->opcode initially is the IL opcode or some simplification of that 
7008  * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific 
7009  * opcode with value bigger than OP_LAST.
7010  * At this point the IR can be handed over to an interpreter, a dumb code generator
7011  * or to the optimizing code generator that will translate it to SSA form.
7012  *
7013  * Profiling directed optimizations.
7014  * We may compile by default with few or no optimizations and instrument the code
7015  * or the user may indicate what methods to optimize the most either in a config file
7016  * or through repeated runs where the compiler applies offline the optimizations to 
7017  * each method and then decides if it was worth it.
7018  */
7019
7020 #define CHECK_TYPE(ins) if (!(ins)->type) UNVERIFIED
7021 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) UNVERIFIED
7022 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) UNVERIFIED
7023 #define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) UNVERIFIED
7024 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
7025 #define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
7026 #define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
7027 #define CHECK_TYPELOAD(klass) if (!(klass) || (klass)->exception_type) TYPE_LOAD_ERROR ((klass))
7028
7029 /* offset from br.s -> br like opcodes */
7030 #define BIG_BRANCH_OFFSET 13
7031
7032 static gboolean
7033 ip_in_bb (MonoCompile *cfg, MonoBasicBlock *bb, const guint8* ip)
7034 {
7035         MonoBasicBlock *b = cfg->cil_offset_to_bb [ip - cfg->cil_start];
7036
7037         return b == NULL || b == bb;
7038 }
7039
7040 static int
7041 get_basic_blocks (MonoCompile *cfg, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
7042 {
7043         unsigned char *ip = start;
7044         unsigned char *target;
7045         int i;
7046         guint cli_addr;
7047         MonoBasicBlock *bblock;
7048         const MonoOpcode *opcode;
7049
7050         while (ip < end) {
7051                 cli_addr = ip - start;
7052                 i = mono_opcode_value ((const guint8 **)&ip, end);
7053                 if (i < 0)
7054                         UNVERIFIED;
7055                 opcode = &mono_opcodes [i];
7056                 switch (opcode->argument) {
7057                 case MonoInlineNone:
7058                         ip++; 
7059                         break;
7060                 case MonoInlineString:
7061                 case MonoInlineType:
7062                 case MonoInlineField:
7063                 case MonoInlineMethod:
7064                 case MonoInlineTok:
7065                 case MonoInlineSig:
7066                 case MonoShortInlineR:
7067                 case MonoInlineI:
7068                         ip += 5;
7069                         break;
7070                 case MonoInlineVar:
7071                         ip += 3;
7072                         break;
7073                 case MonoShortInlineVar:
7074                 case MonoShortInlineI:
7075                         ip += 2;
7076                         break;
7077                 case MonoShortInlineBrTarget:
7078                         target = start + cli_addr + 2 + (signed char)ip [1];
7079                         GET_BBLOCK (cfg, bblock, target);
7080                         ip += 2;
7081                         if (ip < end)
7082                                 GET_BBLOCK (cfg, bblock, ip);
7083                         break;
7084                 case MonoInlineBrTarget:
7085                         target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
7086                         GET_BBLOCK (cfg, bblock, target);
7087                         ip += 5;
7088                         if (ip < end)
7089                                 GET_BBLOCK (cfg, bblock, ip);
7090                         break;
7091                 case MonoInlineSwitch: {
7092                         guint32 n = read32 (ip + 1);
7093                         guint32 j;
7094                         ip += 5;
7095                         cli_addr += 5 + 4 * n;
7096                         target = start + cli_addr;
7097                         GET_BBLOCK (cfg, bblock, target);
7098                         
7099                         for (j = 0; j < n; ++j) {
7100                                 target = start + cli_addr + (gint32)read32 (ip);
7101                                 GET_BBLOCK (cfg, bblock, target);
7102                                 ip += 4;
7103                         }
7104                         break;
7105                 }
7106                 case MonoInlineR:
7107                 case MonoInlineI8:
7108                         ip += 9;
7109                         break;
7110                 default:
7111                         g_assert_not_reached ();
7112                 }
7113
7114                 if (i == CEE_THROW) {
7115                         unsigned char *bb_start = ip - 1;
7116                         
7117                         /* Find the start of the bblock containing the throw */
7118                         bblock = NULL;
7119                         while ((bb_start >= start) && !bblock) {
7120                                 bblock = cfg->cil_offset_to_bb [(bb_start) - start];
7121                                 bb_start --;
7122                         }
7123                         if (bblock)
7124                                 bblock->out_of_line = 1;
7125                 }
7126         }
7127         return 0;
7128 unverified:
7129 exception_exit:
7130         *pos = ip;
7131         return 1;
7132 }
7133
7134 static inline MonoMethod *
7135 mini_get_method_allow_open (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
7136 {
7137         MonoMethod *method;
7138
7139         if (m->wrapper_type != MONO_WRAPPER_NONE) {
7140                 method = mono_method_get_wrapper_data (m, token);
7141                 if (context) {
7142                         MonoError error;
7143                         method = mono_class_inflate_generic_method_checked (method, context, &error);
7144                         g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
7145                 }
7146         } else {
7147                 method = mono_get_method_full (m->klass->image, token, klass, context);
7148         }
7149
7150         return method;
7151 }
7152
7153 static inline MonoMethod *
7154 mini_get_method (MonoCompile *cfg, MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
7155 {
7156         MonoMethod *method = mini_get_method_allow_open (m, token, klass, context);
7157
7158         if (method && cfg && !cfg->gshared && mono_class_is_open_constructed_type (&method->klass->byval_arg))
7159                 return NULL;
7160
7161         return method;
7162 }
7163
7164 static inline MonoClass*
7165 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
7166 {
7167         MonoError error;
7168         MonoClass *klass;
7169
7170         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7171                 klass = mono_method_get_wrapper_data (method, token);
7172                 if (context)
7173                         klass = mono_class_inflate_generic_class (klass, context);
7174         } else {
7175                 klass = mono_class_get_and_inflate_typespec_checked (method->klass->image, token, context, &error);
7176                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
7177         }
7178         if (klass)
7179                 mono_class_init (klass);
7180         return klass;
7181 }
7182
7183 static inline MonoMethodSignature*
7184 mini_get_signature (MonoMethod *method, guint32 token, MonoGenericContext *context)
7185 {
7186         MonoMethodSignature *fsig;
7187
7188         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7189                 MonoError error;
7190
7191                 fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
7192                 if (context) {
7193                         fsig = mono_inflate_generic_signature (fsig, context, &error);
7194                         // FIXME:
7195                         g_assert (mono_error_ok (&error));
7196                 }
7197         } else {
7198                 fsig = mono_metadata_parse_signature (method->klass->image, token);
7199         }
7200         return fsig;
7201 }
7202
7203 static MonoMethod*
7204 throw_exception (void)
7205 {
7206         static MonoMethod *method = NULL;
7207
7208         if (!method) {
7209                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
7210                 method = mono_class_get_method_from_name (secman->securitymanager, "ThrowException", 1);
7211         }
7212         g_assert (method);
7213         return method;
7214 }
7215
7216 static void
7217 emit_throw_exception (MonoCompile *cfg, MonoException *ex)
7218 {
7219         MonoMethod *thrower = throw_exception ();
7220         MonoInst *args [1];
7221
7222         EMIT_NEW_PCONST (cfg, args [0], ex);
7223         mono_emit_method_call (cfg, thrower, args, NULL);
7224 }
7225
7226 /*
7227  * Return the original method is a wrapper is specified. We can only access 
7228  * the custom attributes from the original method.
7229  */
7230 static MonoMethod*
7231 get_original_method (MonoMethod *method)
7232 {
7233         if (method->wrapper_type == MONO_WRAPPER_NONE)
7234                 return method;
7235
7236         /* native code (which is like Critical) can call any managed method XXX FIXME XXX to validate all usages */
7237         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)
7238                 return NULL;
7239
7240         /* in other cases we need to find the original method */
7241         return mono_marshal_method_from_wrapper (method);
7242 }
7243
7244 static void
7245 ensure_method_is_allowed_to_access_field (MonoCompile *cfg, MonoMethod *caller, MonoClassField *field)
7246 {
7247         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
7248         MonoException *ex = mono_security_core_clr_is_field_access_allowed (get_original_method (caller), field);
7249         if (ex)
7250                 emit_throw_exception (cfg, ex);
7251 }
7252
7253 static void
7254 ensure_method_is_allowed_to_call_method (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee)
7255 {
7256         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
7257         MonoException *ex = mono_security_core_clr_is_call_allowed (get_original_method (caller), callee);
7258         if (ex)
7259                 emit_throw_exception (cfg, ex);
7260 }
7261
7262 /*
7263  * Check that the IL instructions at ip are the array initialization
7264  * sequence and return the pointer to the data and the size.
7265  */
7266 static const char*
7267 initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, MonoClass *klass, guint32 len, int *out_size, guint32 *out_field_token)
7268 {
7269         /*
7270          * newarr[System.Int32]
7271          * dup
7272          * ldtoken field valuetype ...
7273          * call void class [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle)
7274          */
7275         if (ip [0] == CEE_DUP && ip [1] == CEE_LDTOKEN && ip [5] == 0x4 && ip [6] == CEE_CALL) {
7276                 MonoError error;
7277                 guint32 token = read32 (ip + 7);
7278                 guint32 field_token = read32 (ip + 2);
7279                 guint32 field_index = field_token & 0xffffff;
7280                 guint32 rva;
7281                 const char *data_ptr;
7282                 int size = 0;
7283                 MonoMethod *cmethod;
7284                 MonoClass *dummy_class;
7285                 MonoClassField *field = mono_field_from_token_checked (method->klass->image, field_token, &dummy_class, NULL, &error);
7286                 int dummy_align;
7287
7288                 if (!field) {
7289                         mono_error_cleanup (&error); /* FIXME don't swallow the error */
7290                         return NULL;
7291                 }
7292
7293                 *out_field_token = field_token;
7294
7295                 cmethod = mini_get_method (NULL, method, token, NULL, NULL);
7296                 if (!cmethod)
7297                         return NULL;
7298                 if (strcmp (cmethod->name, "InitializeArray") || strcmp (cmethod->klass->name, "RuntimeHelpers") || cmethod->klass->image != mono_defaults.corlib)
7299                         return NULL;
7300                 switch (mono_type_get_underlying_type (&klass->byval_arg)->type) {
7301                 case MONO_TYPE_BOOLEAN:
7302                 case MONO_TYPE_I1:
7303                 case MONO_TYPE_U1:
7304                         size = 1; break;
7305                 /* we need to swap on big endian, so punt. Should we handle R4 and R8 as well? */
7306 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
7307                 case MONO_TYPE_CHAR:
7308                 case MONO_TYPE_I2:
7309                 case MONO_TYPE_U2:
7310                         size = 2; break;
7311                 case MONO_TYPE_I4:
7312                 case MONO_TYPE_U4:
7313                 case MONO_TYPE_R4:
7314                         size = 4; break;
7315                 case MONO_TYPE_R8:
7316                 case MONO_TYPE_I8:
7317                 case MONO_TYPE_U8:
7318                         size = 8; break;
7319 #endif
7320                 default:
7321                         return NULL;
7322                 }
7323                 size *= len;
7324                 if (size > mono_type_size (field->type, &dummy_align))
7325                     return NULL;
7326                 *out_size = size;
7327                 /*g_print ("optimized in %s: size: %d, numelems: %d\n", method->name, size, newarr->inst_newa_len->inst_c0);*/
7328                 if (!image_is_dynamic (method->klass->image)) {
7329                         field_index = read32 (ip + 2) & 0xffffff;
7330                         mono_metadata_field_info (method->klass->image, field_index - 1, NULL, &rva, NULL);
7331                         data_ptr = mono_image_rva_map (method->klass->image, rva);
7332                         /*g_print ("field: 0x%08x, rva: %d, rva_ptr: %p\n", read32 (ip + 2), rva, data_ptr);*/
7333                         /* for aot code we do the lookup on load */
7334                         if (aot && data_ptr)
7335                                 return GUINT_TO_POINTER (rva);
7336                 } else {
7337                         /*FIXME is it possible to AOT a SRE assembly not meant to be saved? */ 
7338                         g_assert (!aot);
7339                         data_ptr = mono_field_get_data (field);
7340                 }
7341                 return data_ptr;
7342         }
7343         return NULL;
7344 }
7345
7346 static void
7347 set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsigned char *ip)
7348 {
7349         char *method_fname = mono_method_full_name (method, TRUE);
7350         char *method_code;
7351         MonoMethodHeader *header = mono_method_get_header (method);
7352
7353         if (header->code_size == 0)
7354                 method_code = g_strdup ("method body is empty.");
7355         else
7356                 method_code = mono_disasm_code_one (NULL, method, ip, NULL);
7357         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
7358         cfg->exception_message = g_strdup_printf ("Invalid IL code in %s: %s\n", method_fname, method_code);
7359         g_free (method_fname);
7360         g_free (method_code);
7361         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
7362 }
7363
7364 static void
7365 set_exception_object (MonoCompile *cfg, MonoException *exception)
7366 {
7367         mono_cfg_set_exception (cfg, MONO_EXCEPTION_OBJECT_SUPPLIED);
7368         MONO_GC_REGISTER_ROOT_SINGLE (cfg->exception_ptr);
7369         cfg->exception_ptr = exception;
7370 }
7371
7372 static void
7373 emit_stloc_ir (MonoCompile *cfg, MonoInst **sp, MonoMethodHeader *header, int n)
7374 {
7375         MonoInst *ins;
7376         guint32 opcode = mono_type_to_regmove (cfg, header->locals [n]);
7377         if ((opcode == OP_MOVE) && cfg->cbb->last_ins == sp [0]  &&
7378                         ((sp [0]->opcode == OP_ICONST) || (sp [0]->opcode == OP_I8CONST))) {
7379                 /* Optimize reg-reg moves away */
7380                 /* 
7381                  * Can't optimize other opcodes, since sp[0] might point to
7382                  * the last ins of a decomposed opcode.
7383                  */
7384                 sp [0]->dreg = (cfg)->locals [n]->dreg;
7385         } else {
7386                 EMIT_NEW_LOCSTORE (cfg, ins, n, *sp);
7387         }
7388 }
7389
7390 /*
7391  * ldloca inhibits many optimizations so try to get rid of it in common
7392  * cases.
7393  */
7394 static inline unsigned char *
7395 emit_optimized_ldloca_ir (MonoCompile *cfg, unsigned char *ip, unsigned char *end, int size)
7396 {
7397         int local, token;
7398         MonoClass *klass;
7399         MonoType *type;
7400
7401         if (size == 1) {
7402                 local = ip [1];
7403                 ip += 2;
7404         } else {
7405                 local = read16 (ip + 2);
7406                 ip += 4;
7407         }
7408         
7409         if (ip + 6 < end && (ip [0] == CEE_PREFIX1) && (ip [1] == CEE_INITOBJ) && ip_in_bb (cfg, cfg->cbb, ip + 1)) {
7410                 /* From the INITOBJ case */
7411                 token = read32 (ip + 2);
7412                 klass = mini_get_class (cfg->current_method, token, cfg->generic_context);
7413                 CHECK_TYPELOAD (klass);
7414                 type = mini_get_underlying_type (&klass->byval_arg);
7415                 emit_init_local (cfg, local, type, TRUE);
7416                 return ip + 6;
7417         }
7418  exception_exit:
7419         return NULL;
7420 }
7421
7422 static gboolean
7423 is_exception_class (MonoClass *klass)
7424 {
7425         while (klass) {
7426                 if (klass == mono_defaults.exception_class)
7427                         return TRUE;
7428                 klass = klass->parent;
7429         }
7430         return FALSE;
7431 }
7432
7433 /*
7434  * is_jit_optimizer_disabled:
7435  *
7436  *   Determine whenever M's assembly has a DebuggableAttribute with the
7437  * IsJITOptimizerDisabled flag set.
7438  */
7439 static gboolean
7440 is_jit_optimizer_disabled (MonoMethod *m)
7441 {
7442         MonoAssembly *ass = m->klass->image->assembly;
7443         MonoCustomAttrInfo* attrs;
7444         static MonoClass *klass;
7445         int i;
7446         gboolean val = FALSE;
7447
7448         g_assert (ass);
7449         if (ass->jit_optimizer_disabled_inited)
7450                 return ass->jit_optimizer_disabled;
7451
7452         if (!klass)
7453                 klass = mono_class_from_name (mono_defaults.corlib, "System.Diagnostics", "DebuggableAttribute");
7454         if (!klass) {
7455                 /* Linked away */
7456                 ass->jit_optimizer_disabled = FALSE;
7457                 mono_memory_barrier ();
7458                 ass->jit_optimizer_disabled_inited = TRUE;
7459                 return FALSE;
7460         }
7461
7462         attrs = mono_custom_attrs_from_assembly (ass);
7463         if (attrs) {
7464                 for (i = 0; i < attrs->num_attrs; ++i) {
7465                         MonoCustomAttrEntry *attr = &attrs->attrs [i];
7466                         const gchar *p;
7467                         MonoMethodSignature *sig;
7468
7469                         if (!attr->ctor || attr->ctor->klass != klass)
7470                                 continue;
7471                         /* Decode the attribute. See reflection.c */
7472                         p = (const char*)attr->data;
7473                         g_assert (read16 (p) == 0x0001);
7474                         p += 2;
7475
7476                         // FIXME: Support named parameters
7477                         sig = mono_method_signature (attr->ctor);
7478                         if (sig->param_count != 2 || sig->params [0]->type != MONO_TYPE_BOOLEAN || sig->params [1]->type != MONO_TYPE_BOOLEAN)
7479                                 continue;
7480                         /* Two boolean arguments */
7481                         p ++;
7482                         val = *p;
7483                 }
7484                 mono_custom_attrs_free (attrs);
7485         }
7486
7487         ass->jit_optimizer_disabled = val;
7488         mono_memory_barrier ();
7489         ass->jit_optimizer_disabled_inited = TRUE;
7490
7491         return val;
7492 }
7493
7494 static gboolean
7495 is_supported_tail_call (MonoCompile *cfg, MonoMethod *method, MonoMethod *cmethod, MonoMethodSignature *fsig, int call_opcode)
7496 {
7497         gboolean supported_tail_call;
7498         int i;
7499
7500 #ifdef MONO_ARCH_HAVE_OP_TAIL_CALL
7501         supported_tail_call = mono_arch_tail_call_supported (cfg, mono_method_signature (method), mono_method_signature (cmethod));
7502 #else
7503         supported_tail_call = mono_metadata_signature_equal (mono_method_signature (method), mono_method_signature (cmethod)) && !MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->ret);
7504 #endif
7505
7506         for (i = 0; i < fsig->param_count; ++i) {
7507                 if (fsig->params [i]->byref || fsig->params [i]->type == MONO_TYPE_PTR || fsig->params [i]->type == MONO_TYPE_FNPTR)
7508                         /* These can point to the current method's stack */
7509                         supported_tail_call = FALSE;
7510         }
7511         if (fsig->hasthis && cmethod->klass->valuetype)
7512                 /* this might point to the current method's stack */
7513                 supported_tail_call = FALSE;
7514         if (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
7515                 supported_tail_call = FALSE;
7516         if (cfg->method->save_lmf)
7517                 supported_tail_call = FALSE;
7518         if (cmethod->wrapper_type && cmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD)
7519                 supported_tail_call = FALSE;
7520         if (call_opcode != CEE_CALL)
7521                 supported_tail_call = FALSE;
7522
7523         /* Debugging support */
7524 #if 0
7525         if (supported_tail_call) {
7526                 if (!mono_debug_count ())
7527                         supported_tail_call = FALSE;
7528         }
7529 #endif
7530
7531         return supported_tail_call;
7532 }
7533
7534 /* emits the code needed to access a managed tls var (like ThreadStatic)
7535  * with the value of the tls offset in offset_reg. thread_ins represents the MonoInternalThread
7536  * pointer for the current thread.
7537  * Returns the MonoInst* representing the address of the tls var.
7538  */
7539 static MonoInst*
7540 emit_managed_static_data_access (MonoCompile *cfg, MonoInst *thread_ins, int offset_reg)
7541 {
7542         MonoInst *addr;
7543         int static_data_reg, array_reg, dreg;
7544         int offset2_reg, idx_reg;
7545         // inlined access to the tls data (see threads.c)
7546         static_data_reg = alloc_ireg (cfg);
7547         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, MONO_STRUCT_OFFSET (MonoInternalThread, static_data));
7548         idx_reg = alloc_ireg (cfg);
7549         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, idx_reg, offset_reg, 0x3f);
7550         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
7551         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
7552         array_reg = alloc_ireg (cfg);
7553         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
7554         offset2_reg = alloc_ireg (cfg);
7555         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, offset2_reg, offset_reg, 6);
7556         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset2_reg, 0x1ffffff);
7557         dreg = alloc_ireg (cfg);
7558         EMIT_NEW_BIALU (cfg, addr, OP_PADD, dreg, array_reg, offset2_reg);
7559         return addr;
7560 }
7561
7562 /*
7563  * handle_ctor_call:
7564  *
7565  *   Handle calls made to ctors from NEWOBJ opcodes.
7566  */
7567 static void
7568 handle_ctor_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used,
7569                                   MonoInst **sp, guint8 *ip, int *inline_costs)
7570 {
7571         MonoInst *vtable_arg = NULL, *callvirt_this_arg = NULL, *ins;
7572
7573         if (cmethod->klass->valuetype && mono_class_generic_sharing_enabled (cmethod->klass) &&
7574                                         mono_method_is_generic_sharable (cmethod, TRUE)) {
7575                 if (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst) {
7576                         mono_class_vtable (cfg->domain, cmethod->klass);
7577                         CHECK_TYPELOAD (cmethod->klass);
7578
7579                         vtable_arg = emit_get_rgctx_method (cfg, context_used,
7580                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
7581                 } else {
7582                         if (context_used) {
7583                                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
7584                                                                                                    cmethod->klass, MONO_RGCTX_INFO_VTABLE);
7585                         } else {
7586                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
7587
7588                                 CHECK_TYPELOAD (cmethod->klass);
7589                                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
7590                         }
7591                 }
7592         }
7593
7594         /* Avoid virtual calls to ctors if possible */
7595         if (mono_class_is_marshalbyref (cmethod->klass))
7596                 callvirt_this_arg = sp [0];
7597
7598         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_ctor (cfg, cmethod, fsig, sp))) {
7599                 g_assert (MONO_TYPE_IS_VOID (fsig->ret));
7600                 CHECK_CFG_EXCEPTION;
7601         } else if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used && !vtable_arg &&
7602                            mono_method_check_inlining (cfg, cmethod) &&
7603                            !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE)) {
7604                 int costs;
7605
7606                 if ((costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, FALSE))) {
7607                         cfg->real_offset += 5;
7608
7609                         *inline_costs += costs - 5;
7610                 } else {
7611                         INLINE_FAILURE ("inline failure");
7612                         // FIXME-VT: Clean this up
7613                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))
7614                                 GSHAREDVT_FAILURE(*ip);
7615                         mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, callvirt_this_arg, NULL, NULL);
7616                 }
7617         } else if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
7618                 MonoInst *addr;
7619
7620                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE);
7621                 mono_emit_calli (cfg, fsig, sp, addr, NULL, vtable_arg);
7622         } else if (context_used &&
7623                            ((!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
7624                                  !mono_class_generic_sharing_enabled (cmethod->klass)) || cfg->gsharedvt)) {
7625                 MonoInst *cmethod_addr;
7626
7627                 /* Generic calls made out of gsharedvt methods cannot be patched, so use an indirect call */
7628
7629                 cmethod_addr = emit_get_rgctx_method (cfg, context_used,
7630                                                                                           cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
7631
7632                 mono_emit_calli (cfg, fsig, sp, cmethod_addr, NULL, vtable_arg);
7633         } else {
7634                 INLINE_FAILURE ("ctor call");
7635                 ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp,
7636                                                                                   callvirt_this_arg, NULL, vtable_arg);
7637         }
7638  exception_exit:
7639         return;
7640 }
7641
7642 /*
7643  * mono_method_to_ir:
7644  *
7645  *   Translate the .net IL into linear IR.
7646  */
7647 int
7648 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
7649                    MonoInst *return_var, MonoInst **inline_args, 
7650                    guint inline_offset, gboolean is_virtual_call)
7651 {
7652         MonoError error;
7653         MonoInst *ins, **sp, **stack_start;
7654         MonoBasicBlock *tblock = NULL, *init_localsbb = NULL;
7655         MonoSimpleBasicBlock *bb = NULL, *original_bb = NULL;
7656         MonoMethod *cmethod, *method_definition;
7657         MonoInst **arg_array;
7658         MonoMethodHeader *header;
7659         MonoImage *image;
7660         guint32 token, ins_flag;
7661         MonoClass *klass;
7662         MonoClass *constrained_class = NULL;
7663         unsigned char *ip, *end, *target, *err_pos;
7664         MonoMethodSignature *sig;
7665         MonoGenericContext *generic_context = NULL;
7666         MonoGenericContainer *generic_container = NULL;
7667         MonoType **param_types;
7668         int i, n, start_new_bblock, dreg;
7669         int num_calls = 0, inline_costs = 0;
7670         int breakpoint_id = 0;
7671         guint num_args;
7672         GSList *class_inits = NULL;
7673         gboolean dont_verify, dont_verify_stloc, readonly = FALSE;
7674         int context_used;
7675         gboolean init_locals, seq_points, skip_dead_blocks;
7676         gboolean sym_seq_points = FALSE;
7677         MonoDebugMethodInfo *minfo;
7678         MonoBitSet *seq_point_locs = NULL;
7679         MonoBitSet *seq_point_set_locs = NULL;
7680
7681         cfg->disable_inline = is_jit_optimizer_disabled (method);
7682
7683         /* serialization and xdomain stuff may need access to private fields and methods */
7684         dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
7685         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE;
7686         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH;
7687         dont_verify |= method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; /* bug #77896 */
7688         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP;
7689         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP_INVOKE;
7690
7691         /* still some type unsafety issues in marshal wrappers... (unknown is PtrToStructure) */
7692         dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE;
7693         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_UNKNOWN;
7694         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED;
7695         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_STELEMREF;
7696
7697         image = method->klass->image;
7698         header = mono_method_get_header (method);
7699         if (!header) {
7700                 MonoLoaderError *error;
7701
7702                 if ((error = mono_loader_get_last_error ())) {
7703                         mono_cfg_set_exception (cfg, error->exception_type);
7704                 } else {
7705                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
7706                         cfg->exception_message = g_strdup_printf ("Missing or incorrect header for method %s", cfg->method->name);
7707                 }
7708                 goto exception_exit;
7709         }
7710         generic_container = mono_method_get_generic_container (method);
7711         sig = mono_method_signature (method);
7712         num_args = sig->hasthis + sig->param_count;
7713         ip = (unsigned char*)header->code;
7714         cfg->cil_start = ip;
7715         end = ip + header->code_size;
7716         cfg->stat_cil_code_size += header->code_size;
7717
7718         seq_points = cfg->gen_seq_points && cfg->method == method;
7719
7720         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
7721                 /* We could hit a seq point before attaching to the JIT (#8338) */
7722                 seq_points = FALSE;
7723         }
7724
7725         if (cfg->gen_sdb_seq_points && cfg->method == method) {
7726                 minfo = mono_debug_lookup_method (method);
7727                 if (minfo) {
7728                         MonoSymSeqPoint *sps;
7729                         int i, n_il_offsets;
7730
7731                         mono_debug_get_seq_points (minfo, NULL, NULL, NULL, &sps, &n_il_offsets);
7732                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
7733                         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);
7734                         sym_seq_points = TRUE;
7735                         for (i = 0; i < n_il_offsets; ++i) {
7736                                 if (sps [i].il_offset < header->code_size)
7737                                         mono_bitset_set_fast (seq_point_locs, sps [i].il_offset);
7738                         }
7739                         g_free (sps);
7740                 } else if (!method->wrapper_type && !method->dynamic && mono_debug_image_has_debug_info (method->klass->image)) {
7741                         /* Methods without line number info like auto-generated property accessors */
7742                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
7743                         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);
7744                         sym_seq_points = TRUE;
7745                 }
7746         }
7747
7748         /* 
7749          * Methods without init_locals set could cause asserts in various passes
7750          * (#497220). To work around this, we emit dummy initialization opcodes
7751          * (OP_DUMMY_ICONST etc.) which generate no code. These are only supported
7752          * on some platforms.
7753          */
7754         if ((cfg->opt & MONO_OPT_UNSAFE) && ARCH_HAVE_DUMMY_INIT)
7755                 init_locals = header->init_locals;
7756         else
7757                 init_locals = TRUE;
7758
7759         method_definition = method;
7760         while (method_definition->is_inflated) {
7761                 MonoMethodInflated *imethod = (MonoMethodInflated *) method_definition;
7762                 method_definition = imethod->declaring;
7763         }
7764
7765         /* SkipVerification is not allowed if core-clr is enabled */
7766         if (!dont_verify && mini_assembly_can_skip_verification (cfg->domain, method)) {
7767                 dont_verify = TRUE;
7768                 dont_verify_stloc = TRUE;
7769         }
7770
7771         if (sig->is_inflated)
7772                 generic_context = mono_method_get_context (method);
7773         else if (generic_container)
7774                 generic_context = &generic_container->context;
7775         cfg->generic_context = generic_context;
7776
7777         if (!cfg->gshared)
7778                 g_assert (!sig->has_type_parameters);
7779
7780         if (sig->generic_param_count && method->wrapper_type == MONO_WRAPPER_NONE) {
7781                 g_assert (method->is_inflated);
7782                 g_assert (mono_method_get_context (method)->method_inst);
7783         }
7784         if (method->is_inflated && mono_method_get_context (method)->method_inst)
7785                 g_assert (sig->generic_param_count);
7786
7787         if (cfg->method == method) {
7788                 cfg->real_offset = 0;
7789         } else {
7790                 cfg->real_offset = inline_offset;
7791         }
7792
7793         cfg->cil_offset_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoBasicBlock*) * header->code_size);
7794         cfg->cil_offset_to_bb_len = header->code_size;
7795
7796         cfg->current_method = method;
7797
7798         if (cfg->verbose_level > 2)
7799                 printf ("method to IR %s\n", mono_method_full_name (method, TRUE));
7800
7801         param_types = mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * num_args);
7802         if (sig->hasthis)
7803                 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
7804         for (n = 0; n < sig->param_count; ++n)
7805                 param_types [n + sig->hasthis] = sig->params [n];
7806         cfg->arg_types = param_types;
7807
7808         cfg->dont_inline = g_list_prepend (cfg->dont_inline, method);
7809         if (cfg->method == method) {
7810
7811                 if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
7812                         cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
7813
7814                 /* ENTRY BLOCK */
7815                 NEW_BBLOCK (cfg, start_bblock);
7816                 cfg->bb_entry = start_bblock;
7817                 start_bblock->cil_code = NULL;
7818                 start_bblock->cil_length = 0;
7819
7820                 /* EXIT BLOCK */
7821                 NEW_BBLOCK (cfg, end_bblock);
7822                 cfg->bb_exit = end_bblock;
7823                 end_bblock->cil_code = NULL;
7824                 end_bblock->cil_length = 0;
7825                 end_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
7826                 g_assert (cfg->num_bblocks == 2);
7827
7828                 arg_array = cfg->args;
7829
7830                 if (header->num_clauses) {
7831                         cfg->spvars = g_hash_table_new (NULL, NULL);
7832                         cfg->exvars = g_hash_table_new (NULL, NULL);
7833                 }
7834                 /* handle exception clauses */
7835                 for (i = 0; i < header->num_clauses; ++i) {
7836                         MonoBasicBlock *try_bb;
7837                         MonoExceptionClause *clause = &header->clauses [i];
7838                         GET_BBLOCK (cfg, try_bb, ip + clause->try_offset);
7839                         try_bb->real_offset = clause->try_offset;
7840                         try_bb->try_start = TRUE;
7841                         try_bb->region = ((i + 1) << 8) | clause->flags;
7842                         GET_BBLOCK (cfg, tblock, ip + clause->handler_offset);
7843                         tblock->real_offset = clause->handler_offset;
7844                         tblock->flags |= BB_EXCEPTION_HANDLER;
7845
7846                         /*
7847                          * Linking the try block with the EH block hinders inlining as we won't be able to 
7848                          * merge the bblocks from inlining and produce an artificial hole for no good reason.
7849                          */
7850                         if (COMPILE_LLVM (cfg))
7851                                 link_bblock (cfg, try_bb, tblock);
7852
7853                         if (*(ip + clause->handler_offset) == CEE_POP)
7854                                 tblock->flags |= BB_EXCEPTION_DEAD_OBJ;
7855
7856                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
7857                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER ||
7858                             clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
7859                                 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
7860                                 MONO_ADD_INS (tblock, ins);
7861
7862                                 if (seq_points && clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY && clause->flags != MONO_EXCEPTION_CLAUSE_FILTER) {
7863                                         /* finally clauses already have a seq point */
7864                                         /* seq points for filter clauses are emitted below */
7865                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
7866                                         MONO_ADD_INS (tblock, ins);
7867                                 }
7868
7869                                 /* todo: is a fault block unsafe to optimize? */
7870                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
7871                                         tblock->flags |= BB_EXCEPTION_UNSAFE;
7872                         }
7873
7874                         /*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);
7875                           while (p < end) {
7876                           printf ("%s", mono_disasm_code_one (NULL, method, p, &p));
7877                           }*/
7878                         /* catch and filter blocks get the exception object on the stack */
7879                         if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
7880                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
7881
7882                                 /* mostly like handle_stack_args (), but just sets the input args */
7883                                 /* printf ("handling clause at IL_%04x\n", clause->handler_offset); */
7884                                 tblock->in_scount = 1;
7885                                 tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
7886                                 tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
7887
7888                                 cfg->cbb = tblock;
7889
7890 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
7891                                 /* The EH code passes in the exception in a register to both JITted and LLVM compiled code */
7892                                 if (!cfg->compile_llvm) {
7893                                         MONO_INST_NEW (cfg, ins, OP_GET_EX_OBJ);
7894                                         ins->dreg = tblock->in_stack [0]->dreg;
7895                                         MONO_ADD_INS (tblock, ins);
7896                                 }
7897 #else
7898                                 MonoInst *dummy_use;
7899
7900                                 /* 
7901                                  * Add a dummy use for the exvar so its liveness info will be
7902                                  * correct.
7903                                  */
7904                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, tblock->in_stack [0]);
7905 #endif
7906
7907                                 if (seq_points && clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
7908                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
7909                                         MONO_ADD_INS (tblock, ins);
7910                                 }
7911                                 
7912                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
7913                                         GET_BBLOCK (cfg, tblock, ip + clause->data.filter_offset);
7914                                         tblock->flags |= BB_EXCEPTION_HANDLER;
7915                                         tblock->real_offset = clause->data.filter_offset;
7916                                         tblock->in_scount = 1;
7917                                         tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
7918                                         /* The filter block shares the exvar with the handler block */
7919                                         tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
7920                                         MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
7921                                         MONO_ADD_INS (tblock, ins);
7922                                 }
7923                         }
7924
7925                         if (clause->flags != MONO_EXCEPTION_CLAUSE_FILTER &&
7926                                         clause->data.catch_class &&
7927                                         cfg->gshared &&
7928                                         mono_class_check_context_used (clause->data.catch_class)) {
7929                                 /*
7930                                  * In shared generic code with catch
7931                                  * clauses containing type variables
7932                                  * the exception handling code has to
7933                                  * be able to get to the rgctx.
7934                                  * Therefore we have to make sure that
7935                                  * the vtable/mrgctx argument (for
7936                                  * static or generic methods) or the
7937                                  * "this" argument (for non-static
7938                                  * methods) are live.
7939                                  */
7940                                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
7941                                                 mini_method_get_context (method)->method_inst ||
7942                                                 method->klass->valuetype) {
7943                                         mono_get_vtable_var (cfg);
7944                                 } else {
7945                                         MonoInst *dummy_use;
7946
7947                                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, arg_array [0]);
7948                                 }
7949                         }
7950                 }
7951         } else {
7952                 arg_array = (MonoInst **) alloca (sizeof (MonoInst *) * num_args);
7953                 cfg->cbb = start_bblock;
7954                 cfg->args = arg_array;
7955                 mono_save_args (cfg, sig, inline_args);
7956         }
7957
7958         /* FIRST CODE BLOCK */
7959         NEW_BBLOCK (cfg, tblock);
7960         tblock->cil_code = ip;
7961         cfg->cbb = tblock;
7962         cfg->ip = ip;
7963
7964         ADD_BBLOCK (cfg, tblock);
7965
7966         if (cfg->method == method) {
7967                 breakpoint_id = mono_debugger_method_has_breakpoint (method);
7968                 if (breakpoint_id) {
7969                         MONO_INST_NEW (cfg, ins, OP_BREAK);
7970                         MONO_ADD_INS (cfg->cbb, ins);
7971                 }
7972         }
7973
7974         /* we use a separate basic block for the initialization code */
7975         NEW_BBLOCK (cfg, init_localsbb);
7976         cfg->bb_init = init_localsbb;
7977         init_localsbb->real_offset = cfg->real_offset;
7978         start_bblock->next_bb = init_localsbb;
7979         init_localsbb->next_bb = cfg->cbb;
7980         link_bblock (cfg, start_bblock, init_localsbb);
7981         link_bblock (cfg, init_localsbb, cfg->cbb);
7982                 
7983         cfg->cbb = init_localsbb;
7984
7985         if (cfg->gsharedvt && cfg->method == method) {
7986                 MonoGSharedVtMethodInfo *info;
7987                 MonoInst *var, *locals_var;
7988                 int dreg;
7989
7990                 info = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoGSharedVtMethodInfo));
7991                 info->method = cfg->method;
7992                 info->count_entries = 16;
7993                 info->entries = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
7994                 cfg->gsharedvt_info = info;
7995
7996                 var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
7997                 /* prevent it from being register allocated */
7998                 //var->flags |= MONO_INST_VOLATILE;
7999                 cfg->gsharedvt_info_var = var;
8000
8001                 ins = emit_get_rgctx_gsharedvt_method (cfg, mini_method_check_context_used (cfg, method), method, info);
8002                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, var->dreg, ins->dreg);
8003
8004                 /* Allocate locals */
8005                 locals_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8006                 /* prevent it from being register allocated */
8007                 //locals_var->flags |= MONO_INST_VOLATILE;
8008                 cfg->gsharedvt_locals_var = locals_var;
8009
8010                 dreg = alloc_ireg (cfg);
8011                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, dreg, var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, locals_size));
8012
8013                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
8014                 ins->dreg = locals_var->dreg;
8015                 ins->sreg1 = dreg;
8016                 MONO_ADD_INS (cfg->cbb, ins);
8017                 cfg->gsharedvt_locals_var_ins = ins;
8018                 
8019                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
8020                 /*
8021                 if (init_locals)
8022                         ins->flags |= MONO_INST_INIT;
8023                 */
8024         }
8025
8026         if (mono_security_core_clr_enabled ()) {
8027                 /* check if this is native code, e.g. an icall or a p/invoke */
8028                 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
8029                         MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
8030                         if (wrapped) {
8031                                 gboolean pinvk = (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL);
8032                                 gboolean icall = (wrapped->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL);
8033
8034                                 /* if this ia a native call then it can only be JITted from platform code */
8035                                 if ((icall || pinvk) && method->klass && method->klass->image) {
8036                                         if (!mono_security_core_clr_is_platform_image (method->klass->image)) {
8037                                                 MonoException *ex = icall ? mono_get_exception_security () : 
8038                                                         mono_get_exception_method_access ();
8039                                                 emit_throw_exception (cfg, ex);
8040                                         }
8041                                 }
8042                         }
8043                 }
8044         }
8045
8046         CHECK_CFG_EXCEPTION;
8047
8048         if (header->code_size == 0)
8049                 UNVERIFIED;
8050
8051         if (get_basic_blocks (cfg, header, cfg->real_offset, ip, end, &err_pos)) {
8052                 ip = err_pos;
8053                 UNVERIFIED;
8054         }
8055
8056         if (cfg->method == method)
8057                 mono_debug_init_method (cfg, cfg->cbb, breakpoint_id);
8058
8059         for (n = 0; n < header->num_locals; ++n) {
8060                 if (header->locals [n]->type == MONO_TYPE_VOID && !header->locals [n]->byref)
8061                         UNVERIFIED;
8062         }
8063         class_inits = NULL;
8064
8065         /* We force the vtable variable here for all shared methods
8066            for the possibility that they might show up in a stack
8067            trace where their exact instantiation is needed. */
8068         if (cfg->gshared && method == cfg->method) {
8069                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
8070                                 mini_method_get_context (method)->method_inst ||
8071                                 method->klass->valuetype) {
8072                         mono_get_vtable_var (cfg);
8073                 } else {
8074                         /* FIXME: Is there a better way to do this?
8075                            We need the variable live for the duration
8076                            of the whole method. */
8077                         cfg->args [0]->flags |= MONO_INST_VOLATILE;
8078                 }
8079         }
8080
8081         /* add a check for this != NULL to inlined methods */
8082         if (is_virtual_call) {
8083                 MonoInst *arg_ins;
8084
8085                 NEW_ARGLOAD (cfg, arg_ins, 0);
8086                 MONO_ADD_INS (cfg->cbb, arg_ins);
8087                 MONO_EMIT_NEW_CHECK_THIS (cfg, arg_ins->dreg);
8088         }
8089
8090         skip_dead_blocks = !dont_verify;
8091         if (skip_dead_blocks) {
8092                 original_bb = bb = mono_basic_block_split (method, &cfg->error);
8093                 CHECK_CFG_ERROR;
8094                 g_assert (bb);
8095         }
8096
8097         /* we use a spare stack slot in SWITCH and NEWOBJ and others */
8098         stack_start = sp = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
8099
8100         ins_flag = 0;
8101         start_new_bblock = 0;
8102         while (ip < end) {
8103                 if (cfg->method == method)
8104                         cfg->real_offset = ip - header->code;
8105                 else
8106                         cfg->real_offset = inline_offset;
8107                 cfg->ip = ip;
8108
8109                 context_used = 0;
8110
8111                 if (start_new_bblock) {
8112                         cfg->cbb->cil_length = ip - cfg->cbb->cil_code;
8113                         if (start_new_bblock == 2) {
8114                                 g_assert (ip == tblock->cil_code);
8115                         } else {
8116                                 GET_BBLOCK (cfg, tblock, ip);
8117                         }
8118                         cfg->cbb->next_bb = tblock;
8119                         cfg->cbb = tblock;
8120                         start_new_bblock = 0;
8121                         for (i = 0; i < cfg->cbb->in_scount; ++i) {
8122                                 if (cfg->verbose_level > 3)
8123                                         printf ("loading %d from temp %d\n", i, (int)cfg->cbb->in_stack [i]->inst_c0);
8124                                 EMIT_NEW_TEMPLOAD (cfg, ins, cfg->cbb->in_stack [i]->inst_c0);
8125                                 *sp++ = ins;
8126                         }
8127                         if (class_inits)
8128                                 g_slist_free (class_inits);
8129                         class_inits = NULL;
8130                 } else {
8131                         if ((tblock = cfg->cil_offset_to_bb [ip - cfg->cil_start]) && (tblock != cfg->cbb)) {
8132                                 link_bblock (cfg, cfg->cbb, tblock);
8133                                 if (sp != stack_start) {
8134                                         handle_stack_args (cfg, stack_start, sp - stack_start);
8135                                         sp = stack_start;
8136                                         CHECK_UNVERIFIABLE (cfg);
8137                                 }
8138                                 cfg->cbb->next_bb = tblock;
8139                                 cfg->cbb = tblock;
8140                                 for (i = 0; i < cfg->cbb->in_scount; ++i) {
8141                                         if (cfg->verbose_level > 3)
8142                                                 printf ("loading %d from temp %d\n", i, (int)cfg->cbb->in_stack [i]->inst_c0);
8143                                         EMIT_NEW_TEMPLOAD (cfg, ins, cfg->cbb->in_stack [i]->inst_c0);
8144                                         *sp++ = ins;
8145                                 }
8146                                 g_slist_free (class_inits);
8147                                 class_inits = NULL;
8148                         }
8149                 }
8150
8151                 if (skip_dead_blocks) {
8152                         int ip_offset = ip - header->code;
8153
8154                         if (ip_offset == bb->end)
8155                                 bb = bb->next;
8156
8157                         if (bb->dead) {
8158                                 int op_size = mono_opcode_size (ip, end);
8159                                 g_assert (op_size > 0); /*The BB formation pass must catch all bad ops*/
8160
8161                                 if (cfg->verbose_level > 3) printf ("SKIPPING DEAD OP at %x\n", ip_offset);
8162
8163                                 if (ip_offset + op_size == bb->end) {
8164                                         MONO_INST_NEW (cfg, ins, OP_NOP);
8165                                         MONO_ADD_INS (cfg->cbb, ins);
8166                                         start_new_bblock = 1;
8167                                 }
8168
8169                                 ip += op_size;
8170                                 continue;
8171                         }
8172                 }
8173                 /*
8174                  * Sequence points are points where the debugger can place a breakpoint.
8175                  * Currently, we generate these automatically at points where the IL
8176                  * stack is empty.
8177                  */
8178                 if (seq_points && ((!sym_seq_points && (sp == stack_start)) || (sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code)))) {
8179                         /*
8180                          * Make methods interruptable at the beginning, and at the targets of
8181                          * backward branches.
8182                          * Also, do this at the start of every bblock in methods with clauses too,
8183                          * to be able to handle instructions with inprecise control flow like
8184                          * throw/endfinally.
8185                          * Backward branches are handled at the end of method-to-ir ().
8186                          */
8187                         gboolean intr_loc = ip == header->code || (!cfg->cbb->last_ins && cfg->header->num_clauses);
8188                         gboolean sym_seq_point = sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code);
8189
8190                         /* Avoid sequence points on empty IL like .volatile */
8191                         // FIXME: Enable this
8192                         //if (!(cfg->cbb->last_ins && cfg->cbb->last_ins->opcode == OP_SEQ_POINT)) {
8193                         NEW_SEQ_POINT (cfg, ins, ip - header->code, intr_loc);
8194                         if ((sp != stack_start) && !sym_seq_point)
8195                                 ins->flags |= MONO_INST_NONEMPTY_STACK;
8196                         MONO_ADD_INS (cfg->cbb, ins);
8197
8198                         if (sym_seq_points)
8199                                 mono_bitset_set_fast (seq_point_set_locs, ip - header->code);
8200                 }
8201
8202                 cfg->cbb->real_offset = cfg->real_offset;
8203
8204                 if ((cfg->method == method) && cfg->coverage_info) {
8205                         guint32 cil_offset = ip - header->code;
8206                         cfg->coverage_info->data [cil_offset].cil_code = ip;
8207
8208                         /* TODO: Use an increment here */
8209 #if defined(TARGET_X86)
8210                         MONO_INST_NEW (cfg, ins, OP_STORE_MEM_IMM);
8211                         ins->inst_p0 = &(cfg->coverage_info->data [cil_offset].count);
8212                         ins->inst_imm = 1;
8213                         MONO_ADD_INS (cfg->cbb, ins);
8214 #else
8215                         EMIT_NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
8216                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, ins->dreg, 0, 1);
8217 #endif
8218                 }
8219
8220                 if (cfg->verbose_level > 3)
8221                         printf ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
8222
8223                 switch (*ip) {
8224                 case CEE_NOP:
8225                         if (seq_points && !sym_seq_points && sp != stack_start) {
8226                                 /*
8227                                  * The C# compiler uses these nops to notify the JIT that it should
8228                                  * insert seq points.
8229                                  */
8230                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, FALSE);
8231                                 MONO_ADD_INS (cfg->cbb, ins);
8232                         }
8233                         if (cfg->keep_cil_nops)
8234                                 MONO_INST_NEW (cfg, ins, OP_HARD_NOP);
8235                         else
8236                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8237                         ip++;
8238                         MONO_ADD_INS (cfg->cbb, ins);
8239                         break;
8240                 case CEE_BREAK:
8241                         if (should_insert_brekpoint (cfg->method)) {
8242                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
8243                         } else {
8244                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8245                         }
8246                         ip++;
8247                         MONO_ADD_INS (cfg->cbb, ins);
8248                         break;
8249                 case CEE_LDARG_0:
8250                 case CEE_LDARG_1:
8251                 case CEE_LDARG_2:
8252                 case CEE_LDARG_3:
8253                         CHECK_STACK_OVF (1);
8254                         n = (*ip)-CEE_LDARG_0;
8255                         CHECK_ARG (n);
8256                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8257                         ip++;
8258                         *sp++ = ins;
8259                         break;
8260                 case CEE_LDLOC_0:
8261                 case CEE_LDLOC_1:
8262                 case CEE_LDLOC_2:
8263                 case CEE_LDLOC_3:
8264                         CHECK_STACK_OVF (1);
8265                         n = (*ip)-CEE_LDLOC_0;
8266                         CHECK_LOCAL (n);
8267                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8268                         ip++;
8269                         *sp++ = ins;
8270                         break;
8271                 case CEE_STLOC_0:
8272                 case CEE_STLOC_1:
8273                 case CEE_STLOC_2:
8274                 case CEE_STLOC_3: {
8275                         CHECK_STACK (1);
8276                         n = (*ip)-CEE_STLOC_0;
8277                         CHECK_LOCAL (n);
8278                         --sp;
8279                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
8280                                 UNVERIFIED;
8281                         emit_stloc_ir (cfg, sp, header, n);
8282                         ++ip;
8283                         inline_costs += 1;
8284                         break;
8285                         }
8286                 case CEE_LDARG_S:
8287                         CHECK_OPSIZE (2);
8288                         CHECK_STACK_OVF (1);
8289                         n = ip [1];
8290                         CHECK_ARG (n);
8291                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8292                         *sp++ = ins;
8293                         ip += 2;
8294                         break;
8295                 case CEE_LDARGA_S:
8296                         CHECK_OPSIZE (2);
8297                         CHECK_STACK_OVF (1);
8298                         n = ip [1];
8299                         CHECK_ARG (n);
8300                         NEW_ARGLOADA (cfg, ins, n);
8301                         MONO_ADD_INS (cfg->cbb, ins);
8302                         *sp++ = ins;
8303                         ip += 2;
8304                         break;
8305                 case CEE_STARG_S:
8306                         CHECK_OPSIZE (2);
8307                         CHECK_STACK (1);
8308                         --sp;
8309                         n = ip [1];
8310                         CHECK_ARG (n);
8311                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [ip [1]], *sp))
8312                                 UNVERIFIED;
8313                         EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
8314                         ip += 2;
8315                         break;
8316                 case CEE_LDLOC_S:
8317                         CHECK_OPSIZE (2);
8318                         CHECK_STACK_OVF (1);
8319                         n = ip [1];
8320                         CHECK_LOCAL (n);
8321                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8322                         *sp++ = ins;
8323                         ip += 2;
8324                         break;
8325                 case CEE_LDLOCA_S: {
8326                         unsigned char *tmp_ip;
8327                         CHECK_OPSIZE (2);
8328                         CHECK_STACK_OVF (1);
8329                         CHECK_LOCAL (ip [1]);
8330
8331                         if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 1))) {
8332                                 ip = tmp_ip;
8333                                 inline_costs += 1;
8334                                 break;
8335                         }
8336
8337                         EMIT_NEW_LOCLOADA (cfg, ins, ip [1]);
8338                         *sp++ = ins;
8339                         ip += 2;
8340                         break;
8341                 }
8342                 case CEE_STLOC_S:
8343                         CHECK_OPSIZE (2);
8344                         CHECK_STACK (1);
8345                         --sp;
8346                         CHECK_LOCAL (ip [1]);
8347                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [ip [1]], *sp))
8348                                 UNVERIFIED;
8349                         emit_stloc_ir (cfg, sp, header, ip [1]);
8350                         ip += 2;
8351                         inline_costs += 1;
8352                         break;
8353                 case CEE_LDNULL:
8354                         CHECK_STACK_OVF (1);
8355                         EMIT_NEW_PCONST (cfg, ins, NULL);
8356                         ins->type = STACK_OBJ;
8357                         ++ip;
8358                         *sp++ = ins;
8359                         break;
8360                 case CEE_LDC_I4_M1:
8361                         CHECK_STACK_OVF (1);
8362                         EMIT_NEW_ICONST (cfg, ins, -1);
8363                         ++ip;
8364                         *sp++ = ins;
8365                         break;
8366                 case CEE_LDC_I4_0:
8367                 case CEE_LDC_I4_1:
8368                 case CEE_LDC_I4_2:
8369                 case CEE_LDC_I4_3:
8370                 case CEE_LDC_I4_4:
8371                 case CEE_LDC_I4_5:
8372                 case CEE_LDC_I4_6:
8373                 case CEE_LDC_I4_7:
8374                 case CEE_LDC_I4_8:
8375                         CHECK_STACK_OVF (1);
8376                         EMIT_NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
8377                         ++ip;
8378                         *sp++ = ins;
8379                         break;
8380                 case CEE_LDC_I4_S:
8381                         CHECK_OPSIZE (2);
8382                         CHECK_STACK_OVF (1);
8383                         ++ip;
8384                         EMIT_NEW_ICONST (cfg, ins, *((signed char*)ip));
8385                         ++ip;
8386                         *sp++ = ins;
8387                         break;
8388                 case CEE_LDC_I4:
8389                         CHECK_OPSIZE (5);
8390                         CHECK_STACK_OVF (1);
8391                         EMIT_NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
8392                         ip += 5;
8393                         *sp++ = ins;
8394                         break;
8395                 case CEE_LDC_I8:
8396                         CHECK_OPSIZE (9);
8397                         CHECK_STACK_OVF (1);
8398                         MONO_INST_NEW (cfg, ins, OP_I8CONST);
8399                         ins->type = STACK_I8;
8400                         ins->dreg = alloc_dreg (cfg, STACK_I8);
8401                         ++ip;
8402                         ins->inst_l = (gint64)read64 (ip);
8403                         MONO_ADD_INS (cfg->cbb, ins);
8404                         ip += 8;
8405                         *sp++ = ins;
8406                         break;
8407                 case CEE_LDC_R4: {
8408                         float *f;
8409                         gboolean use_aotconst = FALSE;
8410
8411 #ifdef TARGET_POWERPC
8412                         /* FIXME: Clean this up */
8413                         if (cfg->compile_aot)
8414                                 use_aotconst = TRUE;
8415 #endif
8416
8417                         /* FIXME: we should really allocate this only late in the compilation process */
8418                         f = mono_domain_alloc (cfg->domain, sizeof (float));
8419                         CHECK_OPSIZE (5);
8420                         CHECK_STACK_OVF (1);
8421
8422                         if (use_aotconst) {
8423                                 MonoInst *cons;
8424                                 int dreg;
8425
8426                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R4, f);
8427
8428                                 dreg = alloc_freg (cfg);
8429                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR4_MEMBASE, dreg, cons->dreg, 0);
8430                                 ins->type = cfg->r4_stack_type;
8431                         } else {
8432                                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
8433                                 ins->type = cfg->r4_stack_type;
8434                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8435                                 ins->inst_p0 = f;
8436                                 MONO_ADD_INS (cfg->cbb, ins);
8437                         }
8438                         ++ip;
8439                         readr4 (ip, f);
8440                         ip += 4;
8441                         *sp++ = ins;                    
8442                         break;
8443                 }
8444                 case CEE_LDC_R8: {
8445                         double *d;
8446                         gboolean use_aotconst = FALSE;
8447
8448 #ifdef TARGET_POWERPC
8449                         /* FIXME: Clean this up */
8450                         if (cfg->compile_aot)
8451                                 use_aotconst = TRUE;
8452 #endif
8453
8454                         /* FIXME: we should really allocate this only late in the compilation process */
8455                         d = mono_domain_alloc (cfg->domain, sizeof (double));
8456                         CHECK_OPSIZE (9);
8457                         CHECK_STACK_OVF (1);
8458
8459                         if (use_aotconst) {
8460                                 MonoInst *cons;
8461                                 int dreg;
8462
8463                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R8, d);
8464
8465                                 dreg = alloc_freg (cfg);
8466                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR8_MEMBASE, dreg, cons->dreg, 0);
8467                                 ins->type = STACK_R8;
8468                         } else {
8469                                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
8470                                 ins->type = STACK_R8;
8471                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8472                                 ins->inst_p0 = d;
8473                                 MONO_ADD_INS (cfg->cbb, ins);
8474                         }
8475                         ++ip;
8476                         readr8 (ip, d);
8477                         ip += 8;
8478                         *sp++ = ins;
8479                         break;
8480                 }
8481                 case CEE_DUP: {
8482                         MonoInst *temp, *store;
8483                         CHECK_STACK (1);
8484                         CHECK_STACK_OVF (1);
8485                         sp--;
8486                         ins = *sp;
8487
8488                         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
8489                         EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
8490
8491                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8492                         *sp++ = ins;
8493
8494                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8495                         *sp++ = ins;
8496
8497                         ++ip;
8498                         inline_costs += 2;
8499                         break;
8500                 }
8501                 case CEE_POP:
8502                         CHECK_STACK (1);
8503                         ip++;
8504                         --sp;
8505
8506 #ifdef TARGET_X86
8507                         if (sp [0]->type == STACK_R8)
8508                                 /* we need to pop the value from the x86 FP stack */
8509                                 MONO_EMIT_NEW_UNALU (cfg, OP_X86_FPOP, -1, sp [0]->dreg);
8510 #endif
8511                         break;
8512                 case CEE_JMP: {
8513                         MonoCallInst *call;
8514
8515                         INLINE_FAILURE ("jmp");
8516                         GSHAREDVT_FAILURE (*ip);
8517
8518                         CHECK_OPSIZE (5);
8519                         if (stack_start != sp)
8520                                 UNVERIFIED;
8521                         token = read32 (ip + 1);
8522                         /* FIXME: check the signature matches */
8523                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
8524
8525                         if (!cmethod || mono_loader_get_last_error ())
8526                                 LOAD_ERROR;
8527  
8528                         if (cfg->gshared && mono_method_check_context_used (cmethod))
8529                                 GENERIC_SHARING_FAILURE (CEE_JMP);
8530
8531                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
8532
8533                         if (ARCH_HAVE_OP_TAIL_CALL) {
8534                                 MonoMethodSignature *fsig = mono_method_signature (cmethod);
8535                                 int i, n;
8536
8537                                 /* Handle tail calls similarly to calls */
8538                                 n = fsig->param_count + fsig->hasthis;
8539
8540                                 DISABLE_AOT (cfg);
8541
8542                                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
8543                                 call->method = cmethod;
8544                                 call->tail_call = TRUE;
8545                                 call->signature = mono_method_signature (cmethod);
8546                                 call->args = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
8547                                 call->inst.inst_p0 = cmethod;
8548                                 for (i = 0; i < n; ++i)
8549                                         EMIT_NEW_ARGLOAD (cfg, call->args [i], i);
8550
8551                                 mono_arch_emit_call (cfg, call);
8552                                 cfg->param_area = MAX(cfg->param_area, call->stack_usage);
8553                                 MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
8554                         } else {
8555                                 for (i = 0; i < num_args; ++i)
8556                                         /* Prevent arguments from being optimized away */
8557                                         arg_array [i]->flags |= MONO_INST_VOLATILE;
8558
8559                                 MONO_INST_NEW_CALL (cfg, call, OP_JMP);
8560                                 ins = (MonoInst*)call;
8561                                 ins->inst_p0 = cmethod;
8562                                 MONO_ADD_INS (cfg->cbb, ins);
8563                         }
8564
8565                         ip += 5;
8566                         start_new_bblock = 1;
8567                         break;
8568                 }
8569                 case CEE_CALLI: {
8570                         MonoInst *addr;
8571                         MonoMethodSignature *fsig;
8572
8573                         CHECK_OPSIZE (5);
8574                         token = read32 (ip + 1);
8575
8576                         ins = NULL;
8577
8578                         //GSHAREDVT_FAILURE (*ip);
8579                         cmethod = NULL;
8580                         CHECK_STACK (1);
8581                         --sp;
8582                         addr = *sp;
8583                         fsig = mini_get_signature (method, token, generic_context);
8584
8585                         if (method->dynamic && fsig->pinvoke) {
8586                                 MonoInst *args [3];
8587
8588                                 /*
8589                                  * This is a call through a function pointer using a pinvoke
8590                                  * signature. Have to create a wrapper and call that instead.
8591                                  * FIXME: This is very slow, need to create a wrapper at JIT time
8592                                  * instead based on the signature.
8593                                  */
8594                                 EMIT_NEW_IMAGECONST (cfg, args [0], method->klass->image);
8595                                 EMIT_NEW_PCONST (cfg, args [1], fsig);
8596                                 args [2] = addr;
8597                                 addr = mono_emit_jit_icall (cfg, mono_get_native_calli_wrapper, args);
8598                         }
8599
8600                         n = fsig->param_count + fsig->hasthis;
8601
8602                         CHECK_STACK (n);
8603
8604                         //g_assert (!virtual || fsig->hasthis);
8605
8606                         sp -= n;
8607
8608                         inline_costs += 10 * num_calls++;
8609
8610                         /*
8611                          * Making generic calls out of gsharedvt methods.
8612                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
8613                          * patching gshared method addresses into a gsharedvt method.
8614                          */
8615                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
8616                                 /*
8617                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
8618                                  */
8619                                 MonoInst *callee = addr;
8620
8621                                 if (method->wrapper_type != MONO_WRAPPER_DELEGATE_INVOKE)
8622                                         /* Not tested */
8623                                         GSHAREDVT_FAILURE (*ip);
8624
8625                                 addr = emit_get_rgctx_sig (cfg, context_used,
8626                                                                                           fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
8627                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
8628                                 goto calli_end;
8629                         }
8630
8631                         /* Prevent inlining of methods with indirect calls */
8632                         INLINE_FAILURE ("indirect call");
8633
8634                         if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST || addr->opcode == OP_GOT_ENTRY) {
8635                                 int info_type;
8636                                 gpointer info_data;
8637
8638                                 /*
8639                                  * Instead of emitting an indirect call, emit a direct call
8640                                  * with the contents of the aotconst as the patch info.
8641                                  */
8642                                 if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST) {
8643                                         info_type = addr->inst_c1;
8644                                         info_data = addr->inst_p0;
8645                                 } else {
8646                                         info_type = addr->inst_right->inst_c1;
8647                                         info_data = addr->inst_right->inst_left;
8648                                 }
8649
8650                                 if (info_type == MONO_PATCH_INFO_ICALL_ADDR || info_type == MONO_PATCH_INFO_JIT_ICALL_ADDR) {
8651                                         ins = (MonoInst*)mono_emit_abs_call (cfg, info_type, info_data, fsig, sp);
8652                                         NULLIFY_INS (addr);
8653                                         goto calli_end;
8654                                 }
8655                         }
8656                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8657
8658                         calli_end:
8659
8660                         /* End of call, INS should contain the result of the call, if any */
8661
8662                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8663                                 g_assert (ins);
8664                                 *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
8665                         }
8666
8667                         CHECK_CFG_EXCEPTION;
8668
8669                         ip += 5;
8670                         ins_flag = 0;
8671                         constrained_class = NULL;
8672                         break;
8673                 }
8674                 case CEE_CALL:
8675                 case CEE_CALLVIRT: {
8676                         MonoInst *addr = NULL;
8677                         MonoMethodSignature *fsig = NULL;
8678                         int array_rank = 0;
8679                         int virtual = *ip == CEE_CALLVIRT;
8680                         gboolean pass_imt_from_rgctx = FALSE;
8681                         MonoInst *imt_arg = NULL;
8682                         MonoInst *keep_this_alive = NULL;
8683                         gboolean pass_vtable = FALSE;
8684                         gboolean pass_mrgctx = FALSE;
8685                         MonoInst *vtable_arg = NULL;
8686                         gboolean check_this = FALSE;
8687                         gboolean supported_tail_call = FALSE;
8688                         gboolean tail_call = FALSE;
8689                         gboolean need_seq_point = FALSE;
8690                         guint32 call_opcode = *ip;
8691                         gboolean emit_widen = TRUE;
8692                         gboolean push_res = TRUE;
8693                         gboolean skip_ret = FALSE;
8694                         gboolean delegate_invoke = FALSE;
8695                         gboolean direct_icall = FALSE;
8696                         gboolean constrained_partial_call = FALSE;
8697                         MonoMethod *cil_method;
8698
8699                         CHECK_OPSIZE (5);
8700                         token = read32 (ip + 1);
8701
8702                         ins = NULL;
8703
8704                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
8705                         cil_method = cmethod;
8706                                 
8707                         if (constrained_class) {
8708                                 if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->gshared) {
8709                                         if (!mini_is_gsharedvt_klass (constrained_class)) {
8710                                                 g_assert (!cmethod->klass->valuetype);
8711                                                 if (!mini_type_is_reference (&constrained_class->byval_arg))
8712                                                         constrained_partial_call = TRUE;
8713                                         }
8714                                 }
8715
8716                                 if (method->wrapper_type != MONO_WRAPPER_NONE) {
8717                                         if (cfg->verbose_level > 2)
8718                                                 printf ("DM Constrained call to %s\n", mono_type_get_full_name (constrained_class));
8719                                         if (!((constrained_class->byval_arg.type == MONO_TYPE_VAR ||
8720                                                    constrained_class->byval_arg.type == MONO_TYPE_MVAR) &&
8721                                                   cfg->gshared)) {
8722                                                 cmethod = mono_get_method_constrained_with_method (image, cil_method, constrained_class, generic_context, &cfg->error);
8723                                                 CHECK_CFG_ERROR;
8724                                         }
8725                                 } else {
8726                                         if (cfg->verbose_level > 2)
8727                                                 printf ("Constrained call to %s\n", mono_type_get_full_name (constrained_class));
8728
8729                                         if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->gshared) {
8730                                                 /* 
8731                                                  * This is needed since get_method_constrained can't find 
8732                                                  * the method in klass representing a type var.
8733                                                  * The type var is guaranteed to be a reference type in this
8734                                                  * case.
8735                                                  */
8736                                                 if (!mini_is_gsharedvt_klass (constrained_class))
8737                                                         g_assert (!cmethod->klass->valuetype);
8738                                         } else {
8739                                                 cmethod = mono_get_method_constrained_checked (image, token, constrained_class, generic_context, &cil_method, &cfg->error);
8740                                                 CHECK_CFG_ERROR;
8741                                         }
8742                                 }
8743                         }
8744                                         
8745                         if (!cmethod || mono_loader_get_last_error ())
8746                                 LOAD_ERROR;
8747                         if (!dont_verify && !cfg->skip_visibility) {
8748                                 MonoMethod *target_method = cil_method;
8749                                 if (method->is_inflated) {
8750                                         target_method = mini_get_method_allow_open (method, token, NULL, &(mono_method_get_generic_container (method_definition)->context));
8751                                 }
8752                                 if (!mono_method_can_access_method (method_definition, target_method) &&
8753                                         !mono_method_can_access_method (method, cil_method))
8754                                         METHOD_ACCESS_FAILURE (method, cil_method);
8755                         }
8756
8757                         if (mono_security_core_clr_enabled ())
8758                                 ensure_method_is_allowed_to_call_method (cfg, method, cil_method);
8759
8760                         if (!virtual && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
8761                                 /* MS.NET seems to silently convert this to a callvirt */
8762                                 virtual = 1;
8763
8764                         {
8765                                 /*
8766                                  * MS.NET accepts non virtual calls to virtual final methods of transparent proxy classes and
8767                                  * converts to a callvirt.
8768                                  *
8769                                  * tests/bug-515884.il is an example of this behavior
8770                                  */
8771                                 const int test_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_STATIC;
8772                                 const int expected_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL;
8773                                 if (!virtual && mono_class_is_marshalbyref (cmethod->klass) && (cmethod->flags & test_flags) == expected_flags && cfg->method->wrapper_type == MONO_WRAPPER_NONE)
8774                                         virtual = 1;
8775                         }
8776
8777                         if (!cmethod->klass->inited)
8778                                 if (!mono_class_init (cmethod->klass))
8779                                         TYPE_LOAD_ERROR (cmethod->klass);
8780
8781                         fsig = mono_method_signature (cmethod);
8782                         if (!fsig)
8783                                 LOAD_ERROR;
8784                         if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
8785                                 mini_class_is_system_array (cmethod->klass)) {
8786                                 array_rank = cmethod->klass->rank;
8787                         } else if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && icall_is_direct_callable (cfg, cmethod)) {
8788                                 direct_icall = TRUE;
8789                         } else if (fsig->pinvoke) {
8790                                 MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
8791                                 fsig = mono_method_signature (wrapper);
8792                         } else if (constrained_class) {
8793                         } else {
8794                                 fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
8795                                 CHECK_CFG_ERROR;
8796                         }
8797
8798                         /* See code below */
8799                         if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
8800                                 MonoBasicBlock *tbb;
8801
8802                                 GET_BBLOCK (cfg, tbb, ip + 5);
8803                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
8804                                         /*
8805                                          * We want to extend the try block to cover the call, but we can't do it if the
8806                                          * call is made directly since its followed by an exception check.
8807                                          */
8808                                         direct_icall = FALSE;
8809                                 }
8810                         }
8811
8812                         mono_save_token_info (cfg, image, token, cil_method);
8813
8814                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip + 5 - header->code)))
8815                                 need_seq_point = TRUE;
8816
8817                         /* Don't support calls made using type arguments for now */
8818                         /*
8819                           if (cfg->gsharedvt) {
8820                           if (mini_is_gsharedvt_signature (fsig))
8821                           GSHAREDVT_FAILURE (*ip);
8822                           }
8823                         */
8824
8825                         if (cmethod->string_ctor && method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE)
8826                                 g_assert_not_reached ();
8827
8828                         n = fsig->param_count + fsig->hasthis;
8829
8830                         if (!cfg->gshared && cmethod->klass->generic_container)
8831                                 UNVERIFIED;
8832
8833                         if (!cfg->gshared)
8834                                 g_assert (!mono_method_check_context_used (cmethod));
8835
8836                         CHECK_STACK (n);
8837
8838                         //g_assert (!virtual || fsig->hasthis);
8839
8840                         sp -= n;
8841
8842                         if (constrained_class) {
8843                                 if (mini_is_gsharedvt_klass (constrained_class)) {
8844                                         if ((cmethod->klass != mono_defaults.object_class) && constrained_class->valuetype && cmethod->klass->valuetype) {
8845                                                 /* The 'Own method' case below */
8846                                         } else if (cmethod->klass->image != mono_defaults.corlib && !(cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !cmethod->klass->valuetype) {
8847                                                 /* 'The type parameter is instantiated as a reference type' case below. */
8848                                         } else {
8849                                                 ins = handle_constrained_gsharedvt_call (cfg, cmethod, fsig, sp, constrained_class, &emit_widen);
8850                                                 CHECK_CFG_EXCEPTION;
8851                                                 g_assert (ins);
8852                                                 goto call_end;
8853                                         }
8854                                 }
8855
8856                                 /*
8857                                  * We have the `constrained.' prefix opcode.
8858                                  */
8859                                 if (constrained_partial_call) {
8860                                         gboolean need_box = TRUE;
8861
8862                                         /*
8863                                          * The receiver is a valuetype, but the exact type is not known at compile time. This means the
8864                                          * called method is not known at compile time either. The called method could end up being
8865                                          * one of the methods on the parent classes (object/valuetype/enum), in which case we need
8866                                          * to box the receiver.
8867                                          * A simple solution would be to box always and make a normal virtual call, but that would
8868                                          * be bad performance wise.
8869                                          */
8870                                         if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE && cmethod->klass->generic_class) {
8871                                                 /*
8872                                                  * The parent classes implement no generic interfaces, so the called method will be a vtype method, so no boxing neccessary.
8873                                                  */
8874                                                 need_box = FALSE;
8875                                         }
8876
8877                                         if (!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) && (cmethod->klass == mono_defaults.object_class || cmethod->klass == mono_defaults.enum_class->parent || cmethod->klass == mono_defaults.enum_class)) {
8878                                                 /* The called method is not virtual, i.e. Object:GetType (), the receiver is a vtype, has to box */
8879                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
8880                                                 ins->klass = constrained_class;
8881                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
8882                                                 CHECK_CFG_EXCEPTION;
8883                                         } else if (need_box) {
8884                                                 MonoInst *box_type;
8885                                                 MonoBasicBlock *is_ref_bb, *end_bb;
8886                                                 MonoInst *nonbox_call;
8887
8888                                                 /*
8889                                                  * Determine at runtime whenever the called method is defined on object/valuetype/enum, and emit a boxing call
8890                                                  * if needed.
8891                                                  * FIXME: It is possible to inline the called method in a lot of cases, i.e. for T_INT,
8892                                                  * the no-box case goes to a method in Int32, while the box case goes to a method in Enum.
8893                                                  */
8894                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
8895
8896                                                 NEW_BBLOCK (cfg, is_ref_bb);
8897                                                 NEW_BBLOCK (cfg, end_bb);
8898
8899                                                 box_type = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE);
8900                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, box_type->dreg, 1);
8901                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
8902
8903                                                 /* Non-ref case */
8904                                                 nonbox_call = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8905
8906                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
8907
8908                                                 /* Ref case */
8909                                                 MONO_START_BB (cfg, is_ref_bb);
8910                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
8911                                                 ins->klass = constrained_class;
8912                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
8913                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8914
8915                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
8916
8917                                                 MONO_START_BB (cfg, end_bb);
8918                                                 cfg->cbb = end_bb;
8919
8920                                                 nonbox_call->dreg = ins->dreg;
8921                                                 goto call_end;
8922                                         } else {
8923                                                 g_assert (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE);
8924                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
8925                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8926                                                 goto call_end;
8927                                         }
8928                                 } else if (constrained_class->valuetype && (cmethod->klass == mono_defaults.object_class || cmethod->klass == mono_defaults.enum_class->parent || cmethod->klass == mono_defaults.enum_class)) {
8929                                         /*
8930                                          * The type parameter is instantiated as a valuetype,
8931                                          * but that type doesn't override the method we're
8932                                          * calling, so we need to box `this'.
8933                                          */
8934                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
8935                                         ins->klass = constrained_class;
8936                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
8937                                         CHECK_CFG_EXCEPTION;
8938                                 } else if (!constrained_class->valuetype) {
8939                                         int dreg = alloc_ireg_ref (cfg);
8940
8941                                         /*
8942                                          * The type parameter is instantiated as a reference
8943                                          * type.  We have a managed pointer on the stack, so
8944                                          * we need to dereference it here.
8945                                          */
8946                                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, sp [0]->dreg, 0);
8947                                         ins->type = STACK_OBJ;
8948                                         sp [0] = ins;
8949                                 } else {
8950                                         if (cmethod->klass->valuetype) {
8951                                                 /* Own method */
8952                                         } else {
8953                                                 /* Interface method */
8954                                                 int ioffset, slot;
8955
8956                                                 mono_class_setup_vtable (constrained_class);
8957                                                 CHECK_TYPELOAD (constrained_class);
8958                                                 ioffset = mono_class_interface_offset (constrained_class, cmethod->klass);
8959                                                 if (ioffset == -1)
8960                                                         TYPE_LOAD_ERROR (constrained_class);
8961                                                 slot = mono_method_get_vtable_slot (cmethod);
8962                                                 if (slot == -1)
8963                                                         TYPE_LOAD_ERROR (cmethod->klass);
8964                                                 cmethod = constrained_class->vtable [ioffset + slot];
8965
8966                                                 if (cmethod->klass == mono_defaults.enum_class) {
8967                                                         /* Enum implements some interfaces, so treat this as the first case */
8968                                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
8969                                                         ins->klass = constrained_class;
8970                                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
8971                                                         CHECK_CFG_EXCEPTION;
8972                                                 }
8973                                         }
8974                                         virtual = 0;
8975                                 }
8976                                 constrained_class = NULL;
8977                         }
8978
8979                         if (check_call_signature (cfg, fsig, sp))
8980                                 UNVERIFIED;
8981
8982                         if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (cmethod->name, "Invoke"))
8983                                 delegate_invoke = TRUE;
8984
8985                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_sharable_method (cfg, cmethod, fsig, sp))) {
8986                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8987                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
8988                                         emit_widen = FALSE;
8989                                 }
8990
8991                                 goto call_end;
8992                         }
8993
8994                         /* 
8995                          * If the callee is a shared method, then its static cctor
8996                          * might not get called after the call was patched.
8997                          */
8998                         if (cfg->gshared && cmethod->klass != method->klass && cmethod->klass->generic_class && mono_method_is_generic_sharable (cmethod, TRUE) && mono_class_needs_cctor_run (cmethod->klass, method)) {
8999                                 emit_class_init (cfg, cmethod->klass);
9000                                 CHECK_TYPELOAD (cmethod->klass);
9001                         }
9002
9003                         check_method_sharing (cfg, cmethod, &pass_vtable, &pass_mrgctx);
9004
9005                         if (cfg->gshared) {
9006                                 MonoGenericContext *cmethod_context = mono_method_get_context (cmethod);
9007
9008                                 context_used = mini_method_check_context_used (cfg, cmethod);
9009
9010                                 if (context_used && (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
9011                                         /* Generic method interface
9012                                            calls are resolved via a
9013                                            helper function and don't
9014                                            need an imt. */
9015                                         if (!cmethod_context || !cmethod_context->method_inst)
9016                                                 pass_imt_from_rgctx = TRUE;
9017                                 }
9018
9019                                 /*
9020                                  * If a shared method calls another
9021                                  * shared method then the caller must
9022                                  * have a generic sharing context
9023                                  * because the magic trampoline
9024                                  * requires it.  FIXME: We shouldn't
9025                                  * have to force the vtable/mrgctx
9026                                  * variable here.  Instead there
9027                                  * should be a flag in the cfg to
9028                                  * request a generic sharing context.
9029                                  */
9030                                 if (context_used &&
9031                                                 ((method->flags & METHOD_ATTRIBUTE_STATIC) || method->klass->valuetype))
9032                                         mono_get_vtable_var (cfg);
9033                         }
9034
9035                         if (pass_vtable) {
9036                                 if (context_used) {
9037                                         vtable_arg = emit_get_rgctx_klass (cfg, context_used, cmethod->klass, MONO_RGCTX_INFO_VTABLE);
9038                                 } else {
9039                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
9040
9041                                         CHECK_TYPELOAD (cmethod->klass);
9042                                         EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
9043                                 }
9044                         }
9045
9046                         if (pass_mrgctx) {
9047                                 g_assert (!vtable_arg);
9048
9049                                 if (!cfg->compile_aot) {
9050                                         /* 
9051                                          * emit_get_rgctx_method () calls mono_class_vtable () so check 
9052                                          * for type load errors before.
9053                                          */
9054                                         mono_class_setup_vtable (cmethod->klass);
9055                                         CHECK_TYPELOAD (cmethod->klass);
9056                                 }
9057
9058                                 vtable_arg = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
9059
9060                                 /* !marshalbyref is needed to properly handle generic methods + remoting */
9061                                 if ((!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
9062                                          MONO_METHOD_IS_FINAL (cmethod)) &&
9063                                         !mono_class_is_marshalbyref (cmethod->klass)) {
9064                                         if (virtual)
9065                                                 check_this = TRUE;
9066                                         virtual = 0;
9067                                 }
9068                         }
9069
9070                         if (pass_imt_from_rgctx) {
9071                                 g_assert (!pass_vtable);
9072
9073                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9074                                         cmethod, MONO_RGCTX_INFO_METHOD);
9075                         }
9076
9077                         if (check_this)
9078                                 MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9079
9080                         /* Calling virtual generic methods */
9081                         if (virtual && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) && 
9082                             !(MONO_METHOD_IS_FINAL (cmethod) && 
9083                               cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) &&
9084                             fsig->generic_param_count && 
9085                                 !(cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))) {
9086                                 MonoInst *this_temp, *this_arg_temp, *store;
9087                                 MonoInst *iargs [4];
9088                                 gboolean use_imt = FALSE;
9089
9090                                 g_assert (fsig->is_inflated);
9091
9092                                 /* Prevent inlining of methods that contain indirect calls */
9093                                 INLINE_FAILURE ("virtual generic call");
9094
9095                                 if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))
9096                                         GSHAREDVT_FAILURE (*ip);
9097
9098 #if MONO_ARCH_HAVE_GENERALIZED_IMT_THUNK && defined(MONO_ARCH_GSHARED_SUPPORTED)
9099                                 if (cmethod->wrapper_type == MONO_WRAPPER_NONE)
9100                                         use_imt = TRUE;
9101 #endif
9102
9103                                 if (use_imt) {
9104                                         g_assert (!imt_arg);
9105                                         if (!context_used)
9106                                                 g_assert (cmethod->is_inflated);
9107                                         imt_arg = emit_get_rgctx_method (cfg, context_used,
9108                                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
9109                                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, sp [0], imt_arg, NULL);
9110                                 } else {
9111                                         this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
9112                                         NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
9113                                         MONO_ADD_INS (cfg->cbb, store);
9114
9115                                         /* FIXME: This should be a managed pointer */
9116                                         this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
9117
9118                                         EMIT_NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
9119                                         iargs [1] = emit_get_rgctx_method (cfg, context_used,
9120                                                                                                            cmethod, MONO_RGCTX_INFO_METHOD);
9121                                         EMIT_NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
9122                                         addr = mono_emit_jit_icall (cfg,
9123                                                                                                 mono_helper_compile_generic_method, iargs);
9124
9125                                         EMIT_NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
9126
9127                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9128                                 }
9129
9130                                 goto call_end;
9131                         }
9132
9133                         /*
9134                          * Implement a workaround for the inherent races involved in locking:
9135                          * Monitor.Enter ()
9136                          * try {
9137                          * } finally {
9138                          *    Monitor.Exit ()
9139                          * }
9140                          * If a thread abort happens between the call to Monitor.Enter () and the start of the
9141                          * try block, the Exit () won't be executed, see:
9142                          * http://www.bluebytesoftware.com/blog/2007/01/30/MonitorEnterThreadAbortsAndOrphanedLocks.aspx
9143                          * To work around this, we extend such try blocks to include the last x bytes
9144                          * of the Monitor.Enter () call.
9145                          */
9146                         if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
9147                                 MonoBasicBlock *tbb;
9148
9149                                 GET_BBLOCK (cfg, tbb, ip + 5);
9150                                 /* 
9151                                  * Only extend try blocks with a finally, to avoid catching exceptions thrown
9152                                  * from Monitor.Enter like ArgumentNullException.
9153                                  */
9154                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
9155                                         /* Mark this bblock as needing to be extended */
9156                                         tbb->extend_try_block = TRUE;
9157                                 }
9158                         }
9159
9160                         /* Conversion to a JIT intrinsic */
9161                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_method (cfg, cmethod, fsig, sp))) {
9162                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9163                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
9164                                         emit_widen = FALSE;
9165                                 }
9166                                 goto call_end;
9167                         }
9168
9169                         /* Inlining */
9170                         if ((cfg->opt & MONO_OPT_INLINE) &&
9171                                 (!virtual || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || MONO_METHOD_IS_FINAL (cmethod)) &&
9172                             mono_method_check_inlining (cfg, cmethod)) {
9173                                 int costs;
9174                                 gboolean always = FALSE;
9175
9176                                 if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
9177                                         (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
9178                                         /* Prevent inlining of methods that call wrappers */
9179                                         INLINE_FAILURE ("wrapper call");
9180                                         cmethod = mono_marshal_get_native_wrapper (cmethod, TRUE, FALSE);
9181                                         always = TRUE;
9182                                 }
9183
9184                                 costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, always);
9185                                 if (costs) {
9186                                         cfg->real_offset += 5;
9187
9188                                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9189                                                 /* *sp is already set by inline_method */
9190                                                 sp++;
9191                                                 push_res = FALSE;
9192                                         }
9193
9194                                         inline_costs += costs;
9195
9196                                         goto call_end;
9197                                 }
9198                         }
9199
9200                         /* Tail recursion elimination */
9201                         if ((cfg->opt & MONO_OPT_TAILC) && call_opcode == CEE_CALL && cmethod == method && ip [5] == CEE_RET && !vtable_arg) {
9202                                 gboolean has_vtargs = FALSE;
9203                                 int i;
9204
9205                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9206                                 INLINE_FAILURE ("tail call");
9207
9208                                 /* keep it simple */
9209                                 for (i =  fsig->param_count - 1; i >= 0; i--) {
9210                                         if (MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->params [i])) 
9211                                                 has_vtargs = TRUE;
9212                                 }
9213
9214                                 if (!has_vtargs) {
9215                                         for (i = 0; i < n; ++i)
9216                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9217                                         MONO_INST_NEW (cfg, ins, OP_BR);
9218                                         MONO_ADD_INS (cfg->cbb, ins);
9219                                         tblock = start_bblock->out_bb [0];
9220                                         link_bblock (cfg, cfg->cbb, tblock);
9221                                         ins->inst_target_bb = tblock;
9222                                         start_new_bblock = 1;
9223
9224                                         /* skip the CEE_RET, too */
9225                                         if (ip_in_bb (cfg, cfg->cbb, ip + 5))
9226                                                 skip_ret = TRUE;
9227                                         push_res = FALSE;
9228                                         goto call_end;
9229                                 }
9230                         }
9231
9232                         inline_costs += 10 * num_calls++;
9233
9234                         /*
9235                          * Making generic calls out of gsharedvt methods.
9236                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
9237                          * patching gshared method addresses into a gsharedvt method.
9238                          */
9239                         if (cfg->gsharedvt && (mini_is_gsharedvt_signature (fsig) || cmethod->is_inflated || cmethod->klass->generic_class) &&
9240                                 !(cmethod->klass->rank && cmethod->klass->byval_arg.type != MONO_TYPE_SZARRAY)) {
9241                                 MonoRgctxInfoType info_type;
9242
9243                                 if (virtual) {
9244                                         //if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
9245                                                 //GSHAREDVT_FAILURE (*ip);
9246                                         // disable for possible remoting calls
9247                                         if (fsig->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class))
9248                                                 GSHAREDVT_FAILURE (*ip);
9249                                         if (fsig->generic_param_count) {
9250                                                 /* virtual generic call */
9251                                                 g_assert (!imt_arg);
9252                                                 /* Same as the virtual generic case above */
9253                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9254                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9255                                                 /* This is not needed, as the trampoline code will pass one, and it might be passed in the same reg as the imt arg */
9256                                                 vtable_arg = NULL;
9257                                         } else if ((cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !imt_arg) {
9258                                                 /* This can happen when we call a fully instantiated iface method */
9259                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9260                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9261                                                 vtable_arg = NULL;
9262                                         }
9263                                 }
9264
9265                                 if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (cmethod->name, "Invoke")))
9266                                         keep_this_alive = sp [0];
9267
9268                                 if (virtual && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))
9269                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
9270                                 else
9271                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE;
9272                                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, info_type);
9273
9274                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9275                                 goto call_end;
9276                         }
9277
9278                         /* Generic sharing */
9279
9280                         /*
9281                          * Use this if the callee is gsharedvt sharable too, since
9282                          * at runtime we might find an instantiation so the call cannot
9283                          * be patched (the 'no_patch' code path in mini-trampolines.c).
9284                          */
9285                         if (context_used && !imt_arg && !array_rank && !delegate_invoke &&
9286                                 (!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
9287                                  !mono_class_generic_sharing_enabled (cmethod->klass)) &&
9288                                 (!virtual || MONO_METHOD_IS_FINAL (cmethod) ||
9289                                  !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))) {
9290                                 INLINE_FAILURE ("gshared");
9291
9292                                 g_assert (cfg->gshared && cmethod);
9293                                 g_assert (!addr);
9294
9295                                 /*
9296                                  * We are compiling a call to a
9297                                  * generic method from shared code,
9298                                  * which means that we have to look up
9299                                  * the method in the rgctx and do an
9300                                  * indirect call.
9301                                  */
9302                                 if (fsig->hasthis)
9303                                         MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9304
9305                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
9306                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9307                                 goto call_end;
9308                         }
9309
9310                         /* Direct calls to icalls */
9311                         if (direct_icall) {
9312                                 MonoMethod *wrapper;
9313                                 int costs;
9314
9315                                 /* Inline the wrapper */
9316                                 wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
9317
9318                                 costs = inline_method (cfg, wrapper, fsig, sp, ip, cfg->real_offset, TRUE);
9319                                 g_assert (costs > 0);
9320                                 cfg->real_offset += 5;
9321
9322                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9323                                         /* *sp is already set by inline_method */
9324                                         sp++;
9325                                         push_res = FALSE;
9326                                 }
9327
9328                                 inline_costs += costs;
9329
9330                                 goto call_end;
9331                         }
9332                                         
9333                         /* Array methods */
9334                         if (array_rank) {
9335                                 MonoInst *addr;
9336
9337                                 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ 
9338                                         MonoInst *val = sp [fsig->param_count];
9339
9340                                         if (val->type == STACK_OBJ) {
9341                                                 MonoInst *iargs [2];
9342
9343                                                 iargs [0] = sp [0];
9344                                                 iargs [1] = val;
9345                                                 
9346                                                 mono_emit_jit_icall (cfg, mono_helper_stelem_ref_check, iargs);
9347                                         }
9348                                         
9349                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, TRUE);
9350                                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, fsig->params [fsig->param_count - 1], addr->dreg, 0, val->dreg);
9351                                         if (cfg->gen_write_barriers && val->type == STACK_OBJ && !(val->opcode == OP_PCONST && val->inst_c0 == 0))
9352                                                 emit_write_barrier (cfg, addr, val);
9353                                         if (cfg->gen_write_barriers && mini_is_gsharedvt_klass (cmethod->klass))
9354                                                 GSHAREDVT_FAILURE (*ip);
9355                                 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
9356                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9357
9358                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, addr->dreg, 0);
9359                                 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
9360                                         if (!cmethod->klass->element_class->valuetype && !readonly)
9361                                                 mini_emit_check_array_type (cfg, sp [0], cmethod->klass);
9362                                         CHECK_TYPELOAD (cmethod->klass);
9363                                         
9364                                         readonly = FALSE;
9365                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9366                                         ins = addr;
9367                                 } else {
9368                                         g_assert_not_reached ();
9369                                 }
9370
9371                                 emit_widen = FALSE;
9372                                 goto call_end;
9373                         }
9374
9375                         ins = mini_redirect_call (cfg, cmethod, fsig, sp, virtual ? sp [0] : NULL);
9376                         if (ins)
9377                                 goto call_end;
9378
9379                         /* Tail prefix / tail call optimization */
9380
9381                         /* FIXME: Enabling TAILC breaks some inlining/stack trace/etc tests */
9382                         /* FIXME: runtime generic context pointer for jumps? */
9383                         /* FIXME: handle this for generic sharing eventually */
9384                         if ((ins_flag & MONO_INST_TAILCALL) &&
9385                                 !vtable_arg && !cfg->gshared && is_supported_tail_call (cfg, method, cmethod, fsig, call_opcode))
9386                                 supported_tail_call = TRUE;
9387
9388                         if (supported_tail_call) {
9389                                 MonoCallInst *call;
9390
9391                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9392                                 INLINE_FAILURE ("tail call");
9393
9394                                 //printf ("HIT: %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
9395
9396                                 if (ARCH_HAVE_OP_TAIL_CALL) {
9397                                         /* Handle tail calls similarly to normal calls */
9398                                         tail_call = TRUE;
9399                                 } else {
9400                                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
9401
9402                                         MONO_INST_NEW_CALL (cfg, call, OP_JMP);
9403                                         call->tail_call = TRUE;
9404                                         call->method = cmethod;
9405                                         call->signature = mono_method_signature (cmethod);
9406
9407                                         /*
9408                                          * We implement tail calls by storing the actual arguments into the 
9409                                          * argument variables, then emitting a CEE_JMP.
9410                                          */
9411                                         for (i = 0; i < n; ++i) {
9412                                                 /* Prevent argument from being register allocated */
9413                                                 arg_array [i]->flags |= MONO_INST_VOLATILE;
9414                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9415                                         }
9416                                         ins = (MonoInst*)call;
9417                                         ins->inst_p0 = cmethod;
9418                                         ins->inst_p1 = arg_array [0];
9419                                         MONO_ADD_INS (cfg->cbb, ins);
9420                                         link_bblock (cfg, cfg->cbb, end_bblock);
9421                                         start_new_bblock = 1;
9422
9423                                         // FIXME: Eliminate unreachable epilogs
9424
9425                                         /*
9426                                          * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9427                                          * only reachable from this call.
9428                                          */
9429                                         GET_BBLOCK (cfg, tblock, ip + 5);
9430                                         if (tblock == cfg->cbb || tblock->in_count == 0)
9431                                                 skip_ret = TRUE;
9432                                         push_res = FALSE;
9433
9434                                         goto call_end;
9435                                 }
9436                         }
9437
9438                         /* 
9439                          * Synchronized wrappers.
9440                          * Its hard to determine where to replace a method with its synchronized
9441                          * wrapper without causing an infinite recursion. The current solution is
9442                          * to add the synchronized wrapper in the trampolines, and to
9443                          * change the called method to a dummy wrapper, and resolve that wrapper
9444                          * to the real method in mono_jit_compile_method ().
9445                          */
9446                         if (cfg->method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
9447                                 MonoMethod *orig = mono_marshal_method_from_wrapper (cfg->method);
9448                                 if (cmethod == orig || (cmethod->is_inflated && mono_method_get_declaring_generic_method (cmethod) == orig))
9449                                         cmethod = mono_marshal_get_synchronized_inner_wrapper (cmethod);
9450                         }
9451
9452                         /* Common call */
9453                         INLINE_FAILURE ("call");
9454                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, tail_call, sp, virtual ? sp [0] : NULL,
9455                                                                                           imt_arg, vtable_arg);
9456
9457                         if (tail_call) {
9458                                 link_bblock (cfg, cfg->cbb, end_bblock);
9459                                 start_new_bblock = 1;
9460
9461                                 // FIXME: Eliminate unreachable epilogs
9462
9463                                 /*
9464                                  * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9465                                  * only reachable from this call.
9466                                  */
9467                                 GET_BBLOCK (cfg, tblock, ip + 5);
9468                                 if (tblock == cfg->cbb || tblock->in_count == 0)
9469                                         skip_ret = TRUE;
9470                                 push_res = FALSE;
9471                         }
9472
9473                         call_end:
9474
9475                         /* End of call, INS should contain the result of the call, if any */
9476
9477                         if (push_res && !MONO_TYPE_IS_VOID (fsig->ret)) {
9478                                 g_assert (ins);
9479                                 if (emit_widen)
9480                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
9481                                 else
9482                                         *sp++ = ins;
9483                         }
9484
9485                         if (keep_this_alive) {
9486                                 MonoInst *dummy_use;
9487
9488                                 /* See mono_emit_method_call_full () */
9489                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, keep_this_alive);
9490                         }
9491
9492                         CHECK_CFG_EXCEPTION;
9493
9494                         ip += 5;
9495                         if (skip_ret) {
9496                                 g_assert (*ip == CEE_RET);
9497                                 ip += 1;
9498                         }
9499                         ins_flag = 0;
9500                         constrained_class = NULL;
9501                         if (need_seq_point)
9502                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
9503                         break;
9504                 }
9505                 case CEE_RET:
9506                         if (cfg->method != method) {
9507                                 /* return from inlined method */
9508                                 /* 
9509                                  * If in_count == 0, that means the ret is unreachable due to
9510                                  * being preceeded by a throw. In that case, inline_method () will
9511                                  * handle setting the return value 
9512                                  * (test case: test_0_inline_throw ()).
9513                                  */
9514                                 if (return_var && cfg->cbb->in_count) {
9515                                         MonoType *ret_type = mono_method_signature (method)->ret;
9516
9517                                         MonoInst *store;
9518                                         CHECK_STACK (1);
9519                                         --sp;
9520
9521                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
9522                                                 UNVERIFIED;
9523
9524                                         //g_assert (returnvar != -1);
9525                                         EMIT_NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
9526                                         cfg->ret_var_set = TRUE;
9527                                 } 
9528                         } else {
9529                                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
9530
9531                                 if (cfg->lmf_var && cfg->cbb->in_count)
9532                                         emit_pop_lmf (cfg);
9533
9534                                 if (cfg->ret) {
9535                                         MonoType *ret_type = mini_get_underlying_type (mono_method_signature (method)->ret);
9536
9537                                         if (seq_points && !sym_seq_points) {
9538                                                 /* 
9539                                                  * Place a seq point here too even through the IL stack is not
9540                                                  * empty, so a step over on
9541                                                  * call <FOO>
9542                                                  * ret
9543                                                  * will work correctly.
9544                                                  */
9545                                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, TRUE);
9546                                                 MONO_ADD_INS (cfg->cbb, ins);
9547                                         }
9548
9549                                         g_assert (!return_var);
9550                                         CHECK_STACK (1);
9551                                         --sp;
9552
9553                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
9554                                                 UNVERIFIED;
9555
9556                                         if (mini_type_to_stind (cfg, ret_type) == CEE_STOBJ) {
9557                                                 MonoInst *ret_addr;
9558
9559                                                 if (!cfg->vret_addr) {
9560                                                         MonoInst *ins;
9561
9562                                                         EMIT_NEW_VARSTORE (cfg, ins, cfg->ret, ret_type, (*sp));
9563                                                 } else {
9564                                                         EMIT_NEW_RETLOADA (cfg, ret_addr);
9565
9566                                                         EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STOREV_MEMBASE, ret_addr->dreg, 0, (*sp)->dreg);
9567                                                         ins->klass = mono_class_from_mono_type (ret_type);
9568                                                 }
9569                                         } else {
9570 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
9571                                                 if (COMPILE_SOFT_FLOAT (cfg) && !ret_type->byref && ret_type->type == MONO_TYPE_R4) {
9572                                                         MonoInst *iargs [1];
9573                                                         MonoInst *conv;
9574
9575                                                         iargs [0] = *sp;
9576                                                         conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
9577                                                         mono_arch_emit_setret (cfg, method, conv);
9578                                                 } else {
9579                                                         mono_arch_emit_setret (cfg, method, *sp);
9580                                                 }
9581 #else
9582                                                 mono_arch_emit_setret (cfg, method, *sp);
9583 #endif
9584                                         }
9585                                 }
9586                         }
9587                         if (sp != stack_start)
9588                                 UNVERIFIED;
9589                         MONO_INST_NEW (cfg, ins, OP_BR);
9590                         ip++;
9591                         ins->inst_target_bb = end_bblock;
9592                         MONO_ADD_INS (cfg->cbb, ins);
9593                         link_bblock (cfg, cfg->cbb, end_bblock);
9594                         start_new_bblock = 1;
9595                         break;
9596                 case CEE_BR_S:
9597                         CHECK_OPSIZE (2);
9598                         MONO_INST_NEW (cfg, ins, OP_BR);
9599                         ip++;
9600                         target = ip + 1 + (signed char)(*ip);
9601                         ++ip;
9602                         GET_BBLOCK (cfg, tblock, target);
9603                         link_bblock (cfg, cfg->cbb, tblock);
9604                         ins->inst_target_bb = tblock;
9605                         if (sp != stack_start) {
9606                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9607                                 sp = stack_start;
9608                                 CHECK_UNVERIFIABLE (cfg);
9609                         }
9610                         MONO_ADD_INS (cfg->cbb, ins);
9611                         start_new_bblock = 1;
9612                         inline_costs += BRANCH_COST;
9613                         break;
9614                 case CEE_BEQ_S:
9615                 case CEE_BGE_S:
9616                 case CEE_BGT_S:
9617                 case CEE_BLE_S:
9618                 case CEE_BLT_S:
9619                 case CEE_BNE_UN_S:
9620                 case CEE_BGE_UN_S:
9621                 case CEE_BGT_UN_S:
9622                 case CEE_BLE_UN_S:
9623                 case CEE_BLT_UN_S:
9624                         CHECK_OPSIZE (2);
9625                         CHECK_STACK (2);
9626                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
9627                         ip++;
9628                         target = ip + 1 + *(signed char*)ip;
9629                         ip++;
9630
9631                         ADD_BINCOND (NULL);
9632
9633                         sp = stack_start;
9634                         inline_costs += BRANCH_COST;
9635                         break;
9636                 case CEE_BR:
9637                         CHECK_OPSIZE (5);
9638                         MONO_INST_NEW (cfg, ins, OP_BR);
9639                         ip++;
9640
9641                         target = ip + 4 + (gint32)read32(ip);
9642                         ip += 4;
9643                         GET_BBLOCK (cfg, tblock, target);
9644                         link_bblock (cfg, cfg->cbb, tblock);
9645                         ins->inst_target_bb = tblock;
9646                         if (sp != stack_start) {
9647                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9648                                 sp = stack_start;
9649                                 CHECK_UNVERIFIABLE (cfg);
9650                         }
9651
9652                         MONO_ADD_INS (cfg->cbb, ins);
9653
9654                         start_new_bblock = 1;
9655                         inline_costs += BRANCH_COST;
9656                         break;
9657                 case CEE_BRFALSE_S:
9658                 case CEE_BRTRUE_S:
9659                 case CEE_BRFALSE:
9660                 case CEE_BRTRUE: {
9661                         MonoInst *cmp;
9662                         gboolean is_short = ((*ip) == CEE_BRFALSE_S) || ((*ip) == CEE_BRTRUE_S);
9663                         gboolean is_true = ((*ip) == CEE_BRTRUE_S) || ((*ip) == CEE_BRTRUE);
9664                         guint32 opsize = is_short ? 1 : 4;
9665
9666                         CHECK_OPSIZE (opsize);
9667                         CHECK_STACK (1);
9668                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
9669                                 UNVERIFIED;
9670                         ip ++;
9671                         target = ip + opsize + (is_short ? *(signed char*)ip : (gint32)read32(ip));
9672                         ip += opsize;
9673
9674                         sp--;
9675
9676                         GET_BBLOCK (cfg, tblock, target);
9677                         link_bblock (cfg, cfg->cbb, tblock);
9678                         GET_BBLOCK (cfg, tblock, ip);
9679                         link_bblock (cfg, cfg->cbb, tblock);
9680
9681                         if (sp != stack_start) {
9682                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9683                                 CHECK_UNVERIFIABLE (cfg);
9684                         }
9685
9686                         MONO_INST_NEW(cfg, cmp, OP_ICOMPARE_IMM);
9687                         cmp->sreg1 = sp [0]->dreg;
9688                         type_from_op (cfg, cmp, sp [0], NULL);
9689                         CHECK_TYPE (cmp);
9690
9691 #if SIZEOF_REGISTER == 4
9692                         if (cmp->opcode == OP_LCOMPARE_IMM) {
9693                                 /* Convert it to OP_LCOMPARE */
9694                                 MONO_INST_NEW (cfg, ins, OP_I8CONST);
9695                                 ins->type = STACK_I8;
9696                                 ins->dreg = alloc_dreg (cfg, STACK_I8);
9697                                 ins->inst_l = 0;
9698                                 MONO_ADD_INS (cfg->cbb, ins);
9699                                 cmp->opcode = OP_LCOMPARE;
9700                                 cmp->sreg2 = ins->dreg;
9701                         }
9702 #endif
9703                         MONO_ADD_INS (cfg->cbb, cmp);
9704
9705                         MONO_INST_NEW (cfg, ins, is_true ? CEE_BNE_UN : CEE_BEQ);
9706                         type_from_op (cfg, ins, sp [0], NULL);
9707                         MONO_ADD_INS (cfg->cbb, ins);
9708                         ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);
9709                         GET_BBLOCK (cfg, tblock, target);
9710                         ins->inst_true_bb = tblock;
9711                         GET_BBLOCK (cfg, tblock, ip);
9712                         ins->inst_false_bb = tblock;
9713                         start_new_bblock = 2;
9714
9715                         sp = stack_start;
9716                         inline_costs += BRANCH_COST;
9717                         break;
9718                 }
9719                 case CEE_BEQ:
9720                 case CEE_BGE:
9721                 case CEE_BGT:
9722                 case CEE_BLE:
9723                 case CEE_BLT:
9724                 case CEE_BNE_UN:
9725                 case CEE_BGE_UN:
9726                 case CEE_BGT_UN:
9727                 case CEE_BLE_UN:
9728                 case CEE_BLT_UN:
9729                         CHECK_OPSIZE (5);
9730                         CHECK_STACK (2);
9731                         MONO_INST_NEW (cfg, ins, *ip);
9732                         ip++;
9733                         target = ip + 4 + (gint32)read32(ip);
9734                         ip += 4;
9735
9736                         ADD_BINCOND (NULL);
9737
9738                         sp = stack_start;
9739                         inline_costs += BRANCH_COST;
9740                         break;
9741                 case CEE_SWITCH: {
9742                         MonoInst *src1;
9743                         MonoBasicBlock **targets;
9744                         MonoBasicBlock *default_bblock;
9745                         MonoJumpInfoBBTable *table;
9746                         int offset_reg = alloc_preg (cfg);
9747                         int target_reg = alloc_preg (cfg);
9748                         int table_reg = alloc_preg (cfg);
9749                         int sum_reg = alloc_preg (cfg);
9750                         gboolean use_op_switch;
9751
9752                         CHECK_OPSIZE (5);
9753                         CHECK_STACK (1);
9754                         n = read32 (ip + 1);
9755                         --sp;
9756                         src1 = sp [0];
9757                         if ((src1->type != STACK_I4) && (src1->type != STACK_PTR)) 
9758                                 UNVERIFIED;
9759
9760                         ip += 5;
9761                         CHECK_OPSIZE (n * sizeof (guint32));
9762                         target = ip + n * sizeof (guint32);
9763
9764                         GET_BBLOCK (cfg, default_bblock, target);
9765                         default_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
9766
9767                         targets = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * n);
9768                         for (i = 0; i < n; ++i) {
9769                                 GET_BBLOCK (cfg, tblock, target + (gint32)read32(ip));
9770                                 targets [i] = tblock;
9771                                 targets [i]->flags |= BB_INDIRECT_JUMP_TARGET;
9772                                 ip += 4;
9773                         }
9774
9775                         if (sp != stack_start) {
9776                                 /* 
9777                                  * Link the current bb with the targets as well, so handle_stack_args
9778                                  * will set their in_stack correctly.
9779                                  */
9780                                 link_bblock (cfg, cfg->cbb, default_bblock);
9781                                 for (i = 0; i < n; ++i)
9782                                         link_bblock (cfg, cfg->cbb, targets [i]);
9783
9784                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9785                                 sp = stack_start;
9786                                 CHECK_UNVERIFIABLE (cfg);
9787                         }
9788
9789                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, src1->dreg, n);
9790                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBGE_UN, default_bblock);
9791
9792                         for (i = 0; i < n; ++i)
9793                                 link_bblock (cfg, cfg->cbb, targets [i]);
9794
9795                         table = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
9796                         table->table = targets;
9797                         table->table_size = n;
9798
9799                         use_op_switch = FALSE;
9800 #ifdef TARGET_ARM
9801                         /* ARM implements SWITCH statements differently */
9802                         /* FIXME: Make it use the generic implementation */
9803                         if (!cfg->compile_aot)
9804                                 use_op_switch = TRUE;
9805 #endif
9806
9807                         if (COMPILE_LLVM (cfg))
9808                                 use_op_switch = TRUE;
9809
9810                         cfg->cbb->has_jump_table = 1;
9811
9812                         if (use_op_switch) {
9813                                 MONO_INST_NEW (cfg, ins, OP_SWITCH);
9814                                 ins->sreg1 = src1->dreg;
9815                                 ins->inst_p0 = table;
9816                                 ins->inst_many_bb = targets;
9817                                 ins->klass = GUINT_TO_POINTER (n);
9818                                 MONO_ADD_INS (cfg->cbb, ins);
9819                         } else {
9820                                 if (sizeof (gpointer) == 8)
9821                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 3);
9822                                 else
9823                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 2);
9824
9825 #if SIZEOF_REGISTER == 8
9826                                 /* The upper word might not be zero, and we add it to a 64 bit address later */
9827                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, offset_reg, offset_reg);
9828 #endif
9829
9830                                 if (cfg->compile_aot) {
9831                                         MONO_EMIT_NEW_AOTCONST (cfg, table_reg, table, MONO_PATCH_INFO_SWITCH);
9832                                 } else {
9833                                         MONO_INST_NEW (cfg, ins, OP_JUMP_TABLE);
9834                                         ins->inst_c1 = MONO_PATCH_INFO_SWITCH;
9835                                         ins->inst_p0 = table;
9836                                         ins->dreg = table_reg;
9837                                         MONO_ADD_INS (cfg->cbb, ins);
9838                                 }
9839
9840                                 /* FIXME: Use load_memindex */
9841                                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, table_reg, offset_reg);
9842                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, target_reg, sum_reg, 0);
9843                                 MONO_EMIT_NEW_UNALU (cfg, OP_BR_REG, -1, target_reg);
9844                         }
9845                         start_new_bblock = 1;
9846                         inline_costs += (BRANCH_COST * 2);
9847                         break;
9848                 }
9849                 case CEE_LDIND_I1:
9850                 case CEE_LDIND_U1:
9851                 case CEE_LDIND_I2:
9852                 case CEE_LDIND_U2:
9853                 case CEE_LDIND_I4:
9854                 case CEE_LDIND_U4:
9855                 case CEE_LDIND_I8:
9856                 case CEE_LDIND_I:
9857                 case CEE_LDIND_R4:
9858                 case CEE_LDIND_R8:
9859                 case CEE_LDIND_REF:
9860                         CHECK_STACK (1);
9861                         --sp;
9862
9863                         switch (*ip) {
9864                         case CEE_LDIND_R4:
9865                         case CEE_LDIND_R8:
9866                                 dreg = alloc_freg (cfg);
9867                                 break;
9868                         case CEE_LDIND_I8:
9869                                 dreg = alloc_lreg (cfg);
9870                                 break;
9871                         case CEE_LDIND_REF:
9872                                 dreg = alloc_ireg_ref (cfg);
9873                                 break;
9874                         default:
9875                                 dreg = alloc_preg (cfg);
9876                         }
9877
9878                         NEW_LOAD_MEMBASE (cfg, ins, ldind_to_load_membase (*ip), dreg, sp [0]->dreg, 0);
9879                         ins->type = ldind_type [*ip - CEE_LDIND_I1];
9880                         if (*ip == CEE_LDIND_R4)
9881                                 ins->type = cfg->r4_stack_type;
9882                         ins->flags |= ins_flag;
9883                         MONO_ADD_INS (cfg->cbb, ins);
9884                         *sp++ = ins;
9885                         if (ins_flag & MONO_INST_VOLATILE) {
9886                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
9887                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
9888                         }
9889                         ins_flag = 0;
9890                         ++ip;
9891                         break;
9892                 case CEE_STIND_REF:
9893                 case CEE_STIND_I1:
9894                 case CEE_STIND_I2:
9895                 case CEE_STIND_I4:
9896                 case CEE_STIND_I8:
9897                 case CEE_STIND_R4:
9898                 case CEE_STIND_R8:
9899                 case CEE_STIND_I:
9900                         CHECK_STACK (2);
9901                         sp -= 2;
9902
9903                         if (ins_flag & MONO_INST_VOLATILE) {
9904                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
9905                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
9906                         }
9907
9908                         NEW_STORE_MEMBASE (cfg, ins, stind_to_store_membase (*ip), sp [0]->dreg, 0, sp [1]->dreg);
9909                         ins->flags |= ins_flag;
9910                         ins_flag = 0;
9911
9912                         MONO_ADD_INS (cfg->cbb, ins);
9913
9914                         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)))
9915                                 emit_write_barrier (cfg, sp [0], sp [1]);
9916
9917                         inline_costs += 1;
9918                         ++ip;
9919                         break;
9920
9921                 case CEE_MUL:
9922                         CHECK_STACK (2);
9923
9924                         MONO_INST_NEW (cfg, ins, (*ip));
9925                         sp -= 2;
9926                         ins->sreg1 = sp [0]->dreg;
9927                         ins->sreg2 = sp [1]->dreg;
9928                         type_from_op (cfg, ins, sp [0], sp [1]);
9929                         CHECK_TYPE (ins);
9930                         ins->dreg = alloc_dreg ((cfg), (ins)->type);
9931
9932                         /* Use the immediate opcodes if possible */
9933                         if ((sp [1]->opcode == OP_ICONST) && mono_arch_is_inst_imm (sp [1]->inst_c0)) {
9934                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
9935                                 if (imm_opcode != -1) {
9936                                         ins->opcode = imm_opcode;
9937                                         ins->inst_p1 = (gpointer)(gssize)(sp [1]->inst_c0);
9938                                         ins->sreg2 = -1;
9939
9940                                         NULLIFY_INS (sp [1]);
9941                                 }
9942                         }
9943
9944                         MONO_ADD_INS ((cfg)->cbb, (ins));
9945
9946                         *sp++ = mono_decompose_opcode (cfg, ins);
9947                         ip++;
9948                         break;
9949                 case CEE_ADD:
9950                 case CEE_SUB:
9951                 case CEE_DIV:
9952                 case CEE_DIV_UN:
9953                 case CEE_REM:
9954                 case CEE_REM_UN:
9955                 case CEE_AND:
9956                 case CEE_OR:
9957                 case CEE_XOR:
9958                 case CEE_SHL:
9959                 case CEE_SHR:
9960                 case CEE_SHR_UN:
9961                         CHECK_STACK (2);
9962
9963                         MONO_INST_NEW (cfg, ins, (*ip));
9964                         sp -= 2;
9965                         ins->sreg1 = sp [0]->dreg;
9966                         ins->sreg2 = sp [1]->dreg;
9967                         type_from_op (cfg, ins, sp [0], sp [1]);
9968                         CHECK_TYPE (ins);
9969                         add_widen_op (cfg, ins, &sp [0], &sp [1]);
9970                         ins->dreg = alloc_dreg ((cfg), (ins)->type);
9971
9972                         /* FIXME: Pass opcode to is_inst_imm */
9973
9974                         /* Use the immediate opcodes if possible */
9975                         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)) {
9976                                 int imm_opcode;
9977
9978                                 imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
9979 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
9980                                 /* Keep emulated opcodes which are optimized away later */
9981                                 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) {
9982                                         imm_opcode = mono_op_to_op_imm (ins->opcode);
9983                                 }
9984 #endif
9985                                 if (imm_opcode != -1) {
9986                                         ins->opcode = imm_opcode;
9987                                         if (sp [1]->opcode == OP_I8CONST) {
9988 #if SIZEOF_REGISTER == 8
9989                                                 ins->inst_imm = sp [1]->inst_l;
9990 #else
9991                                                 ins->inst_ls_word = sp [1]->inst_ls_word;
9992                                                 ins->inst_ms_word = sp [1]->inst_ms_word;
9993 #endif
9994                                         }
9995                                         else
9996                                                 ins->inst_imm = (gssize)(sp [1]->inst_c0);
9997                                         ins->sreg2 = -1;
9998
9999                                         /* Might be followed by an instruction added by add_widen_op */
10000                                         if (sp [1]->next == NULL)
10001                                                 NULLIFY_INS (sp [1]);
10002                                 }
10003                         }
10004                         MONO_ADD_INS ((cfg)->cbb, (ins));
10005
10006                         *sp++ = mono_decompose_opcode (cfg, ins);
10007                         ip++;
10008                         break;
10009                 case CEE_NEG:
10010                 case CEE_NOT:
10011                 case CEE_CONV_I1:
10012                 case CEE_CONV_I2:
10013                 case CEE_CONV_I4:
10014                 case CEE_CONV_R4:
10015                 case CEE_CONV_R8:
10016                 case CEE_CONV_U4:
10017                 case CEE_CONV_I8:
10018                 case CEE_CONV_U8:
10019                 case CEE_CONV_OVF_I8:
10020                 case CEE_CONV_OVF_U8:
10021                 case CEE_CONV_R_UN:
10022                         CHECK_STACK (1);
10023
10024                         /* Special case this earlier so we have long constants in the IR */
10025                         if ((((*ip) == CEE_CONV_I8) || ((*ip) == CEE_CONV_U8)) && (sp [-1]->opcode == OP_ICONST)) {
10026                                 int data = sp [-1]->inst_c0;
10027                                 sp [-1]->opcode = OP_I8CONST;
10028                                 sp [-1]->type = STACK_I8;
10029 #if SIZEOF_REGISTER == 8
10030                                 if ((*ip) == CEE_CONV_U8)
10031                                         sp [-1]->inst_c0 = (guint32)data;
10032                                 else
10033                                         sp [-1]->inst_c0 = data;
10034 #else
10035                                 sp [-1]->inst_ls_word = data;
10036                                 if ((*ip) == CEE_CONV_U8)
10037                                         sp [-1]->inst_ms_word = 0;
10038                                 else
10039                                         sp [-1]->inst_ms_word = (data < 0) ? -1 : 0;
10040 #endif
10041                                 sp [-1]->dreg = alloc_dreg (cfg, STACK_I8);
10042                         }
10043                         else {
10044                                 ADD_UNOP (*ip);
10045                         }
10046                         ip++;
10047                         break;
10048                 case CEE_CONV_OVF_I4:
10049                 case CEE_CONV_OVF_I1:
10050                 case CEE_CONV_OVF_I2:
10051                 case CEE_CONV_OVF_I:
10052                 case CEE_CONV_OVF_U:
10053                         CHECK_STACK (1);
10054
10055                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
10056                                 ADD_UNOP (CEE_CONV_OVF_I8);
10057                                 ADD_UNOP (*ip);
10058                         } else {
10059                                 ADD_UNOP (*ip);
10060                         }
10061                         ip++;
10062                         break;
10063                 case CEE_CONV_OVF_U1:
10064                 case CEE_CONV_OVF_U2:
10065                 case CEE_CONV_OVF_U4:
10066                         CHECK_STACK (1);
10067
10068                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
10069                                 ADD_UNOP (CEE_CONV_OVF_U8);
10070                                 ADD_UNOP (*ip);
10071                         } else {
10072                                 ADD_UNOP (*ip);
10073                         }
10074                         ip++;
10075                         break;
10076                 case CEE_CONV_OVF_I1_UN:
10077                 case CEE_CONV_OVF_I2_UN:
10078                 case CEE_CONV_OVF_I4_UN:
10079                 case CEE_CONV_OVF_I8_UN:
10080                 case CEE_CONV_OVF_U1_UN:
10081                 case CEE_CONV_OVF_U2_UN:
10082                 case CEE_CONV_OVF_U4_UN:
10083                 case CEE_CONV_OVF_U8_UN:
10084                 case CEE_CONV_OVF_I_UN:
10085                 case CEE_CONV_OVF_U_UN:
10086                 case CEE_CONV_U2:
10087                 case CEE_CONV_U1:
10088                 case CEE_CONV_I:
10089                 case CEE_CONV_U:
10090                         CHECK_STACK (1);
10091                         ADD_UNOP (*ip);
10092                         CHECK_CFG_EXCEPTION;
10093                         ip++;
10094                         break;
10095                 case CEE_ADD_OVF:
10096                 case CEE_ADD_OVF_UN:
10097                 case CEE_MUL_OVF:
10098                 case CEE_MUL_OVF_UN:
10099                 case CEE_SUB_OVF:
10100                 case CEE_SUB_OVF_UN:
10101                         CHECK_STACK (2);
10102                         ADD_BINOP (*ip);
10103                         ip++;
10104                         break;
10105                 case CEE_CPOBJ:
10106                         GSHAREDVT_FAILURE (*ip);
10107                         CHECK_OPSIZE (5);
10108                         CHECK_STACK (2);
10109                         token = read32 (ip + 1);
10110                         klass = mini_get_class (method, token, generic_context);
10111                         CHECK_TYPELOAD (klass);
10112                         sp -= 2;
10113                         if (generic_class_is_reference_type (cfg, klass)) {
10114                                 MonoInst *store, *load;
10115                                 int dreg = alloc_ireg_ref (cfg);
10116
10117                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, dreg, sp [1]->dreg, 0);
10118                                 load->flags |= ins_flag;
10119                                 MONO_ADD_INS (cfg->cbb, load);
10120
10121                                 NEW_STORE_MEMBASE (cfg, store, OP_STORE_MEMBASE_REG, sp [0]->dreg, 0, dreg);
10122                                 store->flags |= ins_flag;
10123                                 MONO_ADD_INS (cfg->cbb, store);
10124
10125                                 if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER)
10126                                         emit_write_barrier (cfg, sp [0], sp [1]);
10127                         } else {
10128                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
10129                         }
10130                         ins_flag = 0;
10131                         ip += 5;
10132                         break;
10133                 case CEE_LDOBJ: {
10134                         int loc_index = -1;
10135                         int stloc_len = 0;
10136
10137                         CHECK_OPSIZE (5);
10138                         CHECK_STACK (1);
10139                         --sp;
10140                         token = read32 (ip + 1);
10141                         klass = mini_get_class (method, token, generic_context);
10142                         CHECK_TYPELOAD (klass);
10143
10144                         /* Optimize the common ldobj+stloc combination */
10145                         switch (ip [5]) {
10146                         case CEE_STLOC_S:
10147                                 loc_index = ip [6];
10148                                 stloc_len = 2;
10149                                 break;
10150                         case CEE_STLOC_0:
10151                         case CEE_STLOC_1:
10152                         case CEE_STLOC_2:
10153                         case CEE_STLOC_3:
10154                                 loc_index = ip [5] - CEE_STLOC_0;
10155                                 stloc_len = 1;
10156                                 break;
10157                         default:
10158                                 break;
10159                         }
10160
10161                         if ((loc_index != -1) && ip_in_bb (cfg, cfg->cbb, ip + 5)) {
10162                                 CHECK_LOCAL (loc_index);
10163
10164                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10165                                 ins->dreg = cfg->locals [loc_index]->dreg;
10166                                 ins->flags |= ins_flag;
10167                                 ip += 5;
10168                                 ip += stloc_len;
10169                                 if (ins_flag & MONO_INST_VOLATILE) {
10170                                         /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10171                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10172                                 }
10173                                 ins_flag = 0;
10174                                 break;
10175                         }
10176
10177                         /* Optimize the ldobj+stobj combination */
10178                         /* The reference case ends up being a load+store anyway */
10179                         /* Skip this if the operation is volatile. */
10180                         if (((ip [5] == CEE_STOBJ) && ip_in_bb (cfg, cfg->cbb, ip + 5) && read32 (ip + 6) == token) && !generic_class_is_reference_type (cfg, klass) && !(ins_flag & MONO_INST_VOLATILE)) {
10181                                 CHECK_STACK (1);
10182
10183                                 sp --;
10184
10185                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
10186
10187                                 ip += 5 + 5;
10188                                 ins_flag = 0;
10189                                 break;
10190                         }
10191
10192                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10193                         ins->flags |= ins_flag;
10194                         *sp++ = ins;
10195
10196                         if (ins_flag & MONO_INST_VOLATILE) {
10197                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10198                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10199                         }
10200
10201                         ip += 5;
10202                         ins_flag = 0;
10203                         inline_costs += 1;
10204                         break;
10205                 }
10206                 case CEE_LDSTR:
10207                         CHECK_STACK_OVF (1);
10208                         CHECK_OPSIZE (5);
10209                         n = read32 (ip + 1);
10210
10211                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
10212                                 EMIT_NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
10213                                 ins->type = STACK_OBJ;
10214                                 *sp = ins;
10215                         }
10216                         else if (method->wrapper_type != MONO_WRAPPER_NONE) {
10217                                 MonoInst *iargs [1];
10218                                 char *str = mono_method_get_wrapper_data (method, n);
10219
10220                                 if (cfg->compile_aot)
10221                                         EMIT_NEW_LDSTRLITCONST (cfg, iargs [0], str);
10222                                 else
10223                                         EMIT_NEW_PCONST (cfg, iargs [0], str);
10224                                 *sp = mono_emit_jit_icall (cfg, mono_string_new_wrapper, iargs);
10225                         } else {
10226                                 if (cfg->opt & MONO_OPT_SHARED) {
10227                                         MonoInst *iargs [3];
10228
10229                                         if (cfg->compile_aot) {
10230                                                 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
10231                                         }
10232                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10233                                         EMIT_NEW_IMAGECONST (cfg, iargs [1], image);
10234                                         EMIT_NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
10235                                         *sp = mono_emit_jit_icall (cfg, mono_ldstr, iargs);
10236                                         mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
10237                                 } else {
10238                                         if (cfg->cbb->out_of_line) {
10239                                                 MonoInst *iargs [2];
10240
10241                                                 if (image == mono_defaults.corlib) {
10242                                                         /* 
10243                                                          * Avoid relocations in AOT and save some space by using a 
10244                                                          * version of helper_ldstr specialized to mscorlib.
10245                                                          */
10246                                                         EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (n));
10247                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr_mscorlib, iargs);
10248                                                 } else {
10249                                                         /* Avoid creating the string object */
10250                                                         EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
10251                                                         EMIT_NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n));
10252                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr, iargs);
10253                                                 }
10254                                         } 
10255                                         else
10256                                         if (cfg->compile_aot) {
10257                                                 NEW_LDSTRCONST (cfg, ins, image, n);
10258                                                 *sp = ins;
10259                                                 MONO_ADD_INS (cfg->cbb, ins);
10260                                         } 
10261                                         else {
10262                                                 NEW_PCONST (cfg, ins, NULL);
10263                                                 ins->type = STACK_OBJ;
10264                                                 ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
10265                                                 if (!ins->inst_p0)
10266                                                         OUT_OF_MEMORY_FAILURE;
10267
10268                                                 *sp = ins;
10269                                                 MONO_ADD_INS (cfg->cbb, ins);
10270                                         }
10271                                 }
10272                         }
10273
10274                         sp++;
10275                         ip += 5;
10276                         break;
10277                 case CEE_NEWOBJ: {
10278                         MonoInst *iargs [2];
10279                         MonoMethodSignature *fsig;
10280                         MonoInst this_ins;
10281                         MonoInst *alloc;
10282                         MonoInst *vtable_arg = NULL;
10283
10284                         CHECK_OPSIZE (5);
10285                         token = read32 (ip + 1);
10286                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
10287                         if (!cmethod || mono_loader_get_last_error ())
10288                                 LOAD_ERROR;
10289                         fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
10290                         CHECK_CFG_ERROR;
10291
10292                         mono_save_token_info (cfg, image, token, cmethod);
10293
10294                         if (!mono_class_init (cmethod->klass))
10295                                 TYPE_LOAD_ERROR (cmethod->klass);
10296
10297                         context_used = mini_method_check_context_used (cfg, cmethod);
10298
10299                         if (mono_security_core_clr_enabled ())
10300                                 ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
10301
10302                         if (cfg->gshared && cmethod && cmethod->klass != method->klass && cmethod->klass->generic_class && mono_method_is_generic_sharable (cmethod, TRUE) && mono_class_needs_cctor_run (cmethod->klass, method)) {
10303                                 emit_class_init (cfg, cmethod->klass);
10304                                 CHECK_TYPELOAD (cmethod->klass);
10305                         }
10306
10307                         /*
10308                         if (cfg->gsharedvt) {
10309                                 if (mini_is_gsharedvt_variable_signature (sig))
10310                                         GSHAREDVT_FAILURE (*ip);
10311                         }
10312                         */
10313
10314                         n = fsig->param_count;
10315                         CHECK_STACK (n);
10316
10317                         /* 
10318                          * Generate smaller code for the common newobj <exception> instruction in
10319                          * argument checking code.
10320                          */
10321                         if (cfg->cbb->out_of_line && cmethod->klass->image == mono_defaults.corlib &&
10322                                 is_exception_class (cmethod->klass) && n <= 2 &&
10323                                 ((n < 1) || (!fsig->params [0]->byref && fsig->params [0]->type == MONO_TYPE_STRING)) && 
10324                                 ((n < 2) || (!fsig->params [1]->byref && fsig->params [1]->type == MONO_TYPE_STRING))) {
10325                                 MonoInst *iargs [3];
10326
10327                                 sp -= n;
10328
10329                                 EMIT_NEW_ICONST (cfg, iargs [0], cmethod->klass->type_token);
10330                                 switch (n) {
10331                                 case 0:
10332                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_0, iargs);
10333                                         break;
10334                                 case 1:
10335                                         iargs [1] = sp [0];
10336                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_1, iargs);
10337                                         break;
10338                                 case 2:
10339                                         iargs [1] = sp [0];
10340                                         iargs [2] = sp [1];
10341                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_2, iargs);
10342                                         break;
10343                                 default:
10344                                         g_assert_not_reached ();
10345                                 }
10346
10347                                 ip += 5;
10348                                 inline_costs += 5;
10349                                 break;
10350                         }
10351
10352                         /* move the args to allow room for 'this' in the first position */
10353                         while (n--) {
10354                                 --sp;
10355                                 sp [1] = sp [0];
10356                         }
10357
10358                         /* check_call_signature () requires sp[0] to be set */
10359                         this_ins.type = STACK_OBJ;
10360                         sp [0] = &this_ins;
10361                         if (check_call_signature (cfg, fsig, sp))
10362                                 UNVERIFIED;
10363
10364                         iargs [0] = NULL;
10365
10366                         if (mini_class_is_system_array (cmethod->klass)) {
10367                                 *sp = emit_get_rgctx_method (cfg, context_used,
10368                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
10369
10370                                 /* Avoid varargs in the common case */
10371                                 if (fsig->param_count == 1)
10372                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_1, sp);
10373                                 else if (fsig->param_count == 2)
10374                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_2, sp);
10375                                 else if (fsig->param_count == 3)
10376                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_3, sp);
10377                                 else if (fsig->param_count == 4)
10378                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_4, sp);
10379                                 else
10380                                         alloc = handle_array_new (cfg, fsig->param_count, sp, ip);
10381                         } else if (cmethod->string_ctor) {
10382                                 g_assert (!context_used);
10383                                 g_assert (!vtable_arg);
10384                                 /* we simply pass a null pointer */
10385                                 EMIT_NEW_PCONST (cfg, *sp, NULL); 
10386                                 /* now call the string ctor */
10387                                 alloc = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, NULL, NULL, NULL);
10388                         } else {
10389                                 if (cmethod->klass->valuetype) {
10390                                         iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
10391                                         emit_init_rvar (cfg, iargs [0]->dreg, &cmethod->klass->byval_arg);
10392                                         EMIT_NEW_TEMPLOADA (cfg, *sp, iargs [0]->inst_c0);
10393
10394                                         alloc = NULL;
10395
10396                                         /* 
10397                                          * The code generated by mini_emit_virtual_call () expects
10398                                          * iargs [0] to be a boxed instance, but luckily the vcall
10399                                          * will be transformed into a normal call there.
10400                                          */
10401                                 } else if (context_used) {
10402                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, context_used);
10403                                         *sp = alloc;
10404                                 } else {
10405                                         MonoVTable *vtable = NULL;
10406
10407                                         if (!cfg->compile_aot)
10408                                                 vtable = mono_class_vtable (cfg->domain, cmethod->klass);
10409                                         CHECK_TYPELOAD (cmethod->klass);
10410
10411                                         /*
10412                                          * TypeInitializationExceptions thrown from the mono_runtime_class_init
10413                                          * call in mono_jit_runtime_invoke () can abort the finalizer thread.
10414                                          * As a workaround, we call class cctors before allocating objects.
10415                                          */
10416                                         if (mini_field_access_needs_cctor_run (cfg, method, cmethod->klass, vtable) && !(g_slist_find (class_inits, cmethod->klass))) {
10417                                                 emit_class_init (cfg, cmethod->klass);
10418                                                 if (cfg->verbose_level > 2)
10419                                                         printf ("class %s.%s needs init call for ctor\n", cmethod->klass->name_space, cmethod->klass->name);
10420                                                 class_inits = g_slist_prepend (class_inits, cmethod->klass);
10421                                         }
10422
10423                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, 0);
10424                                         *sp = alloc;
10425                                 }
10426                                 CHECK_CFG_EXCEPTION; /*for handle_alloc*/
10427
10428                                 if (alloc)
10429                                         MONO_EMIT_NEW_UNALU (cfg, OP_NOT_NULL, -1, alloc->dreg);
10430
10431                                 /* Now call the actual ctor */
10432                                 handle_ctor_call (cfg, cmethod, fsig, context_used, sp, ip, &inline_costs);
10433                                 CHECK_CFG_EXCEPTION;
10434                         }
10435
10436                         if (alloc == NULL) {
10437                                 /* Valuetype */
10438                                 EMIT_NEW_TEMPLOAD (cfg, ins, iargs [0]->inst_c0);
10439                                 type_to_eval_stack_type (cfg, &ins->klass->byval_arg, ins);
10440                                 *sp++= ins;
10441                         } else {
10442                                 *sp++ = alloc;
10443                         }
10444                         
10445                         ip += 5;
10446                         inline_costs += 5;
10447                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip - header->code)))
10448                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
10449                         break;
10450                 }
10451                 case CEE_CASTCLASS:
10452                         CHECK_STACK (1);
10453                         --sp;
10454                         CHECK_OPSIZE (5);
10455                         token = read32 (ip + 1);
10456                         klass = mini_get_class (method, token, generic_context);
10457                         CHECK_TYPELOAD (klass);
10458                         if (sp [0]->type != STACK_OBJ)
10459                                 UNVERIFIED;
10460
10461                         ins = handle_castclass (cfg, klass, *sp, ip, &inline_costs);
10462                         CHECK_CFG_EXCEPTION;
10463
10464                         *sp ++ = ins;
10465                         ip += 5;
10466                         break;
10467                 case CEE_ISINST: {
10468                         CHECK_STACK (1);
10469                         --sp;
10470                         CHECK_OPSIZE (5);
10471                         token = read32 (ip + 1);
10472                         klass = mini_get_class (method, token, generic_context);
10473                         CHECK_TYPELOAD (klass);
10474                         if (sp [0]->type != STACK_OBJ)
10475                                 UNVERIFIED;
10476  
10477                         context_used = mini_class_check_context_used (cfg, klass);
10478
10479                         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
10480                                 MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
10481                                 MonoInst *args [3];
10482                                 int idx;
10483
10484                                 /* obj */
10485                                 args [0] = *sp;
10486
10487                                 /* klass */
10488                                 EMIT_NEW_CLASSCONST (cfg, args [1], klass);
10489
10490                                 /* inline cache*/
10491                                 if (cfg->compile_aot) {
10492                                         idx = get_castclass_cache_idx (cfg);
10493                                         EMIT_NEW_AOTCONST (cfg, args [2], MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
10494                                 } else {
10495                                         EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));
10496                                 }
10497
10498                                 *sp++ = mono_emit_method_call (cfg, mono_isinst, args, NULL);
10499                                 ip += 5;
10500                                 inline_costs += 2;
10501                         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
10502                                 MonoMethod *mono_isinst;
10503                                 MonoInst *iargs [1];
10504                                 int costs;
10505
10506                                 mono_isinst = mono_marshal_get_isinst (klass); 
10507                                 iargs [0] = sp [0];
10508
10509                                 costs = inline_method (cfg, mono_isinst, mono_method_signature (mono_isinst), 
10510                                                                            iargs, ip, cfg->real_offset, TRUE);
10511                                 CHECK_CFG_EXCEPTION;
10512                                 g_assert (costs > 0);
10513                                 
10514                                 ip += 5;
10515                                 cfg->real_offset += 5;
10516
10517                                 *sp++= iargs [0];
10518
10519                                 inline_costs += costs;
10520                         }
10521                         else {
10522                                 ins = handle_isinst (cfg, klass, *sp, context_used);
10523                                 CHECK_CFG_EXCEPTION;
10524                                 *sp ++ = ins;
10525                                 ip += 5;
10526                         }
10527                         break;
10528                 }
10529                 case CEE_UNBOX_ANY: {
10530                         MonoInst *res, *addr;
10531
10532                         CHECK_STACK (1);
10533                         --sp;
10534                         CHECK_OPSIZE (5);
10535                         token = read32 (ip + 1);
10536                         klass = mini_get_class (method, token, generic_context);
10537                         CHECK_TYPELOAD (klass);
10538
10539                         mono_save_token_info (cfg, image, token, klass);
10540
10541                         context_used = mini_class_check_context_used (cfg, klass);
10542
10543                         if (mini_is_gsharedvt_klass (klass)) {
10544                                 res = handle_unbox_gsharedvt (cfg, klass, *sp);
10545                                 inline_costs += 2;
10546                         } else if (generic_class_is_reference_type (cfg, klass)) {
10547                                 res = handle_castclass (cfg, klass, *sp, ip, &inline_costs);
10548                                 CHECK_CFG_EXCEPTION;
10549                         } else if (mono_class_is_nullable (klass)) {
10550                                 res = handle_unbox_nullable (cfg, *sp, klass, context_used);
10551                         } else {
10552                                 addr = handle_unbox (cfg, klass, sp, context_used);
10553                                 /* LDOBJ */
10554                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
10555                                 res = ins;
10556                                 inline_costs += 2;
10557                         }
10558
10559                         *sp ++ = res;
10560                         ip += 5;
10561                         break;
10562                 }
10563                 case CEE_BOX: {
10564                         MonoInst *val;
10565                         MonoClass *enum_class;
10566                         MonoMethod *has_flag;
10567
10568                         CHECK_STACK (1);
10569                         --sp;
10570                         val = *sp;
10571                         CHECK_OPSIZE (5);
10572                         token = read32 (ip + 1);
10573                         klass = mini_get_class (method, token, generic_context);
10574                         CHECK_TYPELOAD (klass);
10575
10576                         mono_save_token_info (cfg, image, token, klass);
10577
10578                         context_used = mini_class_check_context_used (cfg, klass);
10579
10580                         if (generic_class_is_reference_type (cfg, klass)) {
10581                                 *sp++ = val;
10582                                 ip += 5;
10583                                 break;
10584                         }
10585
10586                         if (klass == mono_defaults.void_class)
10587                                 UNVERIFIED;
10588                         if (target_type_is_incompatible (cfg, &klass->byval_arg, *sp))
10589                                 UNVERIFIED;
10590                         /* frequent check in generic code: box (struct), brtrue */
10591
10592                         /*
10593                          * Look for:
10594                          *
10595                          *   <push int/long ptr>
10596                          *   <push int/long>
10597                          *   box MyFlags
10598                          *   constrained. MyFlags
10599                          *   callvirt instace bool class [mscorlib] System.Enum::HasFlag (class [mscorlib] System.Enum)
10600                          *
10601                          * If we find this sequence and the operand types on box and constrained
10602                          * are equal, we can emit a specialized instruction sequence instead of
10603                          * the very slow HasFlag () call.
10604                          */
10605                         if ((cfg->opt & MONO_OPT_INTRINS) &&
10606                             /* Cheap checks first. */
10607                             ip + 5 + 6 + 5 < end &&
10608                             ip [5] == CEE_PREFIX1 &&
10609                             ip [6] == CEE_CONSTRAINED_ &&
10610                             ip [11] == CEE_CALLVIRT &&
10611                             ip_in_bb (cfg, cfg->cbb, ip + 5 + 6 + 5) &&
10612                             mono_class_is_enum (klass) &&
10613                             (enum_class = mini_get_class (method, read32 (ip + 7), generic_context)) &&
10614                             (has_flag = mini_get_method (cfg, method, read32 (ip + 12), NULL, generic_context)) &&
10615                             has_flag->klass == mono_defaults.enum_class &&
10616                             !strcmp (has_flag->name, "HasFlag") &&
10617                             has_flag->signature->hasthis &&
10618                             has_flag->signature->param_count == 1) {
10619                                 CHECK_TYPELOAD (enum_class);
10620
10621                                 if (enum_class == klass) {
10622                                         MonoInst *enum_this, *enum_flag;
10623
10624                                         ip += 5 + 6 + 5;
10625                                         --sp;
10626
10627                                         enum_this = sp [0];
10628                                         enum_flag = sp [1];
10629
10630                                         *sp++ = handle_enum_has_flag (cfg, klass, enum_this, enum_flag);
10631                                         break;
10632                                 }
10633                         }
10634
10635                         // FIXME: LLVM can't handle the inconsistent bb linking
10636                         if (!mono_class_is_nullable (klass) &&
10637                                 ip + 5 < end && ip_in_bb (cfg, cfg->cbb, ip + 5) &&
10638                                 (ip [5] == CEE_BRTRUE || 
10639                                  ip [5] == CEE_BRTRUE_S ||
10640                                  ip [5] == CEE_BRFALSE ||
10641                                  ip [5] == CEE_BRFALSE_S)) {
10642                                 gboolean is_true = ip [5] == CEE_BRTRUE || ip [5] == CEE_BRTRUE_S;
10643                                 int dreg;
10644                                 MonoBasicBlock *true_bb, *false_bb;
10645
10646                                 ip += 5;
10647
10648                                 if (cfg->verbose_level > 3) {
10649                                         printf ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
10650                                         printf ("<box+brtrue opt>\n");
10651                                 }
10652
10653                                 switch (*ip) {
10654                                 case CEE_BRTRUE_S:
10655                                 case CEE_BRFALSE_S:
10656                                         CHECK_OPSIZE (2);
10657                                         ip++;
10658                                         target = ip + 1 + (signed char)(*ip);
10659                                         ip++;
10660                                         break;
10661                                 case CEE_BRTRUE:
10662                                 case CEE_BRFALSE:
10663                                         CHECK_OPSIZE (5);
10664                                         ip++;
10665                                         target = ip + 4 + (gint)(read32 (ip));
10666                                         ip += 4;
10667                                         break;
10668                                 default:
10669                                         g_assert_not_reached ();
10670                                 }
10671
10672                                 /* 
10673                                  * We need to link both bblocks, since it is needed for handling stack
10674                                  * arguments correctly (See test_0_box_brtrue_opt_regress_81102).
10675                                  * Branching to only one of them would lead to inconsistencies, so
10676                                  * generate an ICONST+BRTRUE, the branch opts will get rid of them.
10677                                  */
10678                                 GET_BBLOCK (cfg, true_bb, target);
10679                                 GET_BBLOCK (cfg, false_bb, ip);
10680
10681                                 mono_link_bblock (cfg, cfg->cbb, true_bb);
10682                                 mono_link_bblock (cfg, cfg->cbb, false_bb);
10683
10684                                 if (sp != stack_start) {
10685                                         handle_stack_args (cfg, stack_start, sp - stack_start);
10686                                         sp = stack_start;
10687                                         CHECK_UNVERIFIABLE (cfg);
10688                                 }
10689
10690                                 if (COMPILE_LLVM (cfg)) {
10691                                         dreg = alloc_ireg (cfg);
10692                                         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
10693                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, dreg, is_true ? 0 : 1);
10694
10695                                         MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, OP_IBEQ, true_bb, false_bb);
10696                                 } else {
10697                                         /* The JIT can't eliminate the iconst+compare */
10698                                         MONO_INST_NEW (cfg, ins, OP_BR);
10699                                         ins->inst_target_bb = is_true ? true_bb : false_bb;
10700                                         MONO_ADD_INS (cfg->cbb, ins);
10701                                 }
10702
10703                                 start_new_bblock = 1;
10704                                 break;
10705                         }
10706
10707                         *sp++ = handle_box (cfg, val, klass, context_used);
10708
10709                         CHECK_CFG_EXCEPTION;
10710                         ip += 5;
10711                         inline_costs += 1;
10712                         break;
10713                 }
10714                 case CEE_UNBOX: {
10715                         CHECK_STACK (1);
10716                         --sp;
10717                         CHECK_OPSIZE (5);
10718                         token = read32 (ip + 1);
10719                         klass = mini_get_class (method, token, generic_context);
10720                         CHECK_TYPELOAD (klass);
10721
10722                         mono_save_token_info (cfg, image, token, klass);
10723
10724                         context_used = mini_class_check_context_used (cfg, klass);
10725
10726                         if (mono_class_is_nullable (klass)) {
10727                                 MonoInst *val;
10728
10729                                 val = handle_unbox_nullable (cfg, *sp, klass, context_used);
10730                                 EMIT_NEW_VARLOADA (cfg, ins, get_vreg_to_inst (cfg, val->dreg), &val->klass->byval_arg);
10731
10732                                 *sp++= ins;
10733                         } else {
10734                                 ins = handle_unbox (cfg, klass, sp, context_used);
10735                                 *sp++ = ins;
10736                         }
10737                         ip += 5;
10738                         inline_costs += 2;
10739                         break;
10740                 }
10741                 case CEE_LDFLD:
10742                 case CEE_LDFLDA:
10743                 case CEE_STFLD:
10744                 case CEE_LDSFLD:
10745                 case CEE_LDSFLDA:
10746                 case CEE_STSFLD: {
10747                         MonoClassField *field;
10748 #ifndef DISABLE_REMOTING
10749                         int costs;
10750 #endif
10751                         guint foffset;
10752                         gboolean is_instance;
10753                         int op;
10754                         gpointer addr = NULL;
10755                         gboolean is_special_static;
10756                         MonoType *ftype;
10757                         MonoInst *store_val = NULL;
10758                         MonoInst *thread_ins;
10759
10760                         op = *ip;
10761                         is_instance = (op == CEE_LDFLD || op == CEE_LDFLDA || op == CEE_STFLD);
10762                         if (is_instance) {
10763                                 if (op == CEE_STFLD) {
10764                                         CHECK_STACK (2);
10765                                         sp -= 2;
10766                                         store_val = sp [1];
10767                                 } else {
10768                                         CHECK_STACK (1);
10769                                         --sp;
10770                                 }
10771                                 if (sp [0]->type == STACK_I4 || sp [0]->type == STACK_I8 || sp [0]->type == STACK_R8)
10772                                         UNVERIFIED;
10773                                 if (*ip != CEE_LDFLD && sp [0]->type == STACK_VTYPE)
10774                                         UNVERIFIED;
10775                         } else {
10776                                 if (op == CEE_STSFLD) {
10777                                         CHECK_STACK (1);
10778                                         sp--;
10779                                         store_val = sp [0];
10780                                 }
10781                         }
10782
10783                         CHECK_OPSIZE (5);
10784                         token = read32 (ip + 1);
10785                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
10786                                 field = mono_method_get_wrapper_data (method, token);
10787                                 klass = field->parent;
10788                         }
10789                         else {
10790                                 field = mono_field_from_token_checked (image, token, &klass, generic_context, &cfg->error);
10791                                 CHECK_CFG_ERROR;
10792                         }
10793                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
10794                                 FIELD_ACCESS_FAILURE (method, field);
10795                         mono_class_init (klass);
10796
10797                         /* if the class is Critical then transparent code cannot access it's fields */
10798                         if (!is_instance && mono_security_core_clr_enabled ())
10799                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
10800
10801                         /* XXX this is technically required but, so far (SL2), no [SecurityCritical] types (not many exists) have
10802                            any visible *instance* field  (in fact there's a single case for a static field in Marshal) XXX
10803                         if (mono_security_core_clr_enabled ())
10804                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
10805                         */
10806
10807                         /*
10808                          * LDFLD etc. is usable on static fields as well, so convert those cases to
10809                          * the static case.
10810                          */
10811                         if (is_instance && field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
10812                                 switch (op) {
10813                                 case CEE_LDFLD:
10814                                         op = CEE_LDSFLD;
10815                                         break;
10816                                 case CEE_STFLD:
10817                                         op = CEE_STSFLD;
10818                                         break;
10819                                 case CEE_LDFLDA:
10820                                         op = CEE_LDSFLDA;
10821                                         break;
10822                                 default:
10823                                         g_assert_not_reached ();
10824                                 }
10825                                 is_instance = FALSE;
10826                         }
10827
10828                         context_used = mini_class_check_context_used (cfg, klass);
10829
10830                         /* INSTANCE CASE */
10831
10832                         foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
10833                         if (op == CEE_STFLD) {
10834                                 if (target_type_is_incompatible (cfg, field->type, sp [1]))
10835                                         UNVERIFIED;
10836 #ifndef DISABLE_REMOTING
10837                                 if ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class) {
10838                                         MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type); 
10839                                         MonoInst *iargs [5];
10840
10841                                         GSHAREDVT_FAILURE (op);
10842
10843                                         iargs [0] = sp [0];
10844                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
10845                                         EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
10846                                         EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : 
10847                                                     field->offset);
10848                                         iargs [4] = sp [1];
10849
10850                                         if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
10851                                                 costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), 
10852                                                                                            iargs, ip, cfg->real_offset, TRUE);
10853                                                 CHECK_CFG_EXCEPTION;
10854                                                 g_assert (costs > 0);
10855                                                       
10856                                                 cfg->real_offset += 5;
10857
10858                                                 inline_costs += costs;
10859                                         } else {
10860                                                 mono_emit_method_call (cfg, stfld_wrapper, iargs, NULL);
10861                                         }
10862                                 } else
10863 #endif
10864                                 {
10865                                         MonoInst *store;
10866
10867                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
10868
10869                                         if (mini_is_gsharedvt_klass (klass)) {
10870                                                 MonoInst *offset_ins;
10871
10872                                                 context_used = mini_class_check_context_used (cfg, klass);
10873
10874                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10875                                                 dreg = alloc_ireg_mp (cfg);
10876                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
10877                                                 /* The decomposition will call mini_emit_stobj () which will emit a wbarrier if needed */
10878                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, dreg, 0, sp [1]->dreg);
10879                                         } else {
10880                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, sp [0]->dreg, foffset, sp [1]->dreg);
10881                                         }
10882                                         if (sp [0]->opcode != OP_LDADDR)
10883                                                 store->flags |= MONO_INST_FAULT;
10884
10885                                 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)) {
10886                                         /* insert call to write barrier */
10887                                         MonoInst *ptr;
10888                                         int dreg;
10889
10890                                         dreg = alloc_ireg_mp (cfg);
10891                                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
10892                                         emit_write_barrier (cfg, ptr, sp [1]);
10893                                 }
10894
10895                                         store->flags |= ins_flag;
10896                                 }
10897                                 ins_flag = 0;
10898                                 ip += 5;
10899                                 break;
10900                         }
10901
10902 #ifndef DISABLE_REMOTING
10903                         if (is_instance && ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class)) {
10904                                 MonoMethod *wrapper = (op == CEE_LDFLDA) ? mono_marshal_get_ldflda_wrapper (field->type) : mono_marshal_get_ldfld_wrapper (field->type); 
10905                                 MonoInst *iargs [4];
10906
10907                                 GSHAREDVT_FAILURE (op);
10908
10909                                 iargs [0] = sp [0];
10910                                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
10911                                 EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
10912                                 EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
10913                                 if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
10914                                         costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), 
10915                                                                                    iargs, ip, cfg->real_offset, TRUE);
10916                                         CHECK_CFG_EXCEPTION;
10917                                         g_assert (costs > 0);
10918                                                       
10919                                         cfg->real_offset += 5;
10920
10921                                         *sp++ = iargs [0];
10922
10923                                         inline_costs += costs;
10924                                 } else {
10925                                         ins = mono_emit_method_call (cfg, wrapper, iargs, NULL);
10926                                         *sp++ = ins;
10927                                 }
10928                         } else 
10929 #endif
10930                         if (is_instance) {
10931                                 if (sp [0]->type == STACK_VTYPE) {
10932                                         MonoInst *var;
10933
10934                                         /* Have to compute the address of the variable */
10935
10936                                         var = get_vreg_to_inst (cfg, sp [0]->dreg);
10937                                         if (!var)
10938                                                 var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, sp [0]->dreg);
10939                                         else
10940                                                 g_assert (var->klass == klass);
10941                                         
10942                                         EMIT_NEW_VARLOADA (cfg, ins, var, &var->klass->byval_arg);
10943                                         sp [0] = ins;
10944                                 }
10945
10946                                 if (op == CEE_LDFLDA) {
10947                                         if (sp [0]->type == STACK_OBJ) {
10948                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
10949                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "NullReferenceException");
10950                                         }
10951
10952                                         dreg = alloc_ireg_mp (cfg);
10953
10954                                         if (mini_is_gsharedvt_klass (klass)) {
10955                                                 MonoInst *offset_ins;
10956
10957                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10958                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
10959                                         } else {
10960                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
10961                                         }
10962                                         ins->klass = mono_class_from_mono_type (field->type);
10963                                         ins->type = STACK_MP;
10964                                         *sp++ = ins;
10965                                 } else {
10966                                         MonoInst *load;
10967
10968                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
10969
10970                                         if (mini_is_gsharedvt_klass (klass)) {
10971                                                 MonoInst *offset_ins;
10972
10973                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10974                                                 dreg = alloc_ireg_mp (cfg);
10975                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
10976                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, dreg, 0);
10977                                         } else {
10978                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, sp [0]->dreg, foffset);
10979                                         }
10980                                         load->flags |= ins_flag;
10981                                         if (sp [0]->opcode != OP_LDADDR)
10982                                                 load->flags |= MONO_INST_FAULT;
10983                                         *sp++ = load;
10984                                 }
10985                         }
10986
10987                         if (is_instance) {
10988                                 ins_flag = 0;
10989                                 ip += 5;
10990                                 break;
10991                         }
10992
10993                         /* STATIC CASE */
10994                         context_used = mini_class_check_context_used (cfg, klass);
10995
10996                         ftype = mono_field_get_type (field);
10997
10998                         if (ftype->attrs & FIELD_ATTRIBUTE_LITERAL)
10999                                 UNVERIFIED;
11000
11001                         /* The special_static_fields field is init'd in mono_class_vtable, so it needs
11002                          * to be called here.
11003                          */
11004                         if (!context_used && !(cfg->opt & MONO_OPT_SHARED)) {
11005                                 mono_class_vtable (cfg->domain, klass);
11006                                 CHECK_TYPELOAD (klass);
11007                         }
11008                         mono_domain_lock (cfg->domain);
11009                         if (cfg->domain->special_static_fields)
11010                                 addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
11011                         mono_domain_unlock (cfg->domain);
11012
11013                         is_special_static = mono_class_field_is_special_static (field);
11014
11015                         if (is_special_static && ((gsize)addr & 0x80000000) == 0)
11016                                 thread_ins = mono_get_thread_intrinsic (cfg);
11017                         else
11018                                 thread_ins = NULL;
11019
11020                         /* Generate IR to compute the field address */
11021                         if (is_special_static && ((gsize)addr & 0x80000000) == 0 && thread_ins && !(cfg->opt & MONO_OPT_SHARED) && !context_used) {
11022                                 /*
11023                                  * Fast access to TLS data
11024                                  * Inline version of get_thread_static_data () in
11025                                  * threads.c.
11026                                  */
11027                                 guint32 offset;
11028                                 int idx, static_data_reg, array_reg, dreg;
11029
11030                                 GSHAREDVT_FAILURE (op);
11031
11032                                 MONO_ADD_INS (cfg->cbb, thread_ins);
11033                                 static_data_reg = alloc_ireg (cfg);
11034                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, MONO_STRUCT_OFFSET (MonoInternalThread, static_data));
11035
11036                                 if (cfg->compile_aot) {
11037                                         int offset_reg, offset2_reg, idx_reg;
11038
11039                                         /* For TLS variables, this will return the TLS offset */
11040                                         EMIT_NEW_SFLDACONST (cfg, ins, field);
11041                                         offset_reg = ins->dreg;
11042                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset_reg, offset_reg, 0x7fffffff);
11043                                         idx_reg = alloc_ireg (cfg);
11044                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, idx_reg, offset_reg, 0x3f);
11045                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
11046                                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
11047                                         array_reg = alloc_ireg (cfg);
11048                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
11049                                         offset2_reg = alloc_ireg (cfg);
11050                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, offset2_reg, offset_reg, 6);
11051                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset2_reg, 0x1ffffff);
11052                                         dreg = alloc_ireg (cfg);
11053                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, array_reg, offset2_reg);
11054                                 } else {
11055                                         offset = (gsize)addr & 0x7fffffff;
11056                                         idx = offset & 0x3f;
11057
11058                                         array_reg = alloc_ireg (cfg);
11059                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, idx * sizeof (gpointer));
11060                                         dreg = alloc_ireg (cfg);
11061                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_ADD_IMM, dreg, array_reg, ((offset >> 6) & 0x1ffffff));
11062                                 }
11063                         } else if ((cfg->opt & MONO_OPT_SHARED) ||
11064                                         (cfg->compile_aot && is_special_static) ||
11065                                         (context_used && is_special_static)) {
11066                                 MonoInst *iargs [2];
11067
11068                                 g_assert (field->parent);
11069                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11070                                 if (context_used) {
11071                                         iargs [1] = emit_get_rgctx_field (cfg, context_used,
11072                                                 field, MONO_RGCTX_INFO_CLASS_FIELD);
11073                                 } else {
11074                                         EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
11075                                 }
11076                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
11077                         } else if (context_used) {
11078                                 MonoInst *static_data;
11079
11080                                 /*
11081                                 g_print ("sharing static field access in %s.%s.%s - depth %d offset %d\n",
11082                                         method->klass->name_space, method->klass->name, method->name,
11083                                         depth, field->offset);
11084                                 */
11085
11086                                 if (mono_class_needs_cctor_run (klass, method))
11087                                         emit_class_init (cfg, klass);
11088
11089                                 /*
11090                                  * The pointer we're computing here is
11091                                  *
11092                                  *   super_info.static_data + field->offset
11093                                  */
11094                                 static_data = emit_get_rgctx_klass (cfg, context_used,
11095                                         klass, MONO_RGCTX_INFO_STATIC_DATA);
11096
11097                                 if (mini_is_gsharedvt_klass (klass)) {
11098                                         MonoInst *offset_ins;
11099
11100                                         offset_ins = emit_get_rgctx_field (cfg, context_used, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11101                                         dreg = alloc_ireg_mp (cfg);
11102                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, static_data->dreg, offset_ins->dreg);
11103                                 } else if (field->offset == 0) {
11104                                         ins = static_data;
11105                                 } else {
11106                                         int addr_reg = mono_alloc_preg (cfg);
11107                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, addr_reg, static_data->dreg, field->offset);
11108                                 }
11109                                 } else if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
11110                                 MonoInst *iargs [2];
11111
11112                                 g_assert (field->parent);
11113                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11114                                 EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
11115                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
11116                         } else {
11117                                 MonoVTable *vtable = NULL;
11118
11119                                 if (!cfg->compile_aot)
11120                                         vtable = mono_class_vtable (cfg->domain, klass);
11121                                 CHECK_TYPELOAD (klass);
11122
11123                                 if (!addr) {
11124                                         if (mini_field_access_needs_cctor_run (cfg, method, klass, vtable)) {
11125                                                 if (!(g_slist_find (class_inits, klass))) {
11126                                                         emit_class_init (cfg, klass);
11127                                                         if (cfg->verbose_level > 2)
11128                                                                 printf ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, mono_field_get_name (field));
11129                                                         class_inits = g_slist_prepend (class_inits, klass);
11130                                                 }
11131                                         } else {
11132                                                 if (cfg->run_cctors) {
11133                                                         MonoException *ex;
11134                                                         /* This makes so that inline cannot trigger */
11135                                                         /* .cctors: too many apps depend on them */
11136                                                         /* running with a specific order... */
11137                                                         g_assert (vtable);
11138                                                         if (! vtable->initialized)
11139                                                                 INLINE_FAILURE ("class init");
11140                                                         ex = mono_runtime_class_init_full (vtable, FALSE);
11141                                                         if (ex) {
11142                                                                 set_exception_object (cfg, ex);
11143                                                                 goto exception_exit;
11144                                                         }
11145                                                 }
11146                                         }
11147                                         if (cfg->compile_aot)
11148                                                 EMIT_NEW_SFLDACONST (cfg, ins, field);
11149                                         else {
11150                                                 g_assert (vtable);
11151                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11152                                                 g_assert (addr);
11153                                                 EMIT_NEW_PCONST (cfg, ins, addr);
11154                                         }
11155                                 } else {
11156                                         MonoInst *iargs [1];
11157                                         EMIT_NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
11158                                         ins = mono_emit_jit_icall (cfg, mono_get_special_static_data, iargs);
11159                                 }
11160                         }
11161
11162                         /* Generate IR to do the actual load/store operation */
11163
11164                         if ((op == CEE_STFLD || op == CEE_STSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11165                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11166                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11167                         }
11168
11169                         if (op == CEE_LDSFLDA) {
11170                                 ins->klass = mono_class_from_mono_type (ftype);
11171                                 ins->type = STACK_PTR;
11172                                 *sp++ = ins;
11173                         } else if (op == CEE_STSFLD) {
11174                                 MonoInst *store;
11175
11176                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, ftype, ins->dreg, 0, store_val->dreg);
11177                                 store->flags |= ins_flag;
11178                         } else {
11179                                 gboolean is_const = FALSE;
11180                                 MonoVTable *vtable = NULL;
11181                                 gpointer addr = NULL;
11182
11183                                 if (!context_used) {
11184                                         vtable = mono_class_vtable (cfg->domain, klass);
11185                                         CHECK_TYPELOAD (klass);
11186                                 }
11187                                 if ((ftype->attrs & FIELD_ATTRIBUTE_INIT_ONLY) && (((addr = mono_aot_readonly_field_override (field)) != NULL) ||
11188                                                 (!context_used && !((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && vtable->initialized))) {
11189                                         int ro_type = ftype->type;
11190                                         if (!addr)
11191                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11192                                         if (ro_type == MONO_TYPE_VALUETYPE && ftype->data.klass->enumtype) {
11193                                                 ro_type = mono_class_enum_basetype (ftype->data.klass)->type;
11194                                         }
11195
11196                                         GSHAREDVT_FAILURE (op);
11197
11198                                         /* printf ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, mono_field_get_name (field));*/
11199                                         is_const = TRUE;
11200                                         switch (ro_type) {
11201                                         case MONO_TYPE_BOOLEAN:
11202                                         case MONO_TYPE_U1:
11203                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint8 *)addr));
11204                                                 sp++;
11205                                                 break;
11206                                         case MONO_TYPE_I1:
11207                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint8 *)addr));
11208                                                 sp++;
11209                                                 break;                                          
11210                                         case MONO_TYPE_CHAR:
11211                                         case MONO_TYPE_U2:
11212                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint16 *)addr));
11213                                                 sp++;
11214                                                 break;
11215                                         case MONO_TYPE_I2:
11216                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint16 *)addr));
11217                                                 sp++;
11218                                                 break;
11219                                                 break;
11220                                         case MONO_TYPE_I4:
11221                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint32 *)addr));
11222                                                 sp++;
11223                                                 break;                                          
11224                                         case MONO_TYPE_U4:
11225                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint32 *)addr));
11226                                                 sp++;
11227                                                 break;
11228                                         case MONO_TYPE_I:
11229                                         case MONO_TYPE_U:
11230                                         case MONO_TYPE_PTR:
11231                                         case MONO_TYPE_FNPTR:
11232                                                 EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11233                                                 type_to_eval_stack_type ((cfg), field->type, *sp);
11234                                                 sp++;
11235                                                 break;
11236                                         case MONO_TYPE_STRING:
11237                                         case MONO_TYPE_OBJECT:
11238                                         case MONO_TYPE_CLASS:
11239                                         case MONO_TYPE_SZARRAY:
11240                                         case MONO_TYPE_ARRAY:
11241                                                 if (!mono_gc_is_moving ()) {
11242                                                         EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11243                                                         type_to_eval_stack_type ((cfg), field->type, *sp);
11244                                                         sp++;
11245                                                 } else {
11246                                                         is_const = FALSE;
11247                                                 }
11248                                                 break;
11249                                         case MONO_TYPE_I8:
11250                                         case MONO_TYPE_U8:
11251                                                 EMIT_NEW_I8CONST (cfg, *sp, *((gint64 *)addr));
11252                                                 sp++;
11253                                                 break;
11254                                         case MONO_TYPE_R4:
11255                                         case MONO_TYPE_R8:
11256                                         case MONO_TYPE_VALUETYPE:
11257                                         default:
11258                                                 is_const = FALSE;
11259                                                 break;
11260                                         }
11261                                 }
11262
11263                                 if (!is_const) {
11264                                         MonoInst *load;
11265
11266                                         CHECK_STACK_OVF (1);
11267
11268                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, ins->dreg, 0);
11269                                         load->flags |= ins_flag;
11270                                         ins_flag = 0;
11271                                         *sp++ = load;
11272                                 }
11273                         }
11274
11275                         if ((op == CEE_LDFLD || op == CEE_LDSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11276                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
11277                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
11278                         }
11279
11280                         ins_flag = 0;
11281                         ip += 5;
11282                         break;
11283                 }
11284                 case CEE_STOBJ:
11285                         CHECK_STACK (2);
11286                         sp -= 2;
11287                         CHECK_OPSIZE (5);
11288                         token = read32 (ip + 1);
11289                         klass = mini_get_class (method, token, generic_context);
11290                         CHECK_TYPELOAD (klass);
11291                         if (ins_flag & MONO_INST_VOLATILE) {
11292                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11293                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11294                         }
11295                         /* FIXME: should check item at sp [1] is compatible with the type of the store. */
11296                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0, sp [1]->dreg);
11297                         ins->flags |= ins_flag;
11298                         if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER &&
11299                                         generic_class_is_reference_type (cfg, klass)) {
11300                                 /* insert call to write barrier */
11301                                 emit_write_barrier (cfg, sp [0], sp [1]);
11302                         }
11303                         ins_flag = 0;
11304                         ip += 5;
11305                         inline_costs += 1;
11306                         break;
11307
11308                         /*
11309                          * Array opcodes
11310                          */
11311                 case CEE_NEWARR: {
11312                         MonoInst *len_ins;
11313                         const char *data_ptr;
11314                         int data_size = 0;
11315                         guint32 field_token;
11316
11317                         CHECK_STACK (1);
11318                         --sp;
11319
11320                         CHECK_OPSIZE (5);
11321                         token = read32 (ip + 1);
11322
11323                         klass = mini_get_class (method, token, generic_context);
11324                         CHECK_TYPELOAD (klass);
11325
11326                         context_used = mini_class_check_context_used (cfg, klass);
11327
11328                         if (sp [0]->type == STACK_I8 || (SIZEOF_VOID_P == 8 && sp [0]->type == STACK_PTR)) {
11329                                 MONO_INST_NEW (cfg, ins, OP_LCONV_TO_OVF_U4);
11330                                 ins->sreg1 = sp [0]->dreg;
11331                                 ins->type = STACK_I4;
11332                                 ins->dreg = alloc_ireg (cfg);
11333                                 MONO_ADD_INS (cfg->cbb, ins);
11334                                 *sp = mono_decompose_opcode (cfg, ins);
11335                         }
11336
11337                         if (context_used) {
11338                                 MonoInst *args [3];
11339                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11340                                 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
11341
11342                                 /* FIXME: Use OP_NEWARR and decompose later to help abcrem */
11343
11344                                 /* vtable */
11345                                 args [0] = emit_get_rgctx_klass (cfg, context_used,
11346                                         array_class, MONO_RGCTX_INFO_VTABLE);
11347                                 /* array len */
11348                                 args [1] = sp [0];
11349
11350                                 if (managed_alloc)
11351                                         ins = mono_emit_method_call (cfg, managed_alloc, args, NULL);
11352                                 else
11353                                         ins = mono_emit_jit_icall (cfg, mono_array_new_specific, args);
11354                         } else {
11355                                 if (cfg->opt & MONO_OPT_SHARED) {
11356                                         /* Decompose now to avoid problems with references to the domainvar */
11357                                         MonoInst *iargs [3];
11358
11359                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11360                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11361                                         iargs [2] = sp [0];
11362
11363                                         ins = mono_emit_jit_icall (cfg, mono_array_new, iargs);
11364                                 } else {
11365                                         /* Decompose later since it is needed by abcrem */
11366                                         MonoClass *array_type = mono_array_class_get (klass, 1);
11367                                         mono_class_vtable (cfg->domain, array_type);
11368                                         CHECK_TYPELOAD (array_type);
11369
11370                                         MONO_INST_NEW (cfg, ins, OP_NEWARR);
11371                                         ins->dreg = alloc_ireg_ref (cfg);
11372                                         ins->sreg1 = sp [0]->dreg;
11373                                         ins->inst_newa_class = klass;
11374                                         ins->type = STACK_OBJ;
11375                                         ins->klass = array_type;
11376                                         MONO_ADD_INS (cfg->cbb, ins);
11377                                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11378                                         cfg->cbb->has_array_access = TRUE;
11379
11380                                         /* Needed so mono_emit_load_get_addr () gets called */
11381                                         mono_get_got_var (cfg);
11382                                 }
11383                         }
11384
11385                         len_ins = sp [0];
11386                         ip += 5;
11387                         *sp++ = ins;
11388                         inline_costs += 1;
11389
11390                         /* 
11391                          * we inline/optimize the initialization sequence if possible.
11392                          * we should also allocate the array as not cleared, since we spend as much time clearing to 0 as initializing
11393                          * for small sizes open code the memcpy
11394                          * ensure the rva field is big enough
11395                          */
11396                         if ((cfg->opt & MONO_OPT_INTRINS) && ip + 6 < end && ip_in_bb (cfg, cfg->cbb, 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))) {
11397                                 MonoMethod *memcpy_method = get_memcpy_method ();
11398                                 MonoInst *iargs [3];
11399                                 int add_reg = alloc_ireg_mp (cfg);
11400
11401                                 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, add_reg, ins->dreg, MONO_STRUCT_OFFSET (MonoArray, vector));
11402                                 if (cfg->compile_aot) {
11403                                         EMIT_NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(field_token), STACK_PTR, NULL);
11404                                 } else {
11405                                         EMIT_NEW_PCONST (cfg, iargs [1], (char*)data_ptr);
11406                                 }
11407                                 EMIT_NEW_ICONST (cfg, iargs [2], data_size);
11408                                 mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
11409                                 ip += 11;
11410                         }
11411
11412                         break;
11413                 }
11414                 case CEE_LDLEN:
11415                         CHECK_STACK (1);
11416                         --sp;
11417                         if (sp [0]->type != STACK_OBJ)
11418                                 UNVERIFIED;
11419
11420                         MONO_INST_NEW (cfg, ins, OP_LDLEN);
11421                         ins->dreg = alloc_preg (cfg);
11422                         ins->sreg1 = sp [0]->dreg;
11423                         ins->type = STACK_I4;
11424                         /* This flag will be inherited by the decomposition */
11425                         ins->flags |= MONO_INST_FAULT;
11426                         MONO_ADD_INS (cfg->cbb, ins);
11427                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11428                         cfg->cbb->has_array_access = TRUE;
11429                         ip ++;
11430                         *sp++ = ins;
11431                         break;
11432                 case CEE_LDELEMA:
11433                         CHECK_STACK (2);
11434                         sp -= 2;
11435                         CHECK_OPSIZE (5);
11436                         if (sp [0]->type != STACK_OBJ)
11437                                 UNVERIFIED;
11438
11439                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11440
11441                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11442                         CHECK_TYPELOAD (klass);
11443                         /* we need to make sure that this array is exactly the type it needs
11444                          * to be for correctness. the wrappers are lax with their usage
11445                          * so we need to ignore them here
11446                          */
11447                         if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE && !readonly) {
11448                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11449                                 mini_emit_check_array_type (cfg, sp [0], array_class);
11450                                 CHECK_TYPELOAD (array_class);
11451                         }
11452
11453                         readonly = FALSE;
11454                         ins = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11455                         *sp++ = ins;
11456                         ip += 5;
11457                         break;
11458                 case CEE_LDELEM:
11459                 case CEE_LDELEM_I1:
11460                 case CEE_LDELEM_U1:
11461                 case CEE_LDELEM_I2:
11462                 case CEE_LDELEM_U2:
11463                 case CEE_LDELEM_I4:
11464                 case CEE_LDELEM_U4:
11465                 case CEE_LDELEM_I8:
11466                 case CEE_LDELEM_I:
11467                 case CEE_LDELEM_R4:
11468                 case CEE_LDELEM_R8:
11469                 case CEE_LDELEM_REF: {
11470                         MonoInst *addr;
11471
11472                         CHECK_STACK (2);
11473                         sp -= 2;
11474
11475                         if (*ip == CEE_LDELEM) {
11476                                 CHECK_OPSIZE (5);
11477                                 token = read32 (ip + 1);
11478                                 klass = mini_get_class (method, token, generic_context);
11479                                 CHECK_TYPELOAD (klass);
11480                                 mono_class_init (klass);
11481                         }
11482                         else
11483                                 klass = array_access_to_klass (*ip);
11484
11485                         if (sp [0]->type != STACK_OBJ)
11486                                 UNVERIFIED;
11487
11488                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11489
11490                         if (mini_is_gsharedvt_variable_klass (klass)) {
11491                                 // FIXME-VT: OP_ICONST optimization
11492                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11493                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11494                                 ins->opcode = OP_LOADV_MEMBASE;
11495                         } else if (sp [1]->opcode == OP_ICONST) {
11496                                 int array_reg = sp [0]->dreg;
11497                                 int index_reg = sp [1]->dreg;
11498                                 int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
11499
11500                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
11501                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset);
11502                         } else {
11503                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11504                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11505                         }
11506                         *sp++ = ins;
11507                         if (*ip == CEE_LDELEM)
11508                                 ip += 5;
11509                         else
11510                                 ++ip;
11511                         break;
11512                 }
11513                 case CEE_STELEM_I:
11514                 case CEE_STELEM_I1:
11515                 case CEE_STELEM_I2:
11516                 case CEE_STELEM_I4:
11517                 case CEE_STELEM_I8:
11518                 case CEE_STELEM_R4:
11519                 case CEE_STELEM_R8:
11520                 case CEE_STELEM_REF:
11521                 case CEE_STELEM: {
11522                         CHECK_STACK (3);
11523                         sp -= 3;
11524
11525                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11526
11527                         if (*ip == CEE_STELEM) {
11528                                 CHECK_OPSIZE (5);
11529                                 token = read32 (ip + 1);
11530                                 klass = mini_get_class (method, token, generic_context);
11531                                 CHECK_TYPELOAD (klass);
11532                                 mono_class_init (klass);
11533                         }
11534                         else
11535                                 klass = array_access_to_klass (*ip);
11536
11537                         if (sp [0]->type != STACK_OBJ)
11538                                 UNVERIFIED;
11539
11540                         emit_array_store (cfg, klass, sp, TRUE);
11541
11542                         if (*ip == CEE_STELEM)
11543                                 ip += 5;
11544                         else
11545                                 ++ip;
11546                         inline_costs += 1;
11547                         break;
11548                 }
11549                 case CEE_CKFINITE: {
11550                         CHECK_STACK (1);
11551                         --sp;
11552
11553                         MONO_INST_NEW (cfg, ins, OP_CKFINITE);
11554                         ins->sreg1 = sp [0]->dreg;
11555                         ins->dreg = alloc_freg (cfg);
11556                         ins->type = STACK_R8;
11557                         MONO_ADD_INS (cfg->cbb, ins);
11558
11559                         *sp++ = mono_decompose_opcode (cfg, ins);
11560
11561                         ++ip;
11562                         break;
11563                 }
11564                 case CEE_REFANYVAL: {
11565                         MonoInst *src_var, *src;
11566
11567                         int klass_reg = alloc_preg (cfg);
11568                         int dreg = alloc_preg (cfg);
11569
11570                         GSHAREDVT_FAILURE (*ip);
11571
11572                         CHECK_STACK (1);
11573                         MONO_INST_NEW (cfg, ins, *ip);
11574                         --sp;
11575                         CHECK_OPSIZE (5);
11576                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11577                         CHECK_TYPELOAD (klass);
11578
11579                         context_used = mini_class_check_context_used (cfg, klass);
11580
11581                         // FIXME:
11582                         src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
11583                         if (!src_var)
11584                                 src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
11585                         EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
11586                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass));
11587
11588                         if (context_used) {
11589                                 MonoInst *klass_ins;
11590
11591                                 klass_ins = emit_get_rgctx_klass (cfg, context_used,
11592                                                 klass, MONO_RGCTX_INFO_KLASS);
11593
11594                                 // FIXME:
11595                                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_ins->dreg);
11596                                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
11597                         } else {
11598                                 mini_emit_class_check (cfg, klass_reg, klass);
11599                         }
11600                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value));
11601                         ins->type = STACK_MP;
11602                         ins->klass = klass;
11603                         *sp++ = ins;
11604                         ip += 5;
11605                         break;
11606                 }
11607                 case CEE_MKREFANY: {
11608                         MonoInst *loc, *addr;
11609
11610                         GSHAREDVT_FAILURE (*ip);
11611
11612                         CHECK_STACK (1);
11613                         MONO_INST_NEW (cfg, ins, *ip);
11614                         --sp;
11615                         CHECK_OPSIZE (5);
11616                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11617                         CHECK_TYPELOAD (klass);
11618
11619                         context_used = mini_class_check_context_used (cfg, klass);
11620
11621                         loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
11622                         EMIT_NEW_TEMPLOADA (cfg, addr, loc->inst_c0);
11623
11624                         if (context_used) {
11625                                 MonoInst *const_ins;
11626                                 int type_reg = alloc_preg (cfg);
11627
11628                                 const_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
11629                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_ins->dreg);
11630                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_ins->dreg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
11631                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
11632                         } else if (cfg->compile_aot) {
11633                                 int const_reg = alloc_preg (cfg);
11634                                 int type_reg = alloc_preg (cfg);
11635
11636                                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
11637                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_reg);
11638                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_reg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
11639                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
11640                         } else {
11641                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), &klass->byval_arg);
11642                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), klass);
11643                         }
11644                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value), sp [0]->dreg);
11645
11646                         EMIT_NEW_TEMPLOAD (cfg, ins, loc->inst_c0);
11647                         ins->type = STACK_VTYPE;
11648                         ins->klass = mono_defaults.typed_reference_class;
11649                         *sp++ = ins;
11650                         ip += 5;
11651                         break;
11652                 }
11653                 case CEE_LDTOKEN: {
11654                         gpointer handle;
11655                         MonoClass *handle_class;
11656
11657                         CHECK_STACK_OVF (1);
11658
11659                         CHECK_OPSIZE (5);
11660                         n = read32 (ip + 1);
11661
11662                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD ||
11663                                         method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
11664                                 handle = mono_method_get_wrapper_data (method, n);
11665                                 handle_class = mono_method_get_wrapper_data (method, n + 1);
11666                                 if (handle_class == mono_defaults.typehandle_class)
11667                                         handle = &((MonoClass*)handle)->byval_arg;
11668                         }
11669                         else {
11670                                 handle = mono_ldtoken_checked (image, n, &handle_class, generic_context, &cfg->error);
11671                                 CHECK_CFG_ERROR;
11672                         }
11673                         if (!handle)
11674                                 LOAD_ERROR;
11675                         mono_class_init (handle_class);
11676                         if (cfg->gshared) {
11677                                 if (mono_metadata_token_table (n) == MONO_TABLE_TYPEDEF ||
11678                                                 mono_metadata_token_table (n) == MONO_TABLE_TYPEREF) {
11679                                         /* This case handles ldtoken
11680                                            of an open type, like for
11681                                            typeof(Gen<>). */
11682                                         context_used = 0;
11683                                 } else if (handle_class == mono_defaults.typehandle_class) {
11684                                         context_used = mini_class_check_context_used (cfg, mono_class_from_mono_type (handle));
11685                                 } else if (handle_class == mono_defaults.fieldhandle_class)
11686                                         context_used = mini_class_check_context_used (cfg, ((MonoClassField*)handle)->parent);
11687                                 else if (handle_class == mono_defaults.methodhandle_class)
11688                                         context_used = mini_method_check_context_used (cfg, handle);
11689                                 else
11690                                         g_assert_not_reached ();
11691                         }
11692
11693                         if ((cfg->opt & MONO_OPT_SHARED) &&
11694                                         method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD &&
11695                                         method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED) {
11696                                 MonoInst *addr, *vtvar, *iargs [3];
11697                                 int method_context_used;
11698
11699                                 method_context_used = mini_method_check_context_used (cfg, method);
11700
11701                                 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL); 
11702
11703                                 EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
11704                                 EMIT_NEW_ICONST (cfg, iargs [1], n);
11705                                 if (method_context_used) {
11706                                         iargs [2] = emit_get_rgctx_method (cfg, method_context_used,
11707                                                 method, MONO_RGCTX_INFO_METHOD);
11708                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper_generic_shared, iargs);
11709                                 } else {
11710                                         EMIT_NEW_PCONST (cfg, iargs [2], generic_context);
11711                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper, iargs);
11712                                 }
11713                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
11714
11715                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
11716
11717                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
11718                         } else {
11719                                 if ((ip + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 5) && 
11720                                         ((ip [5] == CEE_CALL) || (ip [5] == CEE_CALLVIRT)) && 
11721                                         (cmethod = mini_get_method (cfg, method, read32 (ip + 6), NULL, generic_context)) &&
11722                                         (cmethod->klass == mono_defaults.systemtype_class) &&
11723                                         (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
11724                                         MonoClass *tclass = mono_class_from_mono_type (handle);
11725
11726                                         mono_class_init (tclass);
11727                                         if (context_used) {
11728                                                 ins = emit_get_rgctx_klass (cfg, context_used,
11729                                                         tclass, MONO_RGCTX_INFO_REFLECTION_TYPE);
11730                                         } else if (cfg->compile_aot) {
11731                                                 if (method->wrapper_type) {
11732                                                         mono_error_init (&error); //got to do it since there are multiple conditionals below
11733                                                         if (mono_class_get_checked (tclass->image, tclass->type_token, &error) == tclass && !generic_context) {
11734                                                                 /* Special case for static synchronized wrappers */
11735                                                                 EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, tclass->image, tclass->type_token, generic_context);
11736                                                         } else {
11737                                                                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
11738                                                                 /* FIXME: n is not a normal token */
11739                                                                 DISABLE_AOT (cfg);
11740                                                                 EMIT_NEW_PCONST (cfg, ins, NULL);
11741                                                         }
11742                                                 } else {
11743                                                         EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n, generic_context);
11744                                                 }
11745                                         } else {
11746                                                 EMIT_NEW_PCONST (cfg, ins, mono_type_get_object (cfg->domain, handle));
11747                                         }
11748                                         ins->type = STACK_OBJ;
11749                                         ins->klass = cmethod->klass;
11750                                         ip += 5;
11751                                 } else {
11752                                         MonoInst *addr, *vtvar;
11753
11754                                         vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
11755
11756                                         if (context_used) {
11757                                                 if (handle_class == mono_defaults.typehandle_class) {
11758                                                         ins = emit_get_rgctx_klass (cfg, context_used,
11759                                                                         mono_class_from_mono_type (handle),
11760                                                                         MONO_RGCTX_INFO_TYPE);
11761                                                 } else if (handle_class == mono_defaults.methodhandle_class) {
11762                                                         ins = emit_get_rgctx_method (cfg, context_used,
11763                                                                         handle, MONO_RGCTX_INFO_METHOD);
11764                                                 } else if (handle_class == mono_defaults.fieldhandle_class) {
11765                                                         ins = emit_get_rgctx_field (cfg, context_used,
11766                                                                         handle, MONO_RGCTX_INFO_CLASS_FIELD);
11767                                                 } else {
11768                                                         g_assert_not_reached ();
11769                                                 }
11770                                         } else if (cfg->compile_aot) {
11771                                                 EMIT_NEW_LDTOKENCONST (cfg, ins, image, n, generic_context);
11772                                         } else {
11773                                                 EMIT_NEW_PCONST (cfg, ins, handle);
11774                                         }
11775                                         EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
11776                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
11777                                         EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
11778                                 }
11779                         }
11780
11781                         *sp++ = ins;
11782                         ip += 5;
11783                         break;
11784                 }
11785                 case CEE_THROW:
11786                         CHECK_STACK (1);
11787                         MONO_INST_NEW (cfg, ins, OP_THROW);
11788                         --sp;
11789                         ins->sreg1 = sp [0]->dreg;
11790                         ip++;
11791                         cfg->cbb->out_of_line = TRUE;
11792                         MONO_ADD_INS (cfg->cbb, ins);
11793                         MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
11794                         MONO_ADD_INS (cfg->cbb, ins);
11795                         sp = stack_start;
11796                         
11797                         link_bblock (cfg, cfg->cbb, end_bblock);
11798                         start_new_bblock = 1;
11799                         break;
11800                 case CEE_ENDFINALLY:
11801                         /* mono_save_seq_point_info () depends on this */
11802                         if (sp != stack_start)
11803                                 emit_seq_point (cfg, method, ip, FALSE, FALSE);
11804                         MONO_INST_NEW (cfg, ins, OP_ENDFINALLY);
11805                         MONO_ADD_INS (cfg->cbb, ins);
11806                         ip++;
11807                         start_new_bblock = 1;
11808
11809                         /*
11810                          * Control will leave the method so empty the stack, otherwise
11811                          * the next basic block will start with a nonempty stack.
11812                          */
11813                         while (sp != stack_start) {
11814                                 sp--;
11815                         }
11816                         break;
11817                 case CEE_LEAVE:
11818                 case CEE_LEAVE_S: {
11819                         GList *handlers;
11820
11821                         if (*ip == CEE_LEAVE) {
11822                                 CHECK_OPSIZE (5);
11823                                 target = ip + 5 + (gint32)read32(ip + 1);
11824                         } else {
11825                                 CHECK_OPSIZE (2);
11826                                 target = ip + 2 + (signed char)(ip [1]);
11827                         }
11828
11829                         /* empty the stack */
11830                         while (sp != stack_start) {
11831                                 sp--;
11832                         }
11833
11834                         /* 
11835                          * If this leave statement is in a catch block, check for a
11836                          * pending exception, and rethrow it if necessary.
11837                          * We avoid doing this in runtime invoke wrappers, since those are called
11838                          * by native code which excepts the wrapper to catch all exceptions.
11839                          */
11840                         for (i = 0; i < header->num_clauses; ++i) {
11841                                 MonoExceptionClause *clause = &header->clauses [i];
11842
11843                                 /* 
11844                                  * Use <= in the final comparison to handle clauses with multiple
11845                                  * leave statements, like in bug #78024.
11846                                  * The ordering of the exception clauses guarantees that we find the
11847                                  * innermost clause.
11848                                  */
11849                                 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) {
11850                                         MonoInst *exc_ins;
11851                                         MonoBasicBlock *dont_throw;
11852
11853                                         /*
11854                                           MonoInst *load;
11855
11856                                           NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, clause->handler_offset)->inst_c0);
11857                                         */
11858
11859                                         exc_ins = mono_emit_jit_icall (cfg, mono_thread_get_undeniable_exception, NULL);
11860
11861                                         NEW_BBLOCK (cfg, dont_throw);
11862
11863                                         /*
11864                                          * Currently, we always rethrow the abort exception, despite the 
11865                                          * fact that this is not correct. See thread6.cs for an example. 
11866                                          * But propagating the abort exception is more important than 
11867                                          * getting the sematics right.
11868                                          */
11869                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, exc_ins->dreg, 0);
11870                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, dont_throw);
11871                                         MONO_EMIT_NEW_UNALU (cfg, OP_THROW, -1, exc_ins->dreg);
11872
11873                                         MONO_START_BB (cfg, dont_throw);
11874                                 }
11875                         }
11876
11877                         if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
11878                                 GList *tmp;
11879                                 MonoExceptionClause *clause;
11880
11881                                 for (tmp = handlers; tmp; tmp = tmp->next) {
11882                                         clause = tmp->data;
11883                                         tblock = cfg->cil_offset_to_bb [clause->handler_offset];
11884                                         g_assert (tblock);
11885                                         link_bblock (cfg, cfg->cbb, tblock);
11886                                         MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
11887                                         ins->inst_target_bb = tblock;
11888                                         ins->inst_eh_block = clause;
11889                                         MONO_ADD_INS (cfg->cbb, ins);
11890                                         cfg->cbb->has_call_handler = 1;
11891                                         if (COMPILE_LLVM (cfg)) {
11892                                                 MonoBasicBlock *target_bb;
11893
11894                                                 /* 
11895                                                  * Link the finally bblock with the target, since it will
11896                                                  * conceptually branch there.
11897                                                  * FIXME: Have to link the bblock containing the endfinally.
11898                                                  */
11899                                                 GET_BBLOCK (cfg, target_bb, target);
11900                                                 link_bblock (cfg, tblock, target_bb);
11901                                         }
11902                                 }
11903                                 g_list_free (handlers);
11904                         } 
11905
11906                         MONO_INST_NEW (cfg, ins, OP_BR);
11907                         MONO_ADD_INS (cfg->cbb, ins);
11908                         GET_BBLOCK (cfg, tblock, target);
11909                         link_bblock (cfg, cfg->cbb, tblock);
11910                         ins->inst_target_bb = tblock;
11911                         start_new_bblock = 1;
11912
11913                         if (*ip == CEE_LEAVE)
11914                                 ip += 5;
11915                         else
11916                                 ip += 2;
11917
11918                         break;
11919                 }
11920
11921                         /*
11922                          * Mono specific opcodes
11923                          */
11924                 case MONO_CUSTOM_PREFIX: {
11925
11926                         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
11927
11928                         CHECK_OPSIZE (2);
11929                         switch (ip [1]) {
11930                         case CEE_MONO_ICALL: {
11931                                 gpointer func;
11932                                 MonoJitICallInfo *info;
11933
11934                                 token = read32 (ip + 2);
11935                                 func = mono_method_get_wrapper_data (method, token);
11936                                 info = mono_find_jit_icall_by_addr (func);
11937                                 if (!info)
11938                                         g_error ("Could not find icall address in wrapper %s", mono_method_full_name (method, 1));
11939                                 g_assert (info);
11940
11941                                 CHECK_STACK (info->sig->param_count);
11942                                 sp -= info->sig->param_count;
11943
11944                                 ins = mono_emit_jit_icall (cfg, info->func, sp);
11945                                 if (!MONO_TYPE_IS_VOID (info->sig->ret))
11946                                         *sp++ = ins;
11947
11948                                 ip += 6;
11949                                 inline_costs += 10 * num_calls++;
11950
11951                                 break;
11952                         }
11953                         case CEE_MONO_LDPTR_CARD_TABLE: {
11954                                 int shift_bits;
11955                                 gpointer card_mask;
11956                                 CHECK_STACK_OVF (1);
11957
11958                                 if (cfg->compile_aot)
11959                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR, NULL);
11960                                 else
11961                                         EMIT_NEW_PCONST (cfg, ins, mono_gc_get_card_table (&shift_bits, &card_mask));
11962
11963                                 *sp++ = ins;
11964                                 ip += 2;
11965                                 inline_costs += 10 * num_calls++;
11966                                 break;
11967                         }
11968                         case CEE_MONO_LDPTR_NURSERY_START: {
11969                                 int shift_bits;
11970                                 size_t size;
11971                                 CHECK_STACK_OVF (1);
11972
11973                                 if (cfg->compile_aot)
11974                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_GC_NURSERY_START, NULL);
11975                                 else
11976                                         EMIT_NEW_PCONST (cfg, ins, mono_gc_get_nursery (&shift_bits, &size));
11977
11978                                 *sp++ = ins;
11979                                 ip += 2;
11980                                 inline_costs += 10 * num_calls++;
11981                                 break;
11982                         }
11983                         case CEE_MONO_LDPTR_INT_REQ_FLAG: {
11984                                 CHECK_STACK_OVF (1);
11985
11986                                 if (cfg->compile_aot)
11987                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG, NULL);
11988                                 else
11989                                         EMIT_NEW_PCONST (cfg, ins, mono_thread_interruption_request_flag ());
11990
11991                                 *sp++ = ins;
11992                                 ip += 2;
11993                                 inline_costs += 10 * num_calls++;
11994                                 break;
11995                         }
11996                         case CEE_MONO_LDPTR: {
11997                                 gpointer ptr;
11998
11999                                 CHECK_STACK_OVF (1);
12000                                 CHECK_OPSIZE (6);
12001                                 token = read32 (ip + 2);
12002
12003                                 ptr = mono_method_get_wrapper_data (method, token);
12004                                 EMIT_NEW_PCONST (cfg, ins, ptr);
12005                                 *sp++ = ins;
12006                                 ip += 6;
12007                                 inline_costs += 10 * num_calls++;
12008                                 /* Can't embed random pointers into AOT code */
12009                                 DISABLE_AOT (cfg);
12010                                 break;
12011                         }
12012                         case CEE_MONO_JIT_ICALL_ADDR: {
12013                                 MonoJitICallInfo *callinfo;
12014                                 gpointer ptr;
12015
12016                                 CHECK_STACK_OVF (1);
12017                                 CHECK_OPSIZE (6);
12018                                 token = read32 (ip + 2);
12019
12020                                 ptr = mono_method_get_wrapper_data (method, token);
12021                                 callinfo = mono_find_jit_icall_by_addr (ptr);
12022                                 g_assert (callinfo);
12023                                 EMIT_NEW_JIT_ICALL_ADDRCONST (cfg, ins, (char*)callinfo->name);
12024                                 *sp++ = ins;
12025                                 ip += 6;
12026                                 inline_costs += 10 * num_calls++;
12027                                 break;
12028                         }
12029                         case CEE_MONO_ICALL_ADDR: {
12030                                 MonoMethod *cmethod;
12031                                 gpointer ptr;
12032
12033                                 CHECK_STACK_OVF (1);
12034                                 CHECK_OPSIZE (6);
12035                                 token = read32 (ip + 2);
12036
12037                                 cmethod = mono_method_get_wrapper_data (method, token);
12038
12039                                 if (cfg->compile_aot) {
12040                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, cmethod);
12041                                 } else {
12042                                         ptr = mono_lookup_internal_call (cmethod);
12043                                         g_assert (ptr);
12044                                         EMIT_NEW_PCONST (cfg, ins, ptr);
12045                                 }
12046                                 *sp++ = ins;
12047                                 ip += 6;
12048                                 break;
12049                         }
12050                         case CEE_MONO_VTADDR: {
12051                                 MonoInst *src_var, *src;
12052
12053                                 CHECK_STACK (1);
12054                                 --sp;
12055
12056                                 // FIXME:
12057                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
12058                                 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
12059                                 *sp++ = src;
12060                                 ip += 2;
12061                                 break;
12062                         }
12063                         case CEE_MONO_NEWOBJ: {
12064                                 MonoInst *iargs [2];
12065
12066                                 CHECK_STACK_OVF (1);
12067                                 CHECK_OPSIZE (6);
12068                                 token = read32 (ip + 2);
12069                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12070                                 mono_class_init (klass);
12071                                 NEW_DOMAINCONST (cfg, iargs [0]);
12072                                 MONO_ADD_INS (cfg->cbb, iargs [0]);
12073                                 NEW_CLASSCONST (cfg, iargs [1], klass);
12074                                 MONO_ADD_INS (cfg->cbb, iargs [1]);
12075                                 *sp++ = mono_emit_jit_icall (cfg, mono_object_new, iargs);
12076                                 ip += 6;
12077                                 inline_costs += 10 * num_calls++;
12078                                 break;
12079                         }
12080                         case CEE_MONO_OBJADDR:
12081                                 CHECK_STACK (1);
12082                                 --sp;
12083                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
12084                                 ins->dreg = alloc_ireg_mp (cfg);
12085                                 ins->sreg1 = sp [0]->dreg;
12086                                 ins->type = STACK_MP;
12087                                 MONO_ADD_INS (cfg->cbb, ins);
12088                                 *sp++ = ins;
12089                                 ip += 2;
12090                                 break;
12091                         case CEE_MONO_LDNATIVEOBJ:
12092                                 /*
12093                                  * Similar to LDOBJ, but instead load the unmanaged 
12094                                  * representation of the vtype to the stack.
12095                                  */
12096                                 CHECK_STACK (1);
12097                                 CHECK_OPSIZE (6);
12098                                 --sp;
12099                                 token = read32 (ip + 2);
12100                                 klass = mono_method_get_wrapper_data (method, token);
12101                                 g_assert (klass->valuetype);
12102                                 mono_class_init (klass);
12103
12104                                 {
12105                                         MonoInst *src, *dest, *temp;
12106
12107                                         src = sp [0];
12108                                         temp = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
12109                                         temp->backend.is_pinvoke = 1;
12110                                         EMIT_NEW_TEMPLOADA (cfg, dest, temp->inst_c0);
12111                                         mini_emit_stobj (cfg, dest, src, klass, TRUE);
12112
12113                                         EMIT_NEW_TEMPLOAD (cfg, dest, temp->inst_c0);
12114                                         dest->type = STACK_VTYPE;
12115                                         dest->klass = klass;
12116
12117                                         *sp ++ = dest;
12118                                         ip += 6;
12119                                 }
12120                                 break;
12121                         case CEE_MONO_RETOBJ: {
12122                                 /*
12123                                  * Same as RET, but return the native representation of a vtype
12124                                  * to the caller.
12125                                  */
12126                                 g_assert (cfg->ret);
12127                                 g_assert (mono_method_signature (method)->pinvoke); 
12128                                 CHECK_STACK (1);
12129                                 --sp;
12130                                 
12131                                 CHECK_OPSIZE (6);
12132                                 token = read32 (ip + 2);    
12133                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12134
12135                                 if (!cfg->vret_addr) {
12136                                         g_assert (cfg->ret_var_is_local);
12137
12138                                         EMIT_NEW_VARLOADA (cfg, ins, cfg->ret, cfg->ret->inst_vtype);
12139                                 } else {
12140                                         EMIT_NEW_RETLOADA (cfg, ins);
12141                                 }
12142                                 mini_emit_stobj (cfg, ins, sp [0], klass, TRUE);
12143                                 
12144                                 if (sp != stack_start)
12145                                         UNVERIFIED;
12146                                 
12147                                 MONO_INST_NEW (cfg, ins, OP_BR);
12148                                 ins->inst_target_bb = end_bblock;
12149                                 MONO_ADD_INS (cfg->cbb, ins);
12150                                 link_bblock (cfg, cfg->cbb, end_bblock);
12151                                 start_new_bblock = 1;
12152                                 ip += 6;
12153                                 break;
12154                         }
12155                         case CEE_MONO_CISINST:
12156                         case CEE_MONO_CCASTCLASS: {
12157                                 int token;
12158                                 CHECK_STACK (1);
12159                                 --sp;
12160                                 CHECK_OPSIZE (6);
12161                                 token = read32 (ip + 2);
12162                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12163                                 if (ip [1] == CEE_MONO_CISINST)
12164                                         ins = handle_cisinst (cfg, klass, sp [0]);
12165                                 else
12166                                         ins = handle_ccastclass (cfg, klass, sp [0]);
12167                                 *sp++ = ins;
12168                                 ip += 6;
12169                                 break;
12170                         }
12171                         case CEE_MONO_SAVE_LMF:
12172                         case CEE_MONO_RESTORE_LMF:
12173 #ifdef MONO_ARCH_HAVE_LMF_OPS
12174                                 MONO_INST_NEW (cfg, ins, (ip [1] == CEE_MONO_SAVE_LMF) ? OP_SAVE_LMF : OP_RESTORE_LMF);
12175                                 MONO_ADD_INS (cfg->cbb, ins);
12176                                 cfg->need_lmf_area = TRUE;
12177 #endif
12178                                 ip += 2;
12179                                 break;
12180                         case CEE_MONO_CLASSCONST:
12181                                 CHECK_STACK_OVF (1);
12182                                 CHECK_OPSIZE (6);
12183                                 token = read32 (ip + 2);
12184                                 EMIT_NEW_CLASSCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
12185                                 *sp++ = ins;
12186                                 ip += 6;
12187                                 inline_costs += 10 * num_calls++;
12188                                 break;
12189                         case CEE_MONO_NOT_TAKEN:
12190                                 cfg->cbb->out_of_line = TRUE;
12191                                 ip += 2;
12192                                 break;
12193                         case CEE_MONO_TLS: {
12194                                 int key;
12195
12196                                 CHECK_STACK_OVF (1);
12197                                 CHECK_OPSIZE (6);
12198                                 key = (gint32)read32 (ip + 2);
12199                                 g_assert (key < TLS_KEY_NUM);
12200
12201                                 ins = mono_create_tls_get (cfg, key);
12202                                 if (!ins) {
12203                                         if (cfg->compile_aot) {
12204                                                 DISABLE_AOT (cfg);
12205                                                 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
12206                                                 ins->dreg = alloc_preg (cfg);
12207                                                 ins->type = STACK_PTR;
12208                                         } else {
12209                                                 g_assert_not_reached ();
12210                                         }
12211                                 }
12212                                 ins->type = STACK_PTR;
12213                                 MONO_ADD_INS (cfg->cbb, ins);
12214                                 *sp++ = ins;
12215                                 ip += 6;
12216                                 break;
12217                         }
12218                         case CEE_MONO_DYN_CALL: {
12219                                 MonoCallInst *call;
12220
12221                                 /* It would be easier to call a trampoline, but that would put an
12222                                  * extra frame on the stack, confusing exception handling. So
12223                                  * implement it inline using an opcode for now.
12224                                  */
12225
12226                                 if (!cfg->dyn_call_var) {
12227                                         cfg->dyn_call_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12228                                         /* prevent it from being register allocated */
12229                                         cfg->dyn_call_var->flags |= MONO_INST_VOLATILE;
12230                                 }
12231
12232                                 /* Has to use a call inst since it local regalloc expects it */
12233                                 MONO_INST_NEW_CALL (cfg, call, OP_DYN_CALL);
12234                                 ins = (MonoInst*)call;
12235                                 sp -= 2;
12236                                 ins->sreg1 = sp [0]->dreg;
12237                                 ins->sreg2 = sp [1]->dreg;
12238                                 MONO_ADD_INS (cfg->cbb, ins);
12239
12240                                 cfg->param_area = MAX (cfg->param_area, MONO_ARCH_DYN_CALL_PARAM_AREA);
12241
12242                                 ip += 2;
12243                                 inline_costs += 10 * num_calls++;
12244
12245                                 break;
12246                         }
12247                         case CEE_MONO_MEMORY_BARRIER: {
12248                                 CHECK_OPSIZE (6);
12249                                 emit_memory_barrier (cfg, (int)read32 (ip + 2));
12250                                 ip += 6;
12251                                 break;
12252                         }
12253                         case CEE_MONO_JIT_ATTACH: {
12254                                 MonoInst *args [16], *domain_ins;
12255                                 MonoInst *ad_ins, *jit_tls_ins;
12256                                 MonoBasicBlock *next_bb = NULL, *call_bb = NULL;
12257
12258                                 cfg->orig_domain_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12259
12260                                 EMIT_NEW_PCONST (cfg, ins, NULL);
12261                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12262
12263                                 ad_ins = mono_get_domain_intrinsic (cfg);
12264                                 jit_tls_ins = mono_get_jit_tls_intrinsic (cfg);
12265
12266                                 if (MONO_ARCH_HAVE_TLS_GET && ad_ins && jit_tls_ins) {
12267                                         NEW_BBLOCK (cfg, next_bb);
12268                                         NEW_BBLOCK (cfg, call_bb);
12269
12270                                         if (cfg->compile_aot) {
12271                                                 /* AOT code is only used in the root domain */
12272                                                 EMIT_NEW_PCONST (cfg, domain_ins, NULL);
12273                                         } else {
12274                                                 EMIT_NEW_PCONST (cfg, domain_ins, cfg->domain);
12275                                         }
12276                                         MONO_ADD_INS (cfg->cbb, ad_ins);
12277                                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, ad_ins->dreg, domain_ins->dreg);
12278                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, call_bb);
12279
12280                                         MONO_ADD_INS (cfg->cbb, jit_tls_ins);
12281                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, jit_tls_ins->dreg, 0);
12282                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, call_bb);
12283
12284                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, next_bb);
12285                                         MONO_START_BB (cfg, call_bb);
12286                                 }
12287
12288                                 if (cfg->compile_aot) {
12289                                         /* AOT code is only used in the root domain */
12290                                         EMIT_NEW_PCONST (cfg, args [0], NULL);
12291                                 } else {
12292                                         EMIT_NEW_PCONST (cfg, args [0], cfg->domain);
12293                                 }
12294                                 ins = mono_emit_jit_icall (cfg, mono_jit_thread_attach, args);
12295                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12296
12297                                 if (next_bb)
12298                                         MONO_START_BB (cfg, next_bb);
12299                                 ip += 2;
12300                                 break;
12301                         }
12302                         case CEE_MONO_JIT_DETACH: {
12303                                 MonoInst *args [16];
12304
12305                                 /* Restore the original domain */
12306                                 dreg = alloc_ireg (cfg);
12307                                 EMIT_NEW_UNALU (cfg, args [0], OP_MOVE, dreg, cfg->orig_domain_var->dreg);
12308                                 mono_emit_jit_icall (cfg, mono_jit_set_domain, args);
12309                                 ip += 2;
12310                                 break;
12311                         }
12312                         default:
12313                                 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
12314                                 break;
12315                         }
12316                         break;
12317                 }
12318
12319                 case CEE_PREFIX1: {
12320                         CHECK_OPSIZE (2);
12321                         switch (ip [1]) {
12322                         case CEE_ARGLIST: {
12323                                 /* somewhat similar to LDTOKEN */
12324                                 MonoInst *addr, *vtvar;
12325                                 CHECK_STACK_OVF (1);
12326                                 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL); 
12327
12328                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
12329                                 EMIT_NEW_UNALU (cfg, ins, OP_ARGLIST, -1, addr->dreg);
12330
12331                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
12332                                 ins->type = STACK_VTYPE;
12333                                 ins->klass = mono_defaults.argumenthandle_class;
12334                                 *sp++ = ins;
12335                                 ip += 2;
12336                                 break;
12337                         }
12338                         case CEE_CEQ:
12339                         case CEE_CGT:
12340                         case CEE_CGT_UN:
12341                         case CEE_CLT:
12342                         case CEE_CLT_UN: {
12343                                 MonoInst *cmp, *arg1, *arg2;
12344
12345                                 CHECK_STACK (2);
12346                                 sp -= 2;
12347                                 arg1 = sp [0];
12348                                 arg2 = sp [1];
12349
12350                                 /*
12351                                  * The following transforms:
12352                                  *    CEE_CEQ    into OP_CEQ
12353                                  *    CEE_CGT    into OP_CGT
12354                                  *    CEE_CGT_UN into OP_CGT_UN
12355                                  *    CEE_CLT    into OP_CLT
12356                                  *    CEE_CLT_UN into OP_CLT_UN
12357                                  */
12358                                 MONO_INST_NEW (cfg, cmp, (OP_CEQ - CEE_CEQ) + ip [1]);
12359
12360                                 MONO_INST_NEW (cfg, ins, cmp->opcode);
12361                                 cmp->sreg1 = arg1->dreg;
12362                                 cmp->sreg2 = arg2->dreg;
12363                                 type_from_op (cfg, cmp, arg1, arg2);
12364                                 CHECK_TYPE (cmp);
12365                                 add_widen_op (cfg, cmp, &arg1, &arg2);
12366                                 if ((arg1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((arg1->type == STACK_PTR) || (arg1->type == STACK_OBJ) || (arg1->type == STACK_MP))))
12367                                         cmp->opcode = OP_LCOMPARE;
12368                                 else if (arg1->type == STACK_R4)
12369                                         cmp->opcode = OP_RCOMPARE;
12370                                 else if (arg1->type == STACK_R8)
12371                                         cmp->opcode = OP_FCOMPARE;
12372                                 else
12373                                         cmp->opcode = OP_ICOMPARE;
12374                                 MONO_ADD_INS (cfg->cbb, cmp);
12375                                 ins->type = STACK_I4;
12376                                 ins->dreg = alloc_dreg (cfg, ins->type);
12377                                 type_from_op (cfg, ins, arg1, arg2);
12378
12379                                 if (cmp->opcode == OP_FCOMPARE || cmp->opcode == OP_RCOMPARE) {
12380                                         /*
12381                                          * The backends expect the fceq opcodes to do the
12382                                          * comparison too.
12383                                          */
12384                                         ins->sreg1 = cmp->sreg1;
12385                                         ins->sreg2 = cmp->sreg2;
12386                                         NULLIFY_INS (cmp);
12387                                 }
12388                                 MONO_ADD_INS (cfg->cbb, ins);
12389                                 *sp++ = ins;
12390                                 ip += 2;
12391                                 break;
12392                         }
12393                         case CEE_LDFTN: {
12394                                 MonoInst *argconst;
12395                                 MonoMethod *cil_method;
12396
12397                                 CHECK_STACK_OVF (1);
12398                                 CHECK_OPSIZE (6);
12399                                 n = read32 (ip + 2);
12400                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
12401                                 if (!cmethod || mono_loader_get_last_error ())
12402                                         LOAD_ERROR;
12403                                 mono_class_init (cmethod->klass);
12404
12405                                 mono_save_token_info (cfg, image, n, cmethod);
12406
12407                                 context_used = mini_method_check_context_used (cfg, cmethod);
12408
12409                                 cil_method = cmethod;
12410                                 if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
12411                                         METHOD_ACCESS_FAILURE (method, cil_method);
12412
12413                                 if (mono_security_core_clr_enabled ())
12414                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
12415
12416                                 /* 
12417                                  * Optimize the common case of ldftn+delegate creation
12418                                  */
12419                                 if ((sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 6) && (ip [6] == CEE_NEWOBJ)) {
12420                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
12421                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
12422                                                 MonoInst *target_ins, *handle_ins;
12423                                                 MonoMethod *invoke;
12424                                                 int invoke_context_used;
12425
12426                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
12427                                                 if (!invoke || !mono_method_signature (invoke))
12428                                                         LOAD_ERROR;
12429
12430                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
12431
12432                                                 target_ins = sp [-1];
12433
12434                                                 if (mono_security_core_clr_enabled ())
12435                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
12436
12437                                                 if (!(cmethod->flags & METHOD_ATTRIBUTE_STATIC)) {
12438                                                         /*LAME IMPL: We must not add a null check for virtual invoke delegates.*/
12439                                                         if (mono_method_signature (invoke)->param_count == mono_method_signature (cmethod)->param_count) {
12440                                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, target_ins->dreg, 0);
12441                                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "ArgumentException");
12442                                                         }
12443                                                 }
12444
12445                                                 /* FIXME: SGEN support */
12446                                                 if (invoke_context_used == 0) {
12447                                                         ip += 6;
12448                                                         if (cfg->verbose_level > 3)
12449                                                                 g_print ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
12450                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, FALSE))) {
12451                                                                 sp --;
12452                                                                 *sp = handle_ins;
12453                                                                 CHECK_CFG_EXCEPTION;
12454                                                                 ip += 5;
12455                                                                 sp ++;
12456                                                                 break;
12457                                                         }
12458                                                         ip -= 6;
12459                                                 }
12460                                         }
12461                                 }
12462
12463                                 argconst = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD);
12464                                 ins = mono_emit_jit_icall (cfg, mono_ldftn, &argconst);
12465                                 *sp++ = ins;
12466                                 
12467                                 ip += 6;
12468                                 inline_costs += 10 * num_calls++;
12469                                 break;
12470                         }
12471                         case CEE_LDVIRTFTN: {
12472                                 MonoInst *args [2];
12473
12474                                 CHECK_STACK (1);
12475                                 CHECK_OPSIZE (6);
12476                                 n = read32 (ip + 2);
12477                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
12478                                 if (!cmethod || mono_loader_get_last_error ())
12479                                         LOAD_ERROR;
12480                                 mono_class_init (cmethod->klass);
12481  
12482                                 context_used = mini_method_check_context_used (cfg, cmethod);
12483
12484                                 if (mono_security_core_clr_enabled ())
12485                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
12486
12487                                 /*
12488                                  * Optimize the common case of ldvirtftn+delegate creation
12489                                  */
12490                                 if ((sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 6) && (ip [6] == CEE_NEWOBJ) && (ip > header->code && ip [-1] == CEE_DUP)) {
12491                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
12492                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
12493                                                 MonoInst *target_ins, *handle_ins;
12494                                                 MonoMethod *invoke;
12495                                                 int invoke_context_used;
12496                                                 gboolean is_virtual = cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL;
12497
12498                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
12499                                                 if (!invoke || !mono_method_signature (invoke))
12500                                                         LOAD_ERROR;
12501
12502                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
12503
12504                                                 target_ins = sp [-1];
12505
12506                                                 if (mono_security_core_clr_enabled ())
12507                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
12508
12509                                                 /* FIXME: SGEN support */
12510                                                 if (invoke_context_used == 0) {
12511                                                         ip += 6;
12512                                                         if (cfg->verbose_level > 3)
12513                                                                 g_print ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
12514                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, is_virtual))) {
12515                                                                 sp -= 2;
12516                                                                 *sp = handle_ins;
12517                                                                 CHECK_CFG_EXCEPTION;
12518                                                                 ip += 5;
12519                                                                 sp ++;
12520                                                                 break;
12521                                                         }
12522                                                         ip -= 6;
12523                                                 }
12524                                         }
12525                                 }
12526
12527                                 --sp;
12528                                 args [0] = *sp;
12529
12530                                 args [1] = emit_get_rgctx_method (cfg, context_used,
12531                                                                                                   cmethod, MONO_RGCTX_INFO_METHOD);
12532
12533                                 if (context_used)
12534                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn_gshared, args);
12535                                 else
12536                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn, args);
12537
12538                                 ip += 6;
12539                                 inline_costs += 10 * num_calls++;
12540                                 break;
12541                         }
12542                         case CEE_LDARG:
12543                                 CHECK_STACK_OVF (1);
12544                                 CHECK_OPSIZE (4);
12545                                 n = read16 (ip + 2);
12546                                 CHECK_ARG (n);
12547                                 EMIT_NEW_ARGLOAD (cfg, ins, n);
12548                                 *sp++ = ins;
12549                                 ip += 4;
12550                                 break;
12551                         case CEE_LDARGA:
12552                                 CHECK_STACK_OVF (1);
12553                                 CHECK_OPSIZE (4);
12554                                 n = read16 (ip + 2);
12555                                 CHECK_ARG (n);
12556                                 NEW_ARGLOADA (cfg, ins, n);
12557                                 MONO_ADD_INS (cfg->cbb, ins);
12558                                 *sp++ = ins;
12559                                 ip += 4;
12560                                 break;
12561                         case CEE_STARG:
12562                                 CHECK_STACK (1);
12563                                 --sp;
12564                                 CHECK_OPSIZE (4);
12565                                 n = read16 (ip + 2);
12566                                 CHECK_ARG (n);
12567                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
12568                                         UNVERIFIED;
12569                                 EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
12570                                 ip += 4;
12571                                 break;
12572                         case CEE_LDLOC:
12573                                 CHECK_STACK_OVF (1);
12574                                 CHECK_OPSIZE (4);
12575                                 n = read16 (ip + 2);
12576                                 CHECK_LOCAL (n);
12577                                 EMIT_NEW_LOCLOAD (cfg, ins, n);
12578                                 *sp++ = ins;
12579                                 ip += 4;
12580                                 break;
12581                         case CEE_LDLOCA: {
12582                                 unsigned char *tmp_ip;
12583                                 CHECK_STACK_OVF (1);
12584                                 CHECK_OPSIZE (4);
12585                                 n = read16 (ip + 2);
12586                                 CHECK_LOCAL (n);
12587
12588                                 if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 2))) {
12589                                         ip = tmp_ip;
12590                                         inline_costs += 1;
12591                                         break;
12592                                 }                       
12593                                 
12594                                 EMIT_NEW_LOCLOADA (cfg, ins, n);
12595                                 *sp++ = ins;
12596                                 ip += 4;
12597                                 break;
12598                         }
12599                         case CEE_STLOC:
12600                                 CHECK_STACK (1);
12601                                 --sp;
12602                                 CHECK_OPSIZE (4);
12603                                 n = read16 (ip + 2);
12604                                 CHECK_LOCAL (n);
12605                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
12606                                         UNVERIFIED;
12607                                 emit_stloc_ir (cfg, sp, header, n);
12608                                 ip += 4;
12609                                 inline_costs += 1;
12610                                 break;
12611                         case CEE_LOCALLOC:
12612                                 CHECK_STACK (1);
12613                                 --sp;
12614                                 if (sp != stack_start) 
12615                                         UNVERIFIED;
12616                                 if (cfg->method != method) 
12617                                         /* 
12618                                          * Inlining this into a loop in a parent could lead to 
12619                                          * stack overflows which is different behavior than the
12620                                          * non-inlined case, thus disable inlining in this case.
12621                                          */
12622                                         INLINE_FAILURE("localloc");
12623
12624                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
12625                                 ins->dreg = alloc_preg (cfg);
12626                                 ins->sreg1 = sp [0]->dreg;
12627                                 ins->type = STACK_PTR;
12628                                 MONO_ADD_INS (cfg->cbb, ins);
12629
12630                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12631                                 if (init_locals)
12632                                         ins->flags |= MONO_INST_INIT;
12633
12634                                 *sp++ = ins;
12635                                 ip += 2;
12636                                 break;
12637                         case CEE_ENDFILTER: {
12638                                 MonoExceptionClause *clause, *nearest;
12639                                 int cc;
12640
12641                                 CHECK_STACK (1);
12642                                 --sp;
12643                                 if ((sp != stack_start) || (sp [0]->type != STACK_I4)) 
12644                                         UNVERIFIED;
12645                                 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
12646                                 ins->sreg1 = (*sp)->dreg;
12647                                 MONO_ADD_INS (cfg->cbb, ins);
12648                                 start_new_bblock = 1;
12649                                 ip += 2;
12650
12651                                 nearest = NULL;
12652                                 for (cc = 0; cc < header->num_clauses; ++cc) {
12653                                         clause = &header->clauses [cc];
12654                                         if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
12655                                                 ((ip - header->code) > clause->data.filter_offset && (ip - header->code) <= clause->handler_offset) &&
12656                                             (!nearest || (clause->data.filter_offset < nearest->data.filter_offset)))
12657                                                 nearest = clause;
12658                                 }
12659                                 g_assert (nearest);
12660                                 if ((ip - header->code) != nearest->handler_offset)
12661                                         UNVERIFIED;
12662
12663                                 break;
12664                         }
12665                         case CEE_UNALIGNED_:
12666                                 ins_flag |= MONO_INST_UNALIGNED;
12667                                 /* FIXME: record alignment? we can assume 1 for now */
12668                                 CHECK_OPSIZE (3);
12669                                 ip += 3;
12670                                 break;
12671                         case CEE_VOLATILE_:
12672                                 ins_flag |= MONO_INST_VOLATILE;
12673                                 ip += 2;
12674                                 break;
12675                         case CEE_TAIL_:
12676                                 ins_flag   |= MONO_INST_TAILCALL;
12677                                 cfg->flags |= MONO_CFG_HAS_TAIL;
12678                                 /* Can't inline tail calls at this time */
12679                                 inline_costs += 100000;
12680                                 ip += 2;
12681                                 break;
12682                         case CEE_INITOBJ:
12683                                 CHECK_STACK (1);
12684                                 --sp;
12685                                 CHECK_OPSIZE (6);
12686                                 token = read32 (ip + 2);
12687                                 klass = mini_get_class (method, token, generic_context);
12688                                 CHECK_TYPELOAD (klass);
12689                                 if (generic_class_is_reference_type (cfg, klass))
12690                                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, sp [0]->dreg, 0, 0);
12691                                 else
12692                                         mini_emit_initobj (cfg, *sp, NULL, klass);
12693                                 ip += 6;
12694                                 inline_costs += 1;
12695                                 break;
12696                         case CEE_CONSTRAINED_:
12697                                 CHECK_OPSIZE (6);
12698                                 token = read32 (ip + 2);
12699                                 constrained_class = mini_get_class (method, token, generic_context);
12700                                 CHECK_TYPELOAD (constrained_class);
12701                                 ip += 6;
12702                                 break;
12703                         case CEE_CPBLK:
12704                         case CEE_INITBLK: {
12705                                 MonoInst *iargs [3];
12706                                 CHECK_STACK (3);
12707                                 sp -= 3;
12708
12709                                 /* Skip optimized paths for volatile operations. */
12710                                 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)) {
12711                                         mini_emit_memcpy (cfg, sp [0]->dreg, 0, sp [1]->dreg, 0, sp [2]->inst_c0, 0);
12712                                 } 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)) {
12713                                         /* emit_memset only works when val == 0 */
12714                                         mini_emit_memset (cfg, sp [0]->dreg, 0, sp [2]->inst_c0, sp [1]->inst_c0, 0);
12715                                 } else {
12716                                         MonoInst *call;
12717                                         iargs [0] = sp [0];
12718                                         iargs [1] = sp [1];
12719                                         iargs [2] = sp [2];
12720                                         if (ip [1] == CEE_CPBLK) {
12721                                                 /*
12722                                                  * FIXME: It's unclear whether we should be emitting both the acquire
12723                                                  * and release barriers for cpblk. It is technically both a load and
12724                                                  * store operation, so it seems like that's the sensible thing to do.
12725                                                  *
12726                                                  * FIXME: We emit full barriers on both sides of the operation for
12727                                                  * simplicity. We should have a separate atomic memcpy method instead.
12728                                                  */
12729                                                 MonoMethod *memcpy_method = get_memcpy_method ();
12730
12731                                                 if (ins_flag & MONO_INST_VOLATILE)
12732                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
12733
12734                                                 call = mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
12735                                                 call->flags |= ins_flag;
12736
12737                                                 if (ins_flag & MONO_INST_VOLATILE)
12738                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
12739                                         } else {
12740                                                 MonoMethod *memset_method = get_memset_method ();
12741                                                 if (ins_flag & MONO_INST_VOLATILE) {
12742                                                         /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
12743                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
12744                                                 }
12745                                                 call = mono_emit_method_call (cfg, memset_method, iargs, NULL);
12746                                                 call->flags |= ins_flag;
12747                                         }
12748                                 }
12749                                 ip += 2;
12750                                 ins_flag = 0;
12751                                 inline_costs += 1;
12752                                 break;
12753                         }
12754                         case CEE_NO_:
12755                                 CHECK_OPSIZE (3);
12756                                 if (ip [2] & 0x1)
12757                                         ins_flag |= MONO_INST_NOTYPECHECK;
12758                                 if (ip [2] & 0x2)
12759                                         ins_flag |= MONO_INST_NORANGECHECK;
12760                                 /* we ignore the no-nullcheck for now since we
12761                                  * really do it explicitly only when doing callvirt->call
12762                                  */
12763                                 ip += 3;
12764                                 break;
12765                         case CEE_RETHROW: {
12766                                 MonoInst *load;
12767                                 int handler_offset = -1;
12768
12769                                 for (i = 0; i < header->num_clauses; ++i) {
12770                                         MonoExceptionClause *clause = &header->clauses [i];
12771                                         if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
12772                                                 handler_offset = clause->handler_offset;
12773                                                 break;
12774                                         }
12775                                 }
12776
12777                                 cfg->cbb->flags |= BB_EXCEPTION_UNSAFE;
12778
12779                                 if (handler_offset == -1)
12780                                         UNVERIFIED;
12781
12782                                 EMIT_NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
12783                                 MONO_INST_NEW (cfg, ins, OP_RETHROW);
12784                                 ins->sreg1 = load->dreg;
12785                                 MONO_ADD_INS (cfg->cbb, ins);
12786
12787                                 MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
12788                                 MONO_ADD_INS (cfg->cbb, ins);
12789
12790                                 sp = stack_start;
12791                                 link_bblock (cfg, cfg->cbb, end_bblock);
12792                                 start_new_bblock = 1;
12793                                 ip += 2;
12794                                 break;
12795                         }
12796                         case CEE_SIZEOF: {
12797                                 guint32 val;
12798                                 int ialign;
12799
12800                                 CHECK_STACK_OVF (1);
12801                                 CHECK_OPSIZE (6);
12802                                 token = read32 (ip + 2);
12803                                 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC && !image_is_dynamic (method->klass->image) && !generic_context) {
12804                                         MonoType *type = mono_type_create_from_typespec_checked (image, token, &cfg->error);
12805                                         CHECK_CFG_ERROR;
12806
12807                                         val = mono_type_size (type, &ialign);
12808                                 } else {
12809                                         MonoClass *klass = mini_get_class (method, token, generic_context);
12810                                         CHECK_TYPELOAD (klass);
12811
12812                                         val = mono_type_size (&klass->byval_arg, &ialign);
12813
12814                                         if (mini_is_gsharedvt_klass (klass))
12815                                                 GSHAREDVT_FAILURE (*ip);
12816                                 }
12817                                 EMIT_NEW_ICONST (cfg, ins, val);
12818                                 *sp++= ins;
12819                                 ip += 6;
12820                                 break;
12821                         }
12822                         case CEE_REFANYTYPE: {
12823                                 MonoInst *src_var, *src;
12824
12825                                 GSHAREDVT_FAILURE (*ip);
12826
12827                                 CHECK_STACK (1);
12828                                 --sp;
12829
12830                                 // FIXME:
12831                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
12832                                 if (!src_var)
12833                                         src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
12834                                 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
12835                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &mono_defaults.typehandle_class->byval_arg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type));
12836                                 *sp++ = ins;
12837                                 ip += 2;
12838                                 break;
12839                         }
12840                         case CEE_READONLY_:
12841                                 readonly = TRUE;
12842                                 ip += 2;
12843                                 break;
12844
12845                         case CEE_UNUSED56:
12846                         case CEE_UNUSED57:
12847                         case CEE_UNUSED70:
12848                         case CEE_UNUSED:
12849                         case CEE_UNUSED99:
12850                                 UNVERIFIED;
12851                                 
12852                         default:
12853                                 g_warning ("opcode 0xfe 0x%02x not handled", ip [1]);
12854                                 UNVERIFIED;
12855                         }
12856                         break;
12857                 }
12858                 case CEE_UNUSED58:
12859                 case CEE_UNUSED1:
12860                         UNVERIFIED;
12861
12862                 default:
12863                         g_warning ("opcode 0x%02x not handled", *ip);
12864                         UNVERIFIED;
12865                 }
12866         }
12867         if (start_new_bblock != 1)
12868                 UNVERIFIED;
12869
12870         cfg->cbb->cil_length = ip - cfg->cbb->cil_code;
12871         if (cfg->cbb->next_bb) {
12872                 /* This could already be set because of inlining, #693905 */
12873                 MonoBasicBlock *bb = cfg->cbb;
12874
12875                 while (bb->next_bb)
12876                         bb = bb->next_bb;
12877                 bb->next_bb = end_bblock;
12878         } else {
12879                 cfg->cbb->next_bb = end_bblock;
12880         }
12881
12882         if (cfg->method == method && cfg->domainvar) {
12883                 MonoInst *store;
12884                 MonoInst *get_domain;
12885
12886                 cfg->cbb = init_localsbb;
12887
12888                 if ((get_domain = mono_get_domain_intrinsic (cfg))) {
12889                         MONO_ADD_INS (cfg->cbb, get_domain);
12890                 } else {
12891                         get_domain = mono_emit_jit_icall (cfg, mono_domain_get, NULL);
12892                 }
12893                 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, get_domain);
12894                 MONO_ADD_INS (cfg->cbb, store);
12895         }
12896
12897 #if defined(TARGET_POWERPC) || defined(TARGET_X86)
12898         if (cfg->compile_aot)
12899                 /* FIXME: The plt slots require a GOT var even if the method doesn't use it */
12900                 mono_get_got_var (cfg);
12901 #endif
12902
12903         if (cfg->method == method && cfg->got_var)
12904                 mono_emit_load_got_addr (cfg);
12905
12906         if (init_localsbb) {
12907                 cfg->cbb = init_localsbb;
12908                 cfg->ip = NULL;
12909                 for (i = 0; i < header->num_locals; ++i) {
12910                         emit_init_local (cfg, i, header->locals [i], init_locals);
12911                 }
12912         }
12913
12914         if (cfg->init_ref_vars && cfg->method == method) {
12915                 /* Emit initialization for ref vars */
12916                 // FIXME: Avoid duplication initialization for IL locals.
12917                 for (i = 0; i < cfg->num_varinfo; ++i) {
12918                         MonoInst *ins = cfg->varinfo [i];
12919
12920                         if (ins->opcode == OP_LOCAL && ins->type == STACK_OBJ)
12921                                 MONO_EMIT_NEW_PCONST (cfg, ins->dreg, NULL);
12922                 }
12923         }
12924
12925         if (cfg->lmf_var && cfg->method == method) {
12926                 cfg->cbb = init_localsbb;
12927                 emit_push_lmf (cfg);
12928         }
12929
12930         cfg->cbb = init_localsbb;
12931         emit_instrumentation_call (cfg, mono_profiler_method_enter);
12932
12933         if (seq_points) {
12934                 MonoBasicBlock *bb;
12935
12936                 /*
12937                  * Make seq points at backward branch targets interruptable.
12938                  */
12939                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
12940                         if (bb->code && bb->in_count > 1 && bb->code->opcode == OP_SEQ_POINT)
12941                                 bb->code->flags |= MONO_INST_SINGLE_STEP_LOC;
12942         }
12943
12944         /* Add a sequence point for method entry/exit events */
12945         if (seq_points && cfg->gen_sdb_seq_points) {
12946                 NEW_SEQ_POINT (cfg, ins, METHOD_ENTRY_IL_OFFSET, FALSE);
12947                 MONO_ADD_INS (init_localsbb, ins);
12948                 NEW_SEQ_POINT (cfg, ins, METHOD_EXIT_IL_OFFSET, FALSE);
12949                 MONO_ADD_INS (cfg->bb_exit, ins);
12950         }
12951
12952         /*
12953          * Add seq points for IL offsets which have line number info, but wasn't generated a seq point during JITting because
12954          * the code they refer to was dead (#11880).
12955          */
12956         if (sym_seq_points) {
12957                 for (i = 0; i < header->code_size; ++i) {
12958                         if (mono_bitset_test_fast (seq_point_locs, i) && !mono_bitset_test_fast (seq_point_set_locs, i)) {
12959                                 MonoInst *ins;
12960
12961                                 NEW_SEQ_POINT (cfg, ins, i, FALSE);
12962                                 mono_add_seq_point (cfg, NULL, ins, SEQ_POINT_NATIVE_OFFSET_DEAD_CODE);
12963                         }
12964                 }
12965         }
12966
12967         cfg->ip = NULL;
12968
12969         if (cfg->method == method) {
12970                 MonoBasicBlock *bb;
12971                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
12972                         bb->region = mono_find_block_region (cfg, bb->real_offset);
12973                         if (cfg->spvars)
12974                                 mono_create_spvar_for_region (cfg, bb->region);
12975                         if (cfg->verbose_level > 2)
12976                                 printf ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
12977                 }
12978         }
12979
12980         if (inline_costs < 0) {
12981                 char *mname;
12982
12983                 /* Method is too large */
12984                 mname = mono_method_full_name (method, TRUE);
12985                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
12986                 cfg->exception_message = g_strdup_printf ("Method %s is too complex.", mname);
12987                 g_free (mname);
12988         }
12989
12990         if ((cfg->verbose_level > 2) && (cfg->method == method)) 
12991                 mono_print_code (cfg, "AFTER METHOD-TO-IR");
12992
12993         goto cleanup;
12994
12995 mono_error_exit:
12996         g_assert (!mono_error_ok (&cfg->error));
12997         goto cleanup;
12998  
12999  exception_exit:
13000         g_assert (cfg->exception_type != MONO_EXCEPTION_NONE);
13001         goto cleanup;
13002
13003  unverified:
13004         set_exception_type_from_invalid_il (cfg, method, ip);
13005         goto cleanup;
13006
13007  cleanup:
13008         g_slist_free (class_inits);
13009         mono_basic_block_free (original_bb);
13010         cfg->dont_inline = g_list_remove (cfg->dont_inline, method);
13011         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
13012         if (cfg->exception_type)
13013                 return -1;
13014         else
13015                 return inline_costs;
13016 }
13017
13018 static int
13019 store_membase_reg_to_store_membase_imm (int opcode)
13020 {
13021         switch (opcode) {
13022         case OP_STORE_MEMBASE_REG:
13023                 return OP_STORE_MEMBASE_IMM;
13024         case OP_STOREI1_MEMBASE_REG:
13025                 return OP_STOREI1_MEMBASE_IMM;
13026         case OP_STOREI2_MEMBASE_REG:
13027                 return OP_STOREI2_MEMBASE_IMM;
13028         case OP_STOREI4_MEMBASE_REG:
13029                 return OP_STOREI4_MEMBASE_IMM;
13030         case OP_STOREI8_MEMBASE_REG:
13031                 return OP_STOREI8_MEMBASE_IMM;
13032         default:
13033                 g_assert_not_reached ();
13034         }
13035
13036         return -1;
13037 }               
13038
13039 int
13040 mono_op_to_op_imm (int opcode)
13041 {
13042         switch (opcode) {
13043         case OP_IADD:
13044                 return OP_IADD_IMM;
13045         case OP_ISUB:
13046                 return OP_ISUB_IMM;
13047         case OP_IDIV:
13048                 return OP_IDIV_IMM;
13049         case OP_IDIV_UN:
13050                 return OP_IDIV_UN_IMM;
13051         case OP_IREM:
13052                 return OP_IREM_IMM;
13053         case OP_IREM_UN:
13054                 return OP_IREM_UN_IMM;
13055         case OP_IMUL:
13056                 return OP_IMUL_IMM;
13057         case OP_IAND:
13058                 return OP_IAND_IMM;
13059         case OP_IOR:
13060                 return OP_IOR_IMM;
13061         case OP_IXOR:
13062                 return OP_IXOR_IMM;
13063         case OP_ISHL:
13064                 return OP_ISHL_IMM;
13065         case OP_ISHR:
13066                 return OP_ISHR_IMM;
13067         case OP_ISHR_UN:
13068                 return OP_ISHR_UN_IMM;
13069
13070         case OP_LADD:
13071                 return OP_LADD_IMM;
13072         case OP_LSUB:
13073                 return OP_LSUB_IMM;
13074         case OP_LAND:
13075                 return OP_LAND_IMM;
13076         case OP_LOR:
13077                 return OP_LOR_IMM;
13078         case OP_LXOR:
13079                 return OP_LXOR_IMM;
13080         case OP_LSHL:
13081                 return OP_LSHL_IMM;
13082         case OP_LSHR:
13083                 return OP_LSHR_IMM;
13084         case OP_LSHR_UN:
13085                 return OP_LSHR_UN_IMM;
13086 #if SIZEOF_REGISTER == 8
13087         case OP_LREM:
13088                 return OP_LREM_IMM;
13089 #endif
13090
13091         case OP_COMPARE:
13092                 return OP_COMPARE_IMM;
13093         case OP_ICOMPARE:
13094                 return OP_ICOMPARE_IMM;
13095         case OP_LCOMPARE:
13096                 return OP_LCOMPARE_IMM;
13097
13098         case OP_STORE_MEMBASE_REG:
13099                 return OP_STORE_MEMBASE_IMM;
13100         case OP_STOREI1_MEMBASE_REG:
13101                 return OP_STOREI1_MEMBASE_IMM;
13102         case OP_STOREI2_MEMBASE_REG:
13103                 return OP_STOREI2_MEMBASE_IMM;
13104         case OP_STOREI4_MEMBASE_REG:
13105                 return OP_STOREI4_MEMBASE_IMM;
13106
13107 #if defined(TARGET_X86) || defined (TARGET_AMD64)
13108         case OP_X86_PUSH:
13109                 return OP_X86_PUSH_IMM;
13110         case OP_X86_COMPARE_MEMBASE_REG:
13111                 return OP_X86_COMPARE_MEMBASE_IMM;
13112 #endif
13113 #if defined(TARGET_AMD64)
13114         case OP_AMD64_ICOMPARE_MEMBASE_REG:
13115                 return OP_AMD64_ICOMPARE_MEMBASE_IMM;
13116 #endif
13117         case OP_VOIDCALL_REG:
13118                 return OP_VOIDCALL;
13119         case OP_CALL_REG:
13120                 return OP_CALL;
13121         case OP_LCALL_REG:
13122                 return OP_LCALL;
13123         case OP_FCALL_REG:
13124                 return OP_FCALL;
13125         case OP_LOCALLOC:
13126                 return OP_LOCALLOC_IMM;
13127         }
13128
13129         return -1;
13130 }
13131
13132 static int
13133 ldind_to_load_membase (int opcode)
13134 {
13135         switch (opcode) {
13136         case CEE_LDIND_I1:
13137                 return OP_LOADI1_MEMBASE;
13138         case CEE_LDIND_U1:
13139                 return OP_LOADU1_MEMBASE;
13140         case CEE_LDIND_I2:
13141                 return OP_LOADI2_MEMBASE;
13142         case CEE_LDIND_U2:
13143                 return OP_LOADU2_MEMBASE;
13144         case CEE_LDIND_I4:
13145                 return OP_LOADI4_MEMBASE;
13146         case CEE_LDIND_U4:
13147                 return OP_LOADU4_MEMBASE;
13148         case CEE_LDIND_I:
13149                 return OP_LOAD_MEMBASE;
13150         case CEE_LDIND_REF:
13151                 return OP_LOAD_MEMBASE;
13152         case CEE_LDIND_I8:
13153                 return OP_LOADI8_MEMBASE;
13154         case CEE_LDIND_R4:
13155                 return OP_LOADR4_MEMBASE;
13156         case CEE_LDIND_R8:
13157                 return OP_LOADR8_MEMBASE;
13158         default:
13159                 g_assert_not_reached ();
13160         }
13161
13162         return -1;
13163 }
13164
13165 static int
13166 stind_to_store_membase (int opcode)
13167 {
13168         switch (opcode) {
13169         case CEE_STIND_I1:
13170                 return OP_STOREI1_MEMBASE_REG;
13171         case CEE_STIND_I2:
13172                 return OP_STOREI2_MEMBASE_REG;
13173         case CEE_STIND_I4:
13174                 return OP_STOREI4_MEMBASE_REG;
13175         case CEE_STIND_I:
13176         case CEE_STIND_REF:
13177                 return OP_STORE_MEMBASE_REG;
13178         case CEE_STIND_I8:
13179                 return OP_STOREI8_MEMBASE_REG;
13180         case CEE_STIND_R4:
13181                 return OP_STORER4_MEMBASE_REG;
13182         case CEE_STIND_R8:
13183                 return OP_STORER8_MEMBASE_REG;
13184         default:
13185                 g_assert_not_reached ();
13186         }
13187
13188         return -1;
13189 }
13190
13191 int
13192 mono_load_membase_to_load_mem (int opcode)
13193 {
13194         // FIXME: Add a MONO_ARCH_HAVE_LOAD_MEM macro
13195 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13196         switch (opcode) {
13197         case OP_LOAD_MEMBASE:
13198                 return OP_LOAD_MEM;
13199         case OP_LOADU1_MEMBASE:
13200                 return OP_LOADU1_MEM;
13201         case OP_LOADU2_MEMBASE:
13202                 return OP_LOADU2_MEM;
13203         case OP_LOADI4_MEMBASE:
13204                 return OP_LOADI4_MEM;
13205         case OP_LOADU4_MEMBASE:
13206                 return OP_LOADU4_MEM;
13207 #if SIZEOF_REGISTER == 8
13208         case OP_LOADI8_MEMBASE:
13209                 return OP_LOADI8_MEM;
13210 #endif
13211         }
13212 #endif
13213
13214         return -1;
13215 }
13216
13217 static inline int
13218 op_to_op_dest_membase (int store_opcode, int opcode)
13219 {
13220 #if defined(TARGET_X86)
13221         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG)))
13222                 return -1;
13223
13224         switch (opcode) {
13225         case OP_IADD:
13226                 return OP_X86_ADD_MEMBASE_REG;
13227         case OP_ISUB:
13228                 return OP_X86_SUB_MEMBASE_REG;
13229         case OP_IAND:
13230                 return OP_X86_AND_MEMBASE_REG;
13231         case OP_IOR:
13232                 return OP_X86_OR_MEMBASE_REG;
13233         case OP_IXOR:
13234                 return OP_X86_XOR_MEMBASE_REG;
13235         case OP_ADD_IMM:
13236         case OP_IADD_IMM:
13237                 return OP_X86_ADD_MEMBASE_IMM;
13238         case OP_SUB_IMM:
13239         case OP_ISUB_IMM:
13240                 return OP_X86_SUB_MEMBASE_IMM;
13241         case OP_AND_IMM:
13242         case OP_IAND_IMM:
13243                 return OP_X86_AND_MEMBASE_IMM;
13244         case OP_OR_IMM:
13245         case OP_IOR_IMM:
13246                 return OP_X86_OR_MEMBASE_IMM;
13247         case OP_XOR_IMM:
13248         case OP_IXOR_IMM:
13249                 return OP_X86_XOR_MEMBASE_IMM;
13250         case OP_MOVE:
13251                 return OP_NOP;
13252         }
13253 #endif
13254
13255 #if defined(TARGET_AMD64)
13256         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG) || (store_opcode == OP_STOREI8_MEMBASE_REG)))
13257                 return -1;
13258
13259         switch (opcode) {
13260         case OP_IADD:
13261                 return OP_X86_ADD_MEMBASE_REG;
13262         case OP_ISUB:
13263                 return OP_X86_SUB_MEMBASE_REG;
13264         case OP_IAND:
13265                 return OP_X86_AND_MEMBASE_REG;
13266         case OP_IOR:
13267                 return OP_X86_OR_MEMBASE_REG;
13268         case OP_IXOR:
13269                 return OP_X86_XOR_MEMBASE_REG;
13270         case OP_IADD_IMM:
13271                 return OP_X86_ADD_MEMBASE_IMM;
13272         case OP_ISUB_IMM:
13273                 return OP_X86_SUB_MEMBASE_IMM;
13274         case OP_IAND_IMM:
13275                 return OP_X86_AND_MEMBASE_IMM;
13276         case OP_IOR_IMM:
13277                 return OP_X86_OR_MEMBASE_IMM;
13278         case OP_IXOR_IMM:
13279                 return OP_X86_XOR_MEMBASE_IMM;
13280         case OP_LADD:
13281                 return OP_AMD64_ADD_MEMBASE_REG;
13282         case OP_LSUB:
13283                 return OP_AMD64_SUB_MEMBASE_REG;
13284         case OP_LAND:
13285                 return OP_AMD64_AND_MEMBASE_REG;
13286         case OP_LOR:
13287                 return OP_AMD64_OR_MEMBASE_REG;
13288         case OP_LXOR:
13289                 return OP_AMD64_XOR_MEMBASE_REG;
13290         case OP_ADD_IMM:
13291         case OP_LADD_IMM:
13292                 return OP_AMD64_ADD_MEMBASE_IMM;
13293         case OP_SUB_IMM:
13294         case OP_LSUB_IMM:
13295                 return OP_AMD64_SUB_MEMBASE_IMM;
13296         case OP_AND_IMM:
13297         case OP_LAND_IMM:
13298                 return OP_AMD64_AND_MEMBASE_IMM;
13299         case OP_OR_IMM:
13300         case OP_LOR_IMM:
13301                 return OP_AMD64_OR_MEMBASE_IMM;
13302         case OP_XOR_IMM:
13303         case OP_LXOR_IMM:
13304                 return OP_AMD64_XOR_MEMBASE_IMM;
13305         case OP_MOVE:
13306                 return OP_NOP;
13307         }
13308 #endif
13309
13310         return -1;
13311 }
13312
13313 static inline int
13314 op_to_op_store_membase (int store_opcode, int opcode)
13315 {
13316 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13317         switch (opcode) {
13318         case OP_ICEQ:
13319                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13320                         return OP_X86_SETEQ_MEMBASE;
13321         case OP_CNE:
13322                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13323                         return OP_X86_SETNE_MEMBASE;
13324         }
13325 #endif
13326
13327         return -1;
13328 }
13329
13330 static inline int
13331 op_to_op_src1_membase (int load_opcode, int opcode)
13332 {
13333 #ifdef TARGET_X86
13334         /* FIXME: This has sign extension issues */
13335         /*
13336         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
13337                 return OP_X86_COMPARE_MEMBASE8_IMM;
13338         */
13339
13340         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
13341                 return -1;
13342
13343         switch (opcode) {
13344         case OP_X86_PUSH:
13345                 return OP_X86_PUSH_MEMBASE;
13346         case OP_COMPARE_IMM:
13347         case OP_ICOMPARE_IMM:
13348                 return OP_X86_COMPARE_MEMBASE_IMM;
13349         case OP_COMPARE:
13350         case OP_ICOMPARE:
13351                 return OP_X86_COMPARE_MEMBASE_REG;
13352         }
13353 #endif
13354
13355 #ifdef TARGET_AMD64
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         switch (opcode) {
13363         case OP_X86_PUSH:
13364 #ifdef __mono_ilp32__
13365                 if (load_opcode == OP_LOADI8_MEMBASE)
13366 #else
13367                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
13368 #endif
13369                         return OP_X86_PUSH_MEMBASE;
13370                 break;
13371                 /* FIXME: This only works for 32 bit immediates
13372         case OP_COMPARE_IMM:
13373         case OP_LCOMPARE_IMM:
13374                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
13375                         return OP_AMD64_COMPARE_MEMBASE_IMM;
13376                 */
13377         case OP_ICOMPARE_IMM:
13378                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
13379                         return OP_AMD64_ICOMPARE_MEMBASE_IMM;
13380                 break;
13381         case OP_COMPARE:
13382         case OP_LCOMPARE:
13383 #ifdef __mono_ilp32__
13384                 if (load_opcode == OP_LOAD_MEMBASE)
13385                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
13386                 if (load_opcode == OP_LOADI8_MEMBASE)
13387 #else
13388                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
13389 #endif
13390                         return OP_AMD64_COMPARE_MEMBASE_REG;
13391                 break;
13392         case OP_ICOMPARE:
13393                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
13394                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
13395                 break;
13396         }
13397 #endif
13398
13399         return -1;
13400 }
13401
13402 static inline int
13403 op_to_op_src2_membase (int load_opcode, int opcode)
13404 {
13405 #ifdef TARGET_X86
13406         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
13407                 return -1;
13408         
13409         switch (opcode) {
13410         case OP_COMPARE:
13411         case OP_ICOMPARE:
13412                 return OP_X86_COMPARE_REG_MEMBASE;
13413         case OP_IADD:
13414                 return OP_X86_ADD_REG_MEMBASE;
13415         case OP_ISUB:
13416                 return OP_X86_SUB_REG_MEMBASE;
13417         case OP_IAND:
13418                 return OP_X86_AND_REG_MEMBASE;
13419         case OP_IOR:
13420                 return OP_X86_OR_REG_MEMBASE;
13421         case OP_IXOR:
13422                 return OP_X86_XOR_REG_MEMBASE;
13423         }
13424 #endif
13425
13426 #ifdef TARGET_AMD64
13427 #ifdef __mono_ilp32__
13428         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE) ) {
13429 #else
13430         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)) {
13431 #endif
13432                 switch (opcode) {
13433                 case OP_ICOMPARE:
13434                         return OP_AMD64_ICOMPARE_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 #ifdef __mono_ilp32__
13447         } else if (load_opcode == OP_LOADI8_MEMBASE) {
13448 #else
13449         } else if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE)) {
13450 #endif
13451                 switch (opcode) {
13452                 case OP_COMPARE:
13453                 case OP_LCOMPARE:
13454                         return OP_AMD64_COMPARE_REG_MEMBASE;
13455                 case OP_LADD:
13456                         return OP_AMD64_ADD_REG_MEMBASE;
13457                 case OP_LSUB:
13458                         return OP_AMD64_SUB_REG_MEMBASE;
13459                 case OP_LAND:
13460                         return OP_AMD64_AND_REG_MEMBASE;
13461                 case OP_LOR:
13462                         return OP_AMD64_OR_REG_MEMBASE;
13463                 case OP_LXOR:
13464                         return OP_AMD64_XOR_REG_MEMBASE;
13465                 }
13466         }
13467 #endif
13468
13469         return -1;
13470 }
13471
13472 int
13473 mono_op_to_op_imm_noemul (int opcode)
13474 {
13475         switch (opcode) {
13476 #if SIZEOF_REGISTER == 4 && !defined(MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS)
13477         case OP_LSHR:
13478         case OP_LSHL:
13479         case OP_LSHR_UN:
13480                 return -1;
13481 #endif
13482 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
13483         case OP_IDIV:
13484         case OP_IDIV_UN:
13485         case OP_IREM:
13486         case OP_IREM_UN:
13487                 return -1;
13488 #endif
13489 #if defined(MONO_ARCH_EMULATE_MUL_DIV)
13490         case OP_IMUL:
13491                 return -1;
13492 #endif
13493         default:
13494                 return mono_op_to_op_imm (opcode);
13495         }
13496 }
13497
13498 /**
13499  * mono_handle_global_vregs:
13500  *
13501  *   Make vregs used in more than one bblock 'global', i.e. allocate a variable
13502  * for them.
13503  */
13504 void
13505 mono_handle_global_vregs (MonoCompile *cfg)
13506 {
13507         gint32 *vreg_to_bb;
13508         MonoBasicBlock *bb;
13509         int i, pos;
13510
13511         vreg_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (gint32*) * cfg->next_vreg + 1);
13512
13513 #ifdef MONO_ARCH_SIMD_INTRINSICS
13514         if (cfg->uses_simd_intrinsics)
13515                 mono_simd_simplify_indirection (cfg);
13516 #endif
13517
13518         /* Find local vregs used in more than one bb */
13519         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13520                 MonoInst *ins = bb->code;       
13521                 int block_num = bb->block_num;
13522
13523                 if (cfg->verbose_level > 2)
13524                         printf ("\nHANDLE-GLOBAL-VREGS BLOCK %d:\n", bb->block_num);
13525
13526                 cfg->cbb = bb;
13527                 for (; ins; ins = ins->next) {
13528                         const char *spec = INS_INFO (ins->opcode);
13529                         int regtype = 0, regindex;
13530                         gint32 prev_bb;
13531
13532                         if (G_UNLIKELY (cfg->verbose_level > 2))
13533                                 mono_print_ins (ins);
13534
13535                         g_assert (ins->opcode >= MONO_CEE_LAST);
13536
13537                         for (regindex = 0; regindex < 4; regindex ++) {
13538                                 int vreg = 0;
13539
13540                                 if (regindex == 0) {
13541                                         regtype = spec [MONO_INST_DEST];
13542                                         if (regtype == ' ')
13543                                                 continue;
13544                                         vreg = ins->dreg;
13545                                 } else if (regindex == 1) {
13546                                         regtype = spec [MONO_INST_SRC1];
13547                                         if (regtype == ' ')
13548                                                 continue;
13549                                         vreg = ins->sreg1;
13550                                 } else if (regindex == 2) {
13551                                         regtype = spec [MONO_INST_SRC2];
13552                                         if (regtype == ' ')
13553                                                 continue;
13554                                         vreg = ins->sreg2;
13555                                 } else if (regindex == 3) {
13556                                         regtype = spec [MONO_INST_SRC3];
13557                                         if (regtype == ' ')
13558                                                 continue;
13559                                         vreg = ins->sreg3;
13560                                 }
13561
13562 #if SIZEOF_REGISTER == 4
13563                                 /* In the LLVM case, the long opcodes are not decomposed */
13564                                 if (regtype == 'l' && !COMPILE_LLVM (cfg)) {
13565                                         /*
13566                                          * Since some instructions reference the original long vreg,
13567                                          * and some reference the two component vregs, it is quite hard
13568                                          * to determine when it needs to be global. So be conservative.
13569                                          */
13570                                         if (!get_vreg_to_inst (cfg, vreg)) {
13571                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
13572
13573                                                 if (cfg->verbose_level > 2)
13574                                                         printf ("LONG VREG R%d made global.\n", vreg);
13575                                         }
13576
13577                                         /*
13578                                          * Make the component vregs volatile since the optimizations can
13579                                          * get confused otherwise.
13580                                          */
13581                                         get_vreg_to_inst (cfg, vreg + 1)->flags |= MONO_INST_VOLATILE;
13582                                         get_vreg_to_inst (cfg, vreg + 2)->flags |= MONO_INST_VOLATILE;
13583                                 }
13584 #endif
13585
13586                                 g_assert (vreg != -1);
13587
13588                                 prev_bb = vreg_to_bb [vreg];
13589                                 if (prev_bb == 0) {
13590                                         /* 0 is a valid block num */
13591                                         vreg_to_bb [vreg] = block_num + 1;
13592                                 } else if ((prev_bb != block_num + 1) && (prev_bb != -1)) {
13593                                         if (((regtype == 'i' && (vreg < MONO_MAX_IREGS))) || (regtype == 'f' && (vreg < MONO_MAX_FREGS)))
13594                                                 continue;
13595
13596                                         if (!get_vreg_to_inst (cfg, vreg)) {
13597                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
13598                                                         printf ("VREG R%d used in BB%d and BB%d made global.\n", vreg, vreg_to_bb [vreg], block_num);
13599
13600                                                 switch (regtype) {
13601                                                 case 'i':
13602                                                         if (vreg_is_ref (cfg, vreg))
13603                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL, vreg);
13604                                                         else
13605                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL, vreg);
13606                                                         break;
13607                                                 case 'l':
13608                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
13609                                                         break;
13610                                                 case 'f':
13611                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL, vreg);
13612                                                         break;
13613                                                 case 'v':
13614                                                         mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, vreg);
13615                                                         break;
13616                                                 default:
13617                                                         g_assert_not_reached ();
13618                                                 }
13619                                         }
13620
13621                                         /* Flag as having been used in more than one bb */
13622                                         vreg_to_bb [vreg] = -1;
13623                                 }
13624                         }
13625                 }
13626         }
13627
13628         /* If a variable is used in only one bblock, convert it into a local vreg */
13629         for (i = 0; i < cfg->num_varinfo; i++) {
13630                 MonoInst *var = cfg->varinfo [i];
13631                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
13632
13633                 switch (var->type) {
13634                 case STACK_I4:
13635                 case STACK_OBJ:
13636                 case STACK_PTR:
13637                 case STACK_MP:
13638                 case STACK_VTYPE:
13639 #if SIZEOF_REGISTER == 8
13640                 case STACK_I8:
13641 #endif
13642 #if !defined(TARGET_X86)
13643                 /* Enabling this screws up the fp stack on x86 */
13644                 case STACK_R8:
13645 #endif
13646                         if (mono_arch_is_soft_float ())
13647                                 break;
13648
13649                         /* Arguments are implicitly global */
13650                         /* Putting R4 vars into registers doesn't work currently */
13651                         /* The gsharedvt vars are implicitly referenced by ldaddr opcodes, but those opcodes are only generated later */
13652                         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) {
13653                                 /* 
13654                                  * Make that the variable's liveness interval doesn't contain a call, since
13655                                  * that would cause the lvreg to be spilled, making the whole optimization
13656                                  * useless.
13657                                  */
13658                                 /* This is too slow for JIT compilation */
13659 #if 0
13660                                 if (cfg->compile_aot && vreg_to_bb [var->dreg]) {
13661                                         MonoInst *ins;
13662                                         int def_index, call_index, ins_index;
13663                                         gboolean spilled = FALSE;
13664
13665                                         def_index = -1;
13666                                         call_index = -1;
13667                                         ins_index = 0;
13668                                         for (ins = vreg_to_bb [var->dreg]->code; ins; ins = ins->next) {
13669                                                 const char *spec = INS_INFO (ins->opcode);
13670
13671                                                 if ((spec [MONO_INST_DEST] != ' ') && (ins->dreg == var->dreg))
13672                                                         def_index = ins_index;
13673
13674                                                 if (((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg)) ||
13675                                                         ((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg))) {
13676                                                         if (call_index > def_index) {
13677                                                                 spilled = TRUE;
13678                                                                 break;
13679                                                         }
13680                                                 }
13681
13682                                                 if (MONO_IS_CALL (ins))
13683                                                         call_index = ins_index;
13684
13685                                                 ins_index ++;
13686                                         }
13687
13688                                         if (spilled)
13689                                                 break;
13690                                 }
13691 #endif
13692
13693                                 if (G_UNLIKELY (cfg->verbose_level > 2))
13694                                         printf ("CONVERTED R%d(%d) TO VREG.\n", var->dreg, vmv->idx);
13695                                 var->flags |= MONO_INST_IS_DEAD;
13696                                 cfg->vreg_to_inst [var->dreg] = NULL;
13697                         }
13698                         break;
13699                 }
13700         }
13701
13702         /* 
13703          * Compress the varinfo and vars tables so the liveness computation is faster and
13704          * takes up less space.
13705          */
13706         pos = 0;
13707         for (i = 0; i < cfg->num_varinfo; ++i) {
13708                 MonoInst *var = cfg->varinfo [i];
13709                 if (pos < i && cfg->locals_start == i)
13710                         cfg->locals_start = pos;
13711                 if (!(var->flags & MONO_INST_IS_DEAD)) {
13712                         if (pos < i) {
13713                                 cfg->varinfo [pos] = cfg->varinfo [i];
13714                                 cfg->varinfo [pos]->inst_c0 = pos;
13715                                 memcpy (&cfg->vars [pos], &cfg->vars [i], sizeof (MonoMethodVar));
13716                                 cfg->vars [pos].idx = pos;
13717 #if SIZEOF_REGISTER == 4
13718                                 if (cfg->varinfo [pos]->type == STACK_I8) {
13719                                         /* Modify the two component vars too */
13720                                         MonoInst *var1;
13721
13722                                         var1 = get_vreg_to_inst (cfg, cfg->varinfo [pos]->dreg + 1);
13723                                         var1->inst_c0 = pos;
13724                                         var1 = get_vreg_to_inst (cfg, cfg->varinfo [pos]->dreg + 2);
13725                                         var1->inst_c0 = pos;
13726                                 }
13727 #endif
13728                         }
13729                         pos ++;
13730                 }
13731         }
13732         cfg->num_varinfo = pos;
13733         if (cfg->locals_start > cfg->num_varinfo)
13734                 cfg->locals_start = cfg->num_varinfo;
13735 }
13736
13737 /**
13738  * mono_spill_global_vars:
13739  *
13740  *   Generate spill code for variables which are not allocated to registers, 
13741  * and replace vregs with their allocated hregs. *need_local_opts is set to TRUE if
13742  * code is generated which could be optimized by the local optimization passes.
13743  */
13744 void
13745 mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
13746 {
13747         MonoBasicBlock *bb;
13748         char spec2 [16];
13749         int orig_next_vreg;
13750         guint32 *vreg_to_lvreg;
13751         guint32 *lvregs;
13752         guint32 i, lvregs_len;
13753         gboolean dest_has_lvreg = FALSE;
13754         guint32 stacktypes [128];
13755         MonoInst **live_range_start, **live_range_end;
13756         MonoBasicBlock **live_range_start_bb, **live_range_end_bb;
13757         int *gsharedvt_vreg_to_idx = NULL;
13758
13759         *need_local_opts = FALSE;
13760
13761         memset (spec2, 0, sizeof (spec2));
13762
13763         /* FIXME: Move this function to mini.c */
13764         stacktypes ['i'] = STACK_PTR;
13765         stacktypes ['l'] = STACK_I8;
13766         stacktypes ['f'] = STACK_R8;
13767 #ifdef MONO_ARCH_SIMD_INTRINSICS
13768         stacktypes ['x'] = STACK_VTYPE;
13769 #endif
13770
13771 #if SIZEOF_REGISTER == 4
13772         /* Create MonoInsts for longs */
13773         for (i = 0; i < cfg->num_varinfo; i++) {
13774                 MonoInst *ins = cfg->varinfo [i];
13775
13776                 if ((ins->opcode != OP_REGVAR) && !(ins->flags & MONO_INST_IS_DEAD)) {
13777                         switch (ins->type) {
13778                         case STACK_R8:
13779                         case STACK_I8: {
13780                                 MonoInst *tree;
13781
13782                                 if (ins->type == STACK_R8 && !COMPILE_SOFT_FLOAT (cfg))
13783                                         break;
13784
13785                                 g_assert (ins->opcode == OP_REGOFFSET);
13786
13787                                 tree = get_vreg_to_inst (cfg, ins->dreg + 1);
13788                                 g_assert (tree);
13789                                 tree->opcode = OP_REGOFFSET;
13790                                 tree->inst_basereg = ins->inst_basereg;
13791                                 tree->inst_offset = ins->inst_offset + MINI_LS_WORD_OFFSET;
13792
13793                                 tree = get_vreg_to_inst (cfg, ins->dreg + 2);
13794                                 g_assert (tree);
13795                                 tree->opcode = OP_REGOFFSET;
13796                                 tree->inst_basereg = ins->inst_basereg;
13797                                 tree->inst_offset = ins->inst_offset + MINI_MS_WORD_OFFSET;
13798                                 break;
13799                         }
13800                         default:
13801                                 break;
13802                         }
13803                 }
13804         }
13805 #endif
13806
13807         if (cfg->compute_gc_maps) {
13808                 /* registers need liveness info even for !non refs */
13809                 for (i = 0; i < cfg->num_varinfo; i++) {
13810                         MonoInst *ins = cfg->varinfo [i];
13811
13812                         if (ins->opcode == OP_REGVAR)
13813                                 ins->flags |= MONO_INST_GC_TRACK;
13814                 }
13815         }
13816
13817         if (cfg->gsharedvt) {
13818                 gsharedvt_vreg_to_idx = mono_mempool_alloc0 (cfg->mempool, sizeof (int) * cfg->next_vreg);
13819
13820                 for (i = 0; i < cfg->num_varinfo; ++i) {
13821                         MonoInst *ins = cfg->varinfo [i];
13822                         int idx;
13823
13824                         if (mini_is_gsharedvt_variable_type (ins->inst_vtype)) {
13825                                 if (i >= cfg->locals_start) {
13826                                         /* Local */
13827                                         idx = get_gsharedvt_info_slot (cfg, ins->inst_vtype, MONO_RGCTX_INFO_LOCAL_OFFSET);
13828                                         gsharedvt_vreg_to_idx [ins->dreg] = idx + 1;
13829                                         ins->opcode = OP_GSHAREDVT_LOCAL;
13830                                         ins->inst_imm = idx;
13831                                 } else {
13832                                         /* Arg */
13833                                         gsharedvt_vreg_to_idx [ins->dreg] = -1;
13834                                         ins->opcode = OP_GSHAREDVT_ARG_REGOFFSET;
13835                                 }
13836                         }
13837                 }
13838         }
13839                 
13840         /* FIXME: widening and truncation */
13841
13842         /*
13843          * As an optimization, when a variable allocated to the stack is first loaded into 
13844          * an lvreg, we will remember the lvreg and use it the next time instead of loading
13845          * the variable again.
13846          */
13847         orig_next_vreg = cfg->next_vreg;
13848         vreg_to_lvreg = mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * cfg->next_vreg);
13849         lvregs = mono_mempool_alloc (cfg->mempool, sizeof (guint32) * 1024);
13850         lvregs_len = 0;
13851
13852         /* 
13853          * These arrays contain the first and last instructions accessing a given
13854          * variable.
13855          * Since we emit bblocks in the same order we process them here, and we
13856          * don't split live ranges, these will precisely describe the live range of
13857          * the variable, i.e. the instruction range where a valid value can be found
13858          * in the variables location.
13859          * The live range is computed using the liveness info computed by the liveness pass.
13860          * We can't use vmv->range, since that is an abstract live range, and we need
13861          * one which is instruction precise.
13862          * FIXME: Variables used in out-of-line bblocks have a hole in their live range.
13863          */
13864         /* FIXME: Only do this if debugging info is requested */
13865         live_range_start = g_new0 (MonoInst*, cfg->next_vreg);
13866         live_range_end = g_new0 (MonoInst*, cfg->next_vreg);
13867         live_range_start_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
13868         live_range_end_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
13869         
13870         /* Add spill loads/stores */
13871         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13872                 MonoInst *ins;
13873
13874                 if (cfg->verbose_level > 2)
13875                         printf ("\nSPILL BLOCK %d:\n", bb->block_num);
13876
13877                 /* Clear vreg_to_lvreg array */
13878                 for (i = 0; i < lvregs_len; i++)
13879                         vreg_to_lvreg [lvregs [i]] = 0;
13880                 lvregs_len = 0;
13881
13882                 cfg->cbb = bb;
13883                 MONO_BB_FOR_EACH_INS (bb, ins) {
13884                         const char *spec = INS_INFO (ins->opcode);
13885                         int regtype, srcindex, sreg, tmp_reg, prev_dreg, num_sregs;
13886                         gboolean store, no_lvreg;
13887                         int sregs [MONO_MAX_SRC_REGS];
13888
13889                         if (G_UNLIKELY (cfg->verbose_level > 2))
13890                                 mono_print_ins (ins);
13891
13892                         if (ins->opcode == OP_NOP)
13893                                 continue;
13894
13895                         /* 
13896                          * We handle LDADDR here as well, since it can only be decomposed
13897                          * when variable addresses are known.
13898                          */
13899                         if (ins->opcode == OP_LDADDR) {
13900                                 MonoInst *var = ins->inst_p0;
13901
13902                                 if (var->opcode == OP_VTARG_ADDR) {
13903                                         /* Happens on SPARC/S390 where vtypes are passed by reference */
13904                                         MonoInst *vtaddr = var->inst_left;
13905                                         if (vtaddr->opcode == OP_REGVAR) {
13906                                                 ins->opcode = OP_MOVE;
13907                                                 ins->sreg1 = vtaddr->dreg;
13908                                         }
13909                                         else if (var->inst_left->opcode == OP_REGOFFSET) {
13910                                                 ins->opcode = OP_LOAD_MEMBASE;
13911                                                 ins->inst_basereg = vtaddr->inst_basereg;
13912                                                 ins->inst_offset = vtaddr->inst_offset;
13913                                         } else
13914                                                 NOT_IMPLEMENTED;
13915                                 } else if (cfg->gsharedvt && gsharedvt_vreg_to_idx [var->dreg] < 0) {
13916                                         /* gsharedvt arg passed by ref */
13917                                         g_assert (var->opcode == OP_GSHAREDVT_ARG_REGOFFSET);
13918
13919                                         ins->opcode = OP_LOAD_MEMBASE;
13920                                         ins->inst_basereg = var->inst_basereg;
13921                                         ins->inst_offset = var->inst_offset;
13922                                 } else if (cfg->gsharedvt && gsharedvt_vreg_to_idx [var->dreg]) {
13923                                         MonoInst *load, *load2, *load3;
13924                                         int idx = gsharedvt_vreg_to_idx [var->dreg] - 1;
13925                                         int reg1, reg2, reg3;
13926                                         MonoInst *info_var = cfg->gsharedvt_info_var;
13927                                         MonoInst *locals_var = cfg->gsharedvt_locals_var;
13928
13929                                         /*
13930                                          * gsharedvt local.
13931                                          * Compute the address of the local as gsharedvt_locals_var + gsharedvt_info_var->locals_offsets [idx].
13932                                          */
13933
13934                                         g_assert (var->opcode == OP_GSHAREDVT_LOCAL);
13935
13936                                         g_assert (info_var);
13937                                         g_assert (locals_var);
13938
13939                                         /* Mark the instruction used to compute the locals var as used */
13940                                         cfg->gsharedvt_locals_var_ins = NULL;
13941
13942                                         /* Load the offset */
13943                                         if (info_var->opcode == OP_REGOFFSET) {
13944                                                 reg1 = alloc_ireg (cfg);
13945                                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, reg1, info_var->inst_basereg, info_var->inst_offset);
13946                                         } else if (info_var->opcode == OP_REGVAR) {
13947                                                 load = NULL;
13948                                                 reg1 = info_var->dreg;
13949                                         } else {
13950                                                 g_assert_not_reached ();
13951                                         }
13952                                         reg2 = alloc_ireg (cfg);
13953                                         NEW_LOAD_MEMBASE (cfg, load2, OP_LOADI4_MEMBASE, reg2, reg1, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
13954                                         /* Load the locals area address */
13955                                         reg3 = alloc_ireg (cfg);
13956                                         if (locals_var->opcode == OP_REGOFFSET) {
13957                                                 NEW_LOAD_MEMBASE (cfg, load3, OP_LOAD_MEMBASE, reg3, locals_var->inst_basereg, locals_var->inst_offset);
13958                                         } else if (locals_var->opcode == OP_REGVAR) {
13959                                                 NEW_UNALU (cfg, load3, OP_MOVE, reg3, locals_var->dreg);
13960                                         } else {
13961                                                 g_assert_not_reached ();
13962                                         }
13963                                         /* Compute the address */
13964                                         ins->opcode = OP_PADD;
13965                                         ins->sreg1 = reg3;
13966                                         ins->sreg2 = reg2;
13967
13968                                         mono_bblock_insert_before_ins (bb, ins, load3);
13969                                         mono_bblock_insert_before_ins (bb, load3, load2);
13970                                         if (load)
13971                                                 mono_bblock_insert_before_ins (bb, load2, load);
13972                                 } else {
13973                                         g_assert (var->opcode == OP_REGOFFSET);
13974
13975                                         ins->opcode = OP_ADD_IMM;
13976                                         ins->sreg1 = var->inst_basereg;
13977                                         ins->inst_imm = var->inst_offset;
13978                                 }
13979
13980                                 *need_local_opts = TRUE;
13981                                 spec = INS_INFO (ins->opcode);
13982                         }
13983
13984                         if (ins->opcode < MONO_CEE_LAST) {
13985                                 mono_print_ins (ins);
13986                                 g_assert_not_reached ();
13987                         }
13988
13989                         /*
13990                          * Store opcodes have destbasereg in the dreg, but in reality, it is an
13991                          * src register.
13992                          * FIXME:
13993                          */
13994                         if (MONO_IS_STORE_MEMBASE (ins)) {
13995                                 tmp_reg = ins->dreg;
13996                                 ins->dreg = ins->sreg2;
13997                                 ins->sreg2 = tmp_reg;
13998                                 store = TRUE;
13999
14000                                 spec2 [MONO_INST_DEST] = ' ';
14001                                 spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14002                                 spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14003                                 spec2 [MONO_INST_SRC3] = ' ';
14004                                 spec = spec2;
14005                         } else if (MONO_IS_STORE_MEMINDEX (ins))
14006                                 g_assert_not_reached ();
14007                         else
14008                                 store = FALSE;
14009                         no_lvreg = FALSE;
14010
14011                         if (G_UNLIKELY (cfg->verbose_level > 2)) {
14012                                 printf ("\t %.3s %d", spec, ins->dreg);
14013                                 num_sregs = mono_inst_get_src_registers (ins, sregs);
14014                                 for (srcindex = 0; srcindex < num_sregs; ++srcindex)
14015                                         printf (" %d", sregs [srcindex]);
14016                                 printf ("\n");
14017                         }
14018
14019                         /***************/
14020                         /*    DREG     */
14021                         /***************/
14022                         regtype = spec [MONO_INST_DEST];
14023                         g_assert (((ins->dreg == -1) && (regtype == ' ')) || ((ins->dreg != -1) && (regtype != ' ')));
14024                         prev_dreg = -1;
14025
14026                         if ((ins->dreg != -1) && get_vreg_to_inst (cfg, ins->dreg)) {
14027                                 MonoInst *var = get_vreg_to_inst (cfg, ins->dreg);
14028                                 MonoInst *store_ins;
14029                                 int store_opcode;
14030                                 MonoInst *def_ins = ins;
14031                                 int dreg = ins->dreg; /* The original vreg */
14032
14033                                 store_opcode = mono_type_to_store_membase (cfg, var->inst_vtype);
14034
14035                                 if (var->opcode == OP_REGVAR) {
14036                                         ins->dreg = var->dreg;
14037                                 } 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)) {
14038                                         /* 
14039                                          * Instead of emitting a load+store, use a _membase opcode.
14040                                          */
14041                                         g_assert (var->opcode == OP_REGOFFSET);
14042                                         if (ins->opcode == OP_MOVE) {
14043                                                 NULLIFY_INS (ins);
14044                                                 def_ins = NULL;
14045                                         } else {
14046                                                 ins->opcode = op_to_op_dest_membase (store_opcode, ins->opcode);
14047                                                 ins->inst_basereg = var->inst_basereg;
14048                                                 ins->inst_offset = var->inst_offset;
14049                                                 ins->dreg = -1;
14050                                         }
14051                                         spec = INS_INFO (ins->opcode);
14052                                 } else {
14053                                         guint32 lvreg;
14054
14055                                         g_assert (var->opcode == OP_REGOFFSET);
14056
14057                                         prev_dreg = ins->dreg;
14058
14059                                         /* Invalidate any previous lvreg for this vreg */
14060                                         vreg_to_lvreg [ins->dreg] = 0;
14061
14062                                         lvreg = 0;
14063
14064                                         if (COMPILE_SOFT_FLOAT (cfg) && store_opcode == OP_STORER8_MEMBASE_REG) {
14065                                                 regtype = 'l';
14066                                                 store_opcode = OP_STOREI8_MEMBASE_REG;
14067                                         }
14068
14069                                         ins->dreg = alloc_dreg (cfg, stacktypes [regtype]);
14070
14071 #if SIZEOF_REGISTER != 8
14072                                         if (regtype == 'l') {
14073                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET, ins->dreg + 1);
14074                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14075                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET, ins->dreg + 2);
14076                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14077                                                 def_ins = store_ins;
14078                                         }
14079                                         else
14080 #endif
14081                                         {
14082                                                 g_assert (store_opcode != OP_STOREV_MEMBASE);
14083
14084                                                 /* Try to fuse the store into the instruction itself */
14085                                                 /* FIXME: Add more instructions */
14086                                                 if (!lvreg && ((ins->opcode == OP_ICONST) || ((ins->opcode == OP_I8CONST) && (ins->inst_c0 == 0)))) {
14087                                                         ins->opcode = store_membase_reg_to_store_membase_imm (store_opcode);
14088                                                         ins->inst_imm = ins->inst_c0;
14089                                                         ins->inst_destbasereg = var->inst_basereg;
14090                                                         ins->inst_offset = var->inst_offset;
14091                                                         spec = INS_INFO (ins->opcode);
14092                                                 } else if (!lvreg && ((ins->opcode == OP_MOVE) || (ins->opcode == OP_FMOVE) || (ins->opcode == OP_LMOVE) || (ins->opcode == OP_RMOVE))) {
14093                                                         ins->opcode = store_opcode;
14094                                                         ins->inst_destbasereg = var->inst_basereg;
14095                                                         ins->inst_offset = var->inst_offset;
14096
14097                                                         no_lvreg = TRUE;
14098
14099                                                         tmp_reg = ins->dreg;
14100                                                         ins->dreg = ins->sreg2;
14101                                                         ins->sreg2 = tmp_reg;
14102                                                         store = TRUE;
14103
14104                                                         spec2 [MONO_INST_DEST] = ' ';
14105                                                         spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14106                                                         spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14107                                                         spec2 [MONO_INST_SRC3] = ' ';
14108                                                         spec = spec2;
14109                                                 } else if (!lvreg && (op_to_op_store_membase (store_opcode, ins->opcode) != -1)) {
14110                                                         // FIXME: The backends expect the base reg to be in inst_basereg
14111                                                         ins->opcode = op_to_op_store_membase (store_opcode, ins->opcode);
14112                                                         ins->dreg = -1;
14113                                                         ins->inst_basereg = var->inst_basereg;
14114                                                         ins->inst_offset = var->inst_offset;
14115                                                         spec = INS_INFO (ins->opcode);
14116                                                 } else {
14117                                                         /* printf ("INS: "); mono_print_ins (ins); */
14118                                                         /* Create a store instruction */
14119                                                         NEW_STORE_MEMBASE (cfg, store_ins, store_opcode, var->inst_basereg, var->inst_offset, ins->dreg);
14120
14121                                                         /* Insert it after the instruction */
14122                                                         mono_bblock_insert_after_ins (bb, ins, store_ins);
14123
14124                                                         def_ins = store_ins;
14125
14126                                                         /* 
14127                                                          * We can't assign ins->dreg to var->dreg here, since the
14128                                                          * sregs could use it. So set a flag, and do it after
14129                                                          * the sregs.
14130                                                          */
14131                                                         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)))
14132                                                                 dest_has_lvreg = TRUE;
14133                                                 }
14134                                         }
14135                                 }
14136
14137                                 if (def_ins && !live_range_start [dreg]) {
14138                                         live_range_start [dreg] = def_ins;
14139                                         live_range_start_bb [dreg] = bb;
14140                                 }
14141
14142                                 if (cfg->compute_gc_maps && def_ins && (var->flags & MONO_INST_GC_TRACK)) {
14143                                         MonoInst *tmp;
14144
14145                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
14146                                         tmp->inst_c1 = dreg;
14147                                         mono_bblock_insert_after_ins (bb, def_ins, tmp);
14148                                 }
14149                         }
14150
14151                         /************/
14152                         /*  SREGS   */
14153                         /************/
14154                         num_sregs = mono_inst_get_src_registers (ins, sregs);
14155                         for (srcindex = 0; srcindex < 3; ++srcindex) {
14156                                 regtype = spec [MONO_INST_SRC1 + srcindex];
14157                                 sreg = sregs [srcindex];
14158
14159                                 g_assert (((sreg == -1) && (regtype == ' ')) || ((sreg != -1) && (regtype != ' ')));
14160                                 if ((sreg != -1) && get_vreg_to_inst (cfg, sreg)) {
14161                                         MonoInst *var = get_vreg_to_inst (cfg, sreg);
14162                                         MonoInst *use_ins = ins;
14163                                         MonoInst *load_ins;
14164                                         guint32 load_opcode;
14165
14166                                         if (var->opcode == OP_REGVAR) {
14167                                                 sregs [srcindex] = var->dreg;
14168                                                 //mono_inst_set_src_registers (ins, sregs);
14169                                                 live_range_end [sreg] = use_ins;
14170                                                 live_range_end_bb [sreg] = bb;
14171
14172                                                 if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14173                                                         MonoInst *tmp;
14174
14175                                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14176                                                         /* var->dreg is a hreg */
14177                                                         tmp->inst_c1 = sreg;
14178                                                         mono_bblock_insert_after_ins (bb, ins, tmp);
14179                                                 }
14180
14181                                                 continue;
14182                                         }
14183
14184                                         g_assert (var->opcode == OP_REGOFFSET);
14185                                                 
14186                                         load_opcode = mono_type_to_load_membase (cfg, var->inst_vtype);
14187
14188                                         g_assert (load_opcode != OP_LOADV_MEMBASE);
14189
14190                                         if (vreg_to_lvreg [sreg]) {
14191                                                 g_assert (vreg_to_lvreg [sreg] != -1);
14192
14193                                                 /* The variable is already loaded to an lvreg */
14194                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
14195                                                         printf ("\t\tUse lvreg R%d for R%d.\n", vreg_to_lvreg [sreg], sreg);
14196                                                 sregs [srcindex] = vreg_to_lvreg [sreg];
14197                                                 //mono_inst_set_src_registers (ins, sregs);
14198                                                 continue;
14199                                         }
14200
14201                                         /* Try to fuse the load into the instruction */
14202                                         if ((srcindex == 0) && (op_to_op_src1_membase (load_opcode, ins->opcode) != -1)) {
14203                                                 ins->opcode = op_to_op_src1_membase (load_opcode, ins->opcode);
14204                                                 sregs [0] = var->inst_basereg;
14205                                                 //mono_inst_set_src_registers (ins, sregs);
14206                                                 ins->inst_offset = var->inst_offset;
14207                                         } else if ((srcindex == 1) && (op_to_op_src2_membase (load_opcode, ins->opcode) != -1)) {
14208                                                 ins->opcode = op_to_op_src2_membase (load_opcode, ins->opcode);
14209                                                 sregs [1] = var->inst_basereg;
14210                                                 //mono_inst_set_src_registers (ins, sregs);
14211                                                 ins->inst_offset = var->inst_offset;
14212                                         } else {
14213                                                 if (MONO_IS_REAL_MOVE (ins)) {
14214                                                         ins->opcode = OP_NOP;
14215                                                         sreg = ins->dreg;
14216                                                 } else {
14217                                                         //printf ("%d ", srcindex); mono_print_ins (ins);
14218
14219                                                         sreg = alloc_dreg (cfg, stacktypes [regtype]);
14220
14221                                                         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) {
14222                                                                 if (var->dreg == prev_dreg) {
14223                                                                         /*
14224                                                                          * sreg refers to the value loaded by the load
14225                                                                          * emitted below, but we need to use ins->dreg
14226                                                                          * since it refers to the store emitted earlier.
14227                                                                          */
14228                                                                         sreg = ins->dreg;
14229                                                                 }
14230                                                                 g_assert (sreg != -1);
14231                                                                 vreg_to_lvreg [var->dreg] = sreg;
14232                                                                 g_assert (lvregs_len < 1024);
14233                                                                 lvregs [lvregs_len ++] = var->dreg;
14234                                                         }
14235                                                 }
14236
14237                                                 sregs [srcindex] = sreg;
14238                                                 //mono_inst_set_src_registers (ins, sregs);
14239
14240 #if SIZEOF_REGISTER != 8
14241                                                 if (regtype == 'l') {
14242                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 2, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET);
14243                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14244                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 1, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET);
14245                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14246                                                         use_ins = load_ins;
14247                                                 }
14248                                                 else
14249 #endif
14250                                                 {
14251 #if SIZEOF_REGISTER == 4
14252                                                         g_assert (load_opcode != OP_LOADI8_MEMBASE);
14253 #endif
14254                                                         NEW_LOAD_MEMBASE (cfg, load_ins, load_opcode, sreg, var->inst_basereg, var->inst_offset);
14255                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14256                                                         use_ins = load_ins;
14257                                                 }
14258                                         }
14259
14260                                         if (var->dreg < orig_next_vreg) {
14261                                                 live_range_end [var->dreg] = use_ins;
14262                                                 live_range_end_bb [var->dreg] = bb;
14263                                         }
14264
14265                                         if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14266                                                 MonoInst *tmp;
14267
14268                                                 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14269                                                 tmp->inst_c1 = var->dreg;
14270                                                 mono_bblock_insert_after_ins (bb, ins, tmp);
14271                                         }
14272                                 }
14273                         }
14274                         mono_inst_set_src_registers (ins, sregs);
14275
14276                         if (dest_has_lvreg) {
14277                                 g_assert (ins->dreg != -1);
14278                                 vreg_to_lvreg [prev_dreg] = ins->dreg;
14279                                 g_assert (lvregs_len < 1024);
14280                                 lvregs [lvregs_len ++] = prev_dreg;
14281                                 dest_has_lvreg = FALSE;
14282                         }
14283
14284                         if (store) {
14285                                 tmp_reg = ins->dreg;
14286                                 ins->dreg = ins->sreg2;
14287                                 ins->sreg2 = tmp_reg;
14288                         }
14289
14290                         if (MONO_IS_CALL (ins)) {
14291                                 /* Clear vreg_to_lvreg array */
14292                                 for (i = 0; i < lvregs_len; i++)
14293                                         vreg_to_lvreg [lvregs [i]] = 0;
14294                                 lvregs_len = 0;
14295                         } else if (ins->opcode == OP_NOP) {
14296                                 ins->dreg = -1;
14297                                 MONO_INST_NULLIFY_SREGS (ins);
14298                         }
14299
14300                         if (cfg->verbose_level > 2)
14301                                 mono_print_ins_index (1, ins);
14302                 }
14303
14304                 /* Extend the live range based on the liveness info */
14305                 if (cfg->compute_precise_live_ranges && bb->live_out_set && bb->code) {
14306                         for (i = 0; i < cfg->num_varinfo; i ++) {
14307                                 MonoMethodVar *vi = MONO_VARINFO (cfg, i);
14308
14309                                 if (vreg_is_volatile (cfg, vi->vreg))
14310                                         /* The liveness info is incomplete */
14311                                         continue;
14312
14313                                 if (mono_bitset_test_fast (bb->live_in_set, i) && !live_range_start [vi->vreg]) {
14314                                         /* Live from at least the first ins of this bb */
14315                                         live_range_start [vi->vreg] = bb->code;
14316                                         live_range_start_bb [vi->vreg] = bb;
14317                                 }
14318
14319                                 if (mono_bitset_test_fast (bb->live_out_set, i)) {
14320                                         /* Live at least until the last ins of this bb */
14321                                         live_range_end [vi->vreg] = bb->last_ins;
14322                                         live_range_end_bb [vi->vreg] = bb;
14323                                 }
14324                         }
14325                 }
14326         }
14327         
14328 #ifdef MONO_ARCH_HAVE_LIVERANGE_OPS
14329         /*
14330          * Emit LIVERANGE_START/LIVERANGE_END opcodes, the backend will implement them
14331          * by storing the current native offset into MonoMethodVar->live_range_start/end.
14332          */
14333         if (cfg->compute_precise_live_ranges && cfg->comp_done & MONO_COMP_LIVENESS) {
14334                 for (i = 0; i < cfg->num_varinfo; ++i) {
14335                         int vreg = MONO_VARINFO (cfg, i)->vreg;
14336                         MonoInst *ins;
14337
14338                         if (live_range_start [vreg]) {
14339                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_START);
14340                                 ins->inst_c0 = i;
14341                                 ins->inst_c1 = vreg;
14342                                 mono_bblock_insert_after_ins (live_range_start_bb [vreg], live_range_start [vreg], ins);
14343                         }
14344                         if (live_range_end [vreg]) {
14345                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_END);
14346                                 ins->inst_c0 = i;
14347                                 ins->inst_c1 = vreg;
14348                                 if (live_range_end [vreg] == live_range_end_bb [vreg]->last_ins)
14349                                         mono_add_ins_to_end (live_range_end_bb [vreg], ins);
14350                                 else
14351                                         mono_bblock_insert_after_ins (live_range_end_bb [vreg], live_range_end [vreg], ins);
14352                         }
14353                 }
14354         }
14355 #endif
14356
14357         if (cfg->gsharedvt_locals_var_ins) {
14358                 /* Nullify if unused */
14359                 cfg->gsharedvt_locals_var_ins->opcode = OP_PCONST;
14360                 cfg->gsharedvt_locals_var_ins->inst_imm = 0;
14361         }
14362
14363         g_free (live_range_start);
14364         g_free (live_range_end);
14365         g_free (live_range_start_bb);
14366         g_free (live_range_end_bb);
14367 }
14368
14369 /**
14370  * FIXME:
14371  * - use 'iadd' instead of 'int_add'
14372  * - handling ovf opcodes: decompose in method_to_ir.
14373  * - unify iregs/fregs
14374  *   -> partly done, the missing parts are:
14375  *   - a more complete unification would involve unifying the hregs as well, so
14376  *     code wouldn't need if (fp) all over the place. but that would mean the hregs
14377  *     would no longer map to the machine hregs, so the code generators would need to
14378  *     be modified. Also, on ia64 for example, niregs + nfregs > 256 -> bitmasks
14379  *     wouldn't work any more. Duplicating the code in mono_local_regalloc () into
14380  *     fp/non-fp branches speeds it up by about 15%.
14381  * - use sext/zext opcodes instead of shifts
14382  * - add OP_ICALL
14383  * - get rid of TEMPLOADs if possible and use vregs instead
14384  * - clean up usage of OP_P/OP_ opcodes
14385  * - cleanup usage of DUMMY_USE
14386  * - cleanup the setting of ins->type for MonoInst's which are pushed on the 
14387  *   stack
14388  * - set the stack type and allocate a dreg in the EMIT_NEW macros
14389  * - get rid of all the <foo>2 stuff when the new JIT is ready.
14390  * - make sure handle_stack_args () is called before the branch is emitted
14391  * - when the new IR is done, get rid of all unused stuff
14392  * - COMPARE/BEQ as separate instructions or unify them ?
14393  *   - keeping them separate allows specialized compare instructions like
14394  *     compare_imm, compare_membase
14395  *   - most back ends unify fp compare+branch, fp compare+ceq
14396  * - integrate mono_save_args into inline_method
14397  * - get rid of the empty bblocks created by MONO_EMIT_NEW_BRACH_BLOCK2
14398  * - handle long shift opts on 32 bit platforms somehow: they require 
14399  *   3 sregs (2 for arg1 and 1 for arg2)
14400  * - make byref a 'normal' type.
14401  * - use vregs for bb->out_stacks if possible, handle_global_vreg will make them a
14402  *   variable if needed.
14403  * - do not start a new IL level bblock when cfg->cbb is changed by a function call
14404  *   like inline_method.
14405  * - remove inlining restrictions
14406  * - fix LNEG and enable cfold of INEG
14407  * - generalize x86 optimizations like ldelema as a peephole optimization
14408  * - add store_mem_imm for amd64
14409  * - optimize the loading of the interruption flag in the managed->native wrappers
14410  * - avoid special handling of OP_NOP in passes
14411  * - move code inserting instructions into one function/macro.
14412  * - try a coalescing phase after liveness analysis
14413  * - add float -> vreg conversion + local optimizations on !x86
14414  * - figure out how to handle decomposed branches during optimizations, ie.
14415  *   compare+branch, op_jump_table+op_br etc.
14416  * - promote RuntimeXHandles to vregs
14417  * - vtype cleanups:
14418  *   - add a NEW_VARLOADA_VREG macro
14419  * - the vtype optimizations are blocked by the LDADDR opcodes generated for 
14420  *   accessing vtype fields.
14421  * - get rid of I8CONST on 64 bit platforms
14422  * - dealing with the increase in code size due to branches created during opcode
14423  *   decomposition:
14424  *   - use extended basic blocks
14425  *     - all parts of the JIT
14426  *     - handle_global_vregs () && local regalloc
14427  *   - avoid introducing global vregs during decomposition, like 'vtable' in isinst
14428  * - sources of increase in code size:
14429  *   - vtypes
14430  *   - long compares
14431  *   - isinst and castclass
14432  *   - lvregs not allocated to global registers even if used multiple times
14433  * - call cctors outside the JIT, to make -v output more readable and JIT timings more
14434  *   meaningful.
14435  * - check for fp stack leakage in other opcodes too. (-> 'exceptions' optimization)
14436  * - add all micro optimizations from the old JIT
14437  * - put tree optimizations into the deadce pass
14438  * - decompose op_start_handler/op_endfilter/op_endfinally earlier using an arch
14439  *   specific function.
14440  * - unify the float comparison opcodes with the other comparison opcodes, i.e.
14441  *   fcompare + branchCC.
14442  * - create a helper function for allocating a stack slot, taking into account 
14443  *   MONO_CFG_HAS_SPILLUP.
14444  * - merge r68207.
14445  * - merge the ia64 switch changes.
14446  * - optimize mono_regstate2_alloc_int/float.
14447  * - fix the pessimistic handling of variables accessed in exception handler blocks.
14448  * - need to write a tree optimization pass, but the creation of trees is difficult, i.e.
14449  *   parts of the tree could be separated by other instructions, killing the tree
14450  *   arguments, or stores killing loads etc. Also, should we fold loads into other
14451  *   instructions if the result of the load is used multiple times ?
14452  * - make the REM_IMM optimization in mini-x86.c arch-independent.
14453  * - LAST MERGE: 108395.
14454  * - when returning vtypes in registers, generate IR and append it to the end of the
14455  *   last bb instead of doing it in the epilog.
14456  * - change the store opcodes so they use sreg1 instead of dreg to store the base register.
14457  */
14458
14459 /*
14460
14461 NOTES
14462 -----
14463
14464 - When to decompose opcodes:
14465   - earlier: this makes some optimizations hard to implement, since the low level IR
14466   no longer contains the neccessary information. But it is easier to do.
14467   - later: harder to implement, enables more optimizations.
14468 - Branches inside bblocks:
14469   - created when decomposing complex opcodes. 
14470     - branches to another bblock: harmless, but not tracked by the branch 
14471       optimizations, so need to branch to a label at the start of the bblock.
14472     - branches to inside the same bblock: very problematic, trips up the local
14473       reg allocator. Can be fixed by spitting the current bblock, but that is a
14474       complex operation, since some local vregs can become global vregs etc.
14475 - Local/global vregs:
14476   - local vregs: temporary vregs used inside one bblock. Assigned to hregs by the
14477     local register allocator.
14478   - global vregs: used in more than one bblock. Have an associated MonoMethodVar
14479     structure, created by mono_create_var (). Assigned to hregs or the stack by
14480     the global register allocator.
14481 - When to do optimizations like alu->alu_imm:
14482   - earlier -> saves work later on since the IR will be smaller/simpler
14483   - later -> can work on more instructions
14484 - Handling of valuetypes:
14485   - When a vtype is pushed on the stack, a new temporary is created, an 
14486     instruction computing its address (LDADDR) is emitted and pushed on
14487     the stack. Need to optimize cases when the vtype is used immediately as in
14488     argument passing, stloc etc.
14489 - Instead of the to_end stuff in the old JIT, simply call the function handling
14490   the values on the stack before emitting the last instruction of the bb.
14491 */
14492
14493 #endif /* DISABLE_JIT */