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