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