c4553b90815fd8b4a045872cdd32a32869c5af93
[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         if (!cfg->compile_aot || !cfg->backend->need_got_var)
1231                 return NULL;
1232         if (!cfg->got_var) {
1233                 cfg->got_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1234         }
1235         return cfg->got_var;
1236 }
1237
1238 static MonoInst *
1239 mono_get_vtable_var (MonoCompile *cfg)
1240 {
1241         g_assert (cfg->gshared);
1242
1243         if (!cfg->rgctx_var) {
1244                 cfg->rgctx_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1245                 /* force the var to be stack allocated */
1246                 cfg->rgctx_var->flags |= MONO_INST_VOLATILE;
1247         }
1248
1249         return cfg->rgctx_var;
1250 }
1251
1252 static MonoType*
1253 type_from_stack_type (MonoInst *ins) {
1254         switch (ins->type) {
1255         case STACK_I4: return &mono_defaults.int32_class->byval_arg;
1256         case STACK_I8: return &mono_defaults.int64_class->byval_arg;
1257         case STACK_PTR: return &mono_defaults.int_class->byval_arg;
1258         case STACK_R4: return &mono_defaults.single_class->byval_arg;
1259         case STACK_R8: return &mono_defaults.double_class->byval_arg;
1260         case STACK_MP:
1261                 return &ins->klass->this_arg;
1262         case STACK_OBJ: return &mono_defaults.object_class->byval_arg;
1263         case STACK_VTYPE: return &ins->klass->byval_arg;
1264         default:
1265                 g_error ("stack type %d to monotype not handled\n", ins->type);
1266         }
1267         return NULL;
1268 }
1269
1270 static G_GNUC_UNUSED int
1271 type_to_stack_type (MonoCompile *cfg, MonoType *t)
1272 {
1273         t = mono_type_get_underlying_type (t);
1274         switch (t->type) {
1275         case MONO_TYPE_I1:
1276         case MONO_TYPE_U1:
1277         case MONO_TYPE_I2:
1278         case MONO_TYPE_U2:
1279         case MONO_TYPE_I4:
1280         case MONO_TYPE_U4:
1281                 return STACK_I4;
1282         case MONO_TYPE_I:
1283         case MONO_TYPE_U:
1284         case MONO_TYPE_PTR:
1285         case MONO_TYPE_FNPTR:
1286                 return STACK_PTR;
1287         case MONO_TYPE_CLASS:
1288         case MONO_TYPE_STRING:
1289         case MONO_TYPE_OBJECT:
1290         case MONO_TYPE_SZARRAY:
1291         case MONO_TYPE_ARRAY:    
1292                 return STACK_OBJ;
1293         case MONO_TYPE_I8:
1294         case MONO_TYPE_U8:
1295                 return STACK_I8;
1296         case MONO_TYPE_R4:
1297                 return cfg->r4_stack_type;
1298         case MONO_TYPE_R8:
1299                 return STACK_R8;
1300         case MONO_TYPE_VALUETYPE:
1301         case MONO_TYPE_TYPEDBYREF:
1302                 return STACK_VTYPE;
1303         case MONO_TYPE_GENERICINST:
1304                 if (mono_type_generic_inst_is_valuetype (t))
1305                         return STACK_VTYPE;
1306                 else
1307                         return STACK_OBJ;
1308                 break;
1309         default:
1310                 g_assert_not_reached ();
1311         }
1312
1313         return -1;
1314 }
1315
1316 static MonoClass*
1317 array_access_to_klass (int opcode)
1318 {
1319         switch (opcode) {
1320         case CEE_LDELEM_U1:
1321                 return mono_defaults.byte_class;
1322         case CEE_LDELEM_U2:
1323                 return mono_defaults.uint16_class;
1324         case CEE_LDELEM_I:
1325         case CEE_STELEM_I:
1326                 return mono_defaults.int_class;
1327         case CEE_LDELEM_I1:
1328         case CEE_STELEM_I1:
1329                 return mono_defaults.sbyte_class;
1330         case CEE_LDELEM_I2:
1331         case CEE_STELEM_I2:
1332                 return mono_defaults.int16_class;
1333         case CEE_LDELEM_I4:
1334         case CEE_STELEM_I4:
1335                 return mono_defaults.int32_class;
1336         case CEE_LDELEM_U4:
1337                 return mono_defaults.uint32_class;
1338         case CEE_LDELEM_I8:
1339         case CEE_STELEM_I8:
1340                 return mono_defaults.int64_class;
1341         case CEE_LDELEM_R4:
1342         case CEE_STELEM_R4:
1343                 return mono_defaults.single_class;
1344         case CEE_LDELEM_R8:
1345         case CEE_STELEM_R8:
1346                 return mono_defaults.double_class;
1347         case CEE_LDELEM_REF:
1348         case CEE_STELEM_REF:
1349                 return mono_defaults.object_class;
1350         default:
1351                 g_assert_not_reached ();
1352         }
1353         return NULL;
1354 }
1355
1356 /*
1357  * We try to share variables when possible
1358  */
1359 static MonoInst *
1360 mono_compile_get_interface_var (MonoCompile *cfg, int slot, MonoInst *ins)
1361 {
1362         MonoInst *res;
1363         int pos, vnum;
1364
1365         /* inlining can result in deeper stacks */ 
1366         if (slot >= cfg->header->max_stack)
1367                 return mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1368
1369         pos = ins->type - 1 + slot * STACK_MAX;
1370
1371         switch (ins->type) {
1372         case STACK_I4:
1373         case STACK_I8:
1374         case STACK_R8:
1375         case STACK_PTR:
1376         case STACK_MP:
1377         case STACK_OBJ:
1378                 if ((vnum = cfg->intvars [pos]))
1379                         return cfg->varinfo [vnum];
1380                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1381                 cfg->intvars [pos] = res->inst_c0;
1382                 break;
1383         default:
1384                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1385         }
1386         return res;
1387 }
1388
1389 static void
1390 mono_save_token_info (MonoCompile *cfg, MonoImage *image, guint32 token, gpointer key)
1391 {
1392         /* 
1393          * Don't use this if a generic_context is set, since that means AOT can't
1394          * look up the method using just the image+token.
1395          * table == 0 means this is a reference made from a wrapper.
1396          */
1397         if (cfg->compile_aot && !cfg->generic_context && (mono_metadata_token_table (token) > 0)) {
1398                 MonoJumpInfoToken *jump_info_token = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoToken));
1399                 jump_info_token->image = image;
1400                 jump_info_token->token = token;
1401                 g_hash_table_insert (cfg->token_info_hash, key, jump_info_token);
1402         }
1403 }
1404
1405 /*
1406  * This function is called to handle items that are left on the evaluation stack
1407  * at basic block boundaries. What happens is that we save the values to local variables
1408  * and we reload them later when first entering the target basic block (with the
1409  * handle_loaded_temps () function).
1410  * A single joint point will use the same variables (stored in the array bb->out_stack or
1411  * bb->in_stack, if the basic block is before or after the joint point).
1412  *
1413  * This function needs to be called _before_ emitting the last instruction of
1414  * the bb (i.e. before emitting a branch).
1415  * If the stack merge fails at a join point, cfg->unverifiable is set.
1416  */
1417 static void
1418 handle_stack_args (MonoCompile *cfg, MonoInst **sp, int count)
1419 {
1420         int i, bindex;
1421         MonoBasicBlock *bb = cfg->cbb;
1422         MonoBasicBlock *outb;
1423         MonoInst *inst, **locals;
1424         gboolean found;
1425
1426         if (!count)
1427                 return;
1428         if (cfg->verbose_level > 3)
1429                 printf ("%d item(s) on exit from B%d\n", count, bb->block_num);
1430         if (!bb->out_scount) {
1431                 bb->out_scount = count;
1432                 //printf ("bblock %d has out:", bb->block_num);
1433                 found = FALSE;
1434                 for (i = 0; i < bb->out_count; ++i) {
1435                         outb = bb->out_bb [i];
1436                         /* exception handlers are linked, but they should not be considered for stack args */
1437                         if (outb->flags & BB_EXCEPTION_HANDLER)
1438                                 continue;
1439                         //printf (" %d", outb->block_num);
1440                         if (outb->in_stack) {
1441                                 found = TRUE;
1442                                 bb->out_stack = outb->in_stack;
1443                                 break;
1444                         }
1445                 }
1446                 //printf ("\n");
1447                 if (!found) {
1448                         bb->out_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * count);
1449                         for (i = 0; i < count; ++i) {
1450                                 /* 
1451                                  * try to reuse temps already allocated for this purpouse, if they occupy the same
1452                                  * stack slot and if they are of the same type.
1453                                  * This won't cause conflicts since if 'local' is used to 
1454                                  * store one of the values in the in_stack of a bblock, then
1455                                  * the same variable will be used for the same outgoing stack 
1456                                  * slot as well. 
1457                                  * This doesn't work when inlining methods, since the bblocks
1458                                  * in the inlined methods do not inherit their in_stack from
1459                                  * the bblock they are inlined to. See bug #58863 for an
1460                                  * example.
1461                                  */
1462                                 if (cfg->inlined_method)
1463                                         bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
1464                                 else
1465                                         bb->out_stack [i] = mono_compile_get_interface_var (cfg, i, sp [i]);
1466                         }
1467                 }
1468         }
1469
1470         for (i = 0; i < bb->out_count; ++i) {
1471                 outb = bb->out_bb [i];
1472                 /* exception handlers are linked, but they should not be considered for stack args */
1473                 if (outb->flags & BB_EXCEPTION_HANDLER)
1474                         continue;
1475                 if (outb->in_scount) {
1476                         if (outb->in_scount != bb->out_scount) {
1477                                 cfg->unverifiable = TRUE;
1478                                 return;
1479                         }
1480                         continue; /* check they are the same locals */
1481                 }
1482                 outb->in_scount = count;
1483                 outb->in_stack = bb->out_stack;
1484         }
1485
1486         locals = bb->out_stack;
1487         cfg->cbb = bb;
1488         for (i = 0; i < count; ++i) {
1489                 EMIT_NEW_TEMPSTORE (cfg, inst, locals [i]->inst_c0, sp [i]);
1490                 inst->cil_code = sp [i]->cil_code;
1491                 sp [i] = locals [i];
1492                 if (cfg->verbose_level > 3)
1493                         printf ("storing %d to temp %d\n", i, (int)locals [i]->inst_c0);
1494         }
1495
1496         /*
1497          * It is possible that the out bblocks already have in_stack assigned, and
1498          * the in_stacks differ. In this case, we will store to all the different 
1499          * in_stacks.
1500          */
1501
1502         found = TRUE;
1503         bindex = 0;
1504         while (found) {
1505                 /* Find a bblock which has a different in_stack */
1506                 found = FALSE;
1507                 while (bindex < bb->out_count) {
1508                         outb = bb->out_bb [bindex];
1509                         /* exception handlers are linked, but they should not be considered for stack args */
1510                         if (outb->flags & BB_EXCEPTION_HANDLER) {
1511                                 bindex++;
1512                                 continue;
1513                         }
1514                         if (outb->in_stack != locals) {
1515                                 for (i = 0; i < count; ++i) {
1516                                         EMIT_NEW_TEMPSTORE (cfg, inst, outb->in_stack [i]->inst_c0, sp [i]);
1517                                         inst->cil_code = sp [i]->cil_code;
1518                                         sp [i] = locals [i];
1519                                         if (cfg->verbose_level > 3)
1520                                                 printf ("storing %d to temp %d\n", i, (int)outb->in_stack [i]->inst_c0);
1521                                 }
1522                                 locals = outb->in_stack;
1523                                 found = TRUE;
1524                                 break;
1525                         }
1526                         bindex ++;
1527                 }
1528         }
1529 }
1530
1531 static void
1532 mini_emit_interface_bitmap_check (MonoCompile *cfg, int intf_bit_reg, int base_reg, int offset, MonoClass *klass)
1533 {
1534         int ibitmap_reg = alloc_preg (cfg);
1535 #ifdef COMPRESSED_INTERFACE_BITMAP
1536         MonoInst *args [2];
1537         MonoInst *res, *ins;
1538         NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, ibitmap_reg, base_reg, offset);
1539         MONO_ADD_INS (cfg->cbb, ins);
1540         args [0] = ins;
1541         if (cfg->compile_aot)
1542                 EMIT_NEW_AOTCONST (cfg, args [1], MONO_PATCH_INFO_IID, klass);
1543         else
1544                 EMIT_NEW_ICONST (cfg, args [1], klass->interface_id);
1545         res = mono_emit_jit_icall (cfg, mono_class_interface_match, args);
1546         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, intf_bit_reg, res->dreg);
1547 #else
1548         int ibitmap_byte_reg = alloc_preg (cfg);
1549
1550         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, ibitmap_reg, base_reg, offset);
1551
1552         if (cfg->compile_aot) {
1553                 int iid_reg = alloc_preg (cfg);
1554                 int shifted_iid_reg = alloc_preg (cfg);
1555                 int ibitmap_byte_address_reg = alloc_preg (cfg);
1556                 int masked_iid_reg = alloc_preg (cfg);
1557                 int iid_one_bit_reg = alloc_preg (cfg);
1558                 int iid_bit_reg = alloc_preg (cfg);
1559                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1560                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, shifted_iid_reg, iid_reg, 3);
1561                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, ibitmap_byte_address_reg, ibitmap_reg, shifted_iid_reg);
1562                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, ibitmap_byte_reg, ibitmap_byte_address_reg, 0);
1563                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, masked_iid_reg, iid_reg, 7);
1564                 MONO_EMIT_NEW_ICONST (cfg, iid_one_bit_reg, 1);
1565                 MONO_EMIT_NEW_BIALU (cfg, OP_ISHL, iid_bit_reg, iid_one_bit_reg, masked_iid_reg);
1566                 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, intf_bit_reg, ibitmap_byte_reg, iid_bit_reg);
1567         } else {
1568                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, ibitmap_byte_reg, ibitmap_reg, klass->interface_id >> 3);
1569                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, intf_bit_reg, ibitmap_byte_reg, 1 << (klass->interface_id & 7));
1570         }
1571 #endif
1572 }
1573
1574 /* 
1575  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoClass
1576  * stored in "klass_reg" implements the interface "klass".
1577  */
1578 static void
1579 mini_emit_load_intf_bit_reg_class (MonoCompile *cfg, int intf_bit_reg, int klass_reg, MonoClass *klass)
1580 {
1581         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, interface_bitmap), klass);
1582 }
1583
1584 /* 
1585  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoVTable
1586  * stored in "vtable_reg" implements the interface "klass".
1587  */
1588 static void
1589 mini_emit_load_intf_bit_reg_vtable (MonoCompile *cfg, int intf_bit_reg, int vtable_reg, MonoClass *klass)
1590 {
1591         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, interface_bitmap), klass);
1592 }
1593
1594 /* 
1595  * Emit code which checks whenever the interface id of @klass is smaller than
1596  * than the value given by max_iid_reg.
1597 */
1598 static void
1599 mini_emit_max_iid_check (MonoCompile *cfg, int max_iid_reg, MonoClass *klass,
1600                                                  MonoBasicBlock *false_target)
1601 {
1602         if (cfg->compile_aot) {
1603                 int iid_reg = alloc_preg (cfg);
1604                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1605                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, max_iid_reg, iid_reg);
1606         }
1607         else
1608                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, max_iid_reg, klass->interface_id);
1609         if (false_target)
1610                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1611         else
1612                 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1613 }
1614
1615 /* Same as above, but obtains max_iid from a vtable */
1616 static void
1617 mini_emit_max_iid_check_vtable (MonoCompile *cfg, int vtable_reg, MonoClass *klass,
1618                                                                  MonoBasicBlock *false_target)
1619 {
1620         int max_iid_reg = alloc_preg (cfg);
1621                 
1622         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, max_interface_id));
1623         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1624 }
1625
1626 /* Same as above, but obtains max_iid from a klass */
1627 static void
1628 mini_emit_max_iid_check_class (MonoCompile *cfg, int klass_reg, MonoClass *klass,
1629                                                                  MonoBasicBlock *false_target)
1630 {
1631         int max_iid_reg = alloc_preg (cfg);
1632
1633         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, max_interface_id));
1634         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1635 }
1636
1637 static void
1638 mini_emit_isninst_cast_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_ins, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1639 {
1640         int idepth_reg = alloc_preg (cfg);
1641         int stypes_reg = alloc_preg (cfg);
1642         int stype = alloc_preg (cfg);
1643
1644         mono_class_setup_supertypes (klass);
1645
1646         if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1647                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth));
1648                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1649                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1650         }
1651         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes));
1652         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1653         if (klass_ins) {
1654                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, klass_ins->dreg);
1655         } else if (cfg->compile_aot) {
1656                 int const_reg = alloc_preg (cfg);
1657                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1658                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, const_reg);
1659         } else {
1660                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, stype, klass);
1661         }
1662         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, true_target);
1663 }
1664
1665 static void
1666 mini_emit_isninst_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1667 {
1668         mini_emit_isninst_cast_inst (cfg, klass_reg, klass, NULL, false_target, true_target);
1669 }
1670
1671 static void
1672 mini_emit_iface_cast (MonoCompile *cfg, int vtable_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1673 {
1674         int intf_reg = alloc_preg (cfg);
1675
1676         mini_emit_max_iid_check_vtable (cfg, vtable_reg, klass, false_target);
1677         mini_emit_load_intf_bit_reg_vtable (cfg, intf_reg, vtable_reg, klass);
1678         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_reg, 0);
1679         if (true_target)
1680                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1681         else
1682                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");               
1683 }
1684
1685 /*
1686  * Variant of the above that takes a register to the class, not the vtable.
1687  */
1688 static void
1689 mini_emit_iface_class_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1690 {
1691         int intf_bit_reg = alloc_preg (cfg);
1692
1693         mini_emit_max_iid_check_class (cfg, klass_reg, klass, false_target);
1694         mini_emit_load_intf_bit_reg_class (cfg, intf_bit_reg, klass_reg, klass);
1695         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_bit_reg, 0);
1696         if (true_target)
1697                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1698         else
1699                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
1700 }
1701
1702 static inline void
1703 mini_emit_class_check_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_inst)
1704 {
1705         if (klass_inst) {
1706                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_inst->dreg);
1707         } else if (cfg->compile_aot) {
1708                 int const_reg = alloc_preg (cfg);
1709                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1710                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, const_reg);
1711         } else {
1712                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
1713         }
1714         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1715 }
1716
1717 static inline void
1718 mini_emit_class_check (MonoCompile *cfg, int klass_reg, MonoClass *klass)
1719 {
1720         mini_emit_class_check_inst (cfg, klass_reg, klass, NULL);
1721 }
1722
1723 static inline void
1724 mini_emit_class_check_branch (MonoCompile *cfg, int klass_reg, MonoClass *klass, int branch_op, MonoBasicBlock *target)
1725 {
1726         if (cfg->compile_aot) {
1727                 int const_reg = alloc_preg (cfg);
1728                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1729                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, const_reg);
1730         } else {
1731                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
1732         }
1733         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, branch_op, target);
1734 }
1735
1736 static void
1737 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null);
1738         
1739 static void
1740 mini_emit_castclass_inst (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoInst *klass_inst, MonoBasicBlock *object_is_null)
1741 {
1742         if (klass->rank) {
1743                 int rank_reg = alloc_preg (cfg);
1744                 int eclass_reg = alloc_preg (cfg);
1745
1746                 g_assert (!klass_inst);
1747                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, rank));
1748                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
1749                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1750                 //              MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
1751                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
1752                 if (klass->cast_class == mono_defaults.object_class) {
1753                         int parent_reg = alloc_preg (cfg);
1754                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
1755                         mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, object_is_null);
1756                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1757                 } else if (klass->cast_class == mono_defaults.enum_class->parent) {
1758                         mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, object_is_null);
1759                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1760                 } else if (klass->cast_class == mono_defaults.enum_class) {
1761                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1762                 } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1763                         mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, NULL, NULL);
1764                 } else {
1765                         // Pass -1 as obj_reg to skip the check below for arrays of arrays
1766                         mini_emit_castclass (cfg, -1, eclass_reg, klass->cast_class, object_is_null);
1767                 }
1768
1769                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY) && (obj_reg != -1)) {
1770                         /* Check that the object is a vector too */
1771                         int bounds_reg = alloc_preg (cfg);
1772                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
1773                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
1774                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1775                 }
1776         } else {
1777                 int idepth_reg = alloc_preg (cfg);
1778                 int stypes_reg = alloc_preg (cfg);
1779                 int stype = alloc_preg (cfg);
1780
1781                 mono_class_setup_supertypes (klass);
1782
1783                 if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1784                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth));
1785                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1786                         MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1787                 }
1788                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes));
1789                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1790                 mini_emit_class_check_inst (cfg, stype, klass, klass_inst);
1791         }
1792 }
1793
1794 static void
1795 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null)
1796 {
1797         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, NULL, object_is_null);
1798 }
1799
1800 static void 
1801 mini_emit_memset (MonoCompile *cfg, int destreg, int offset, int size, int val, int align)
1802 {
1803         int val_reg;
1804
1805         g_assert (val == 0);
1806
1807         if (align == 0)
1808                 align = 4;
1809
1810         if ((size <= SIZEOF_REGISTER) && (size <= align)) {
1811                 switch (size) {
1812                 case 1:
1813                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, destreg, offset, val);
1814                         return;
1815                 case 2:
1816                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI2_MEMBASE_IMM, destreg, offset, val);
1817                         return;
1818                 case 4:
1819                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI4_MEMBASE_IMM, destreg, offset, val);
1820                         return;
1821 #if SIZEOF_REGISTER == 8
1822                 case 8:
1823                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI8_MEMBASE_IMM, destreg, offset, val);
1824                         return;
1825 #endif
1826                 }
1827         }
1828
1829         val_reg = alloc_preg (cfg);
1830
1831         if (SIZEOF_REGISTER == 8)
1832                 MONO_EMIT_NEW_I8CONST (cfg, val_reg, val);
1833         else
1834                 MONO_EMIT_NEW_ICONST (cfg, val_reg, val);
1835
1836         if (align < 4) {
1837                 /* This could be optimized further if neccesary */
1838                 while (size >= 1) {
1839                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1840                         offset += 1;
1841                         size -= 1;
1842                 }
1843                 return;
1844         }       
1845
1846         if (!cfg->backend->no_unaligned_access && SIZEOF_REGISTER == 8) {
1847                 if (offset % 8) {
1848                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1849                         offset += 4;
1850                         size -= 4;
1851                 }
1852                 while (size >= 8) {
1853                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, offset, val_reg);
1854                         offset += 8;
1855                         size -= 8;
1856                 }
1857         }       
1858
1859         while (size >= 4) {
1860                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1861                 offset += 4;
1862                 size -= 4;
1863         }
1864         while (size >= 2) {
1865                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, val_reg);
1866                 offset += 2;
1867                 size -= 2;
1868         }
1869         while (size >= 1) {
1870                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1871                 offset += 1;
1872                 size -= 1;
1873         }
1874 }
1875
1876 void 
1877 mini_emit_memcpy (MonoCompile *cfg, int destreg, int doffset, int srcreg, int soffset, int size, int align)
1878 {
1879         int cur_reg;
1880
1881         if (align == 0)
1882                 align = 4;
1883
1884         /*FIXME arbitrary hack to avoid unbound code expansion.*/
1885         g_assert (size < 10000);
1886
1887         if (align < 4) {
1888                 /* This could be optimized further if neccesary */
1889                 while (size >= 1) {
1890                         cur_reg = alloc_preg (cfg);
1891                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1892                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1893                         doffset += 1;
1894                         soffset += 1;
1895                         size -= 1;
1896                 }
1897         }
1898
1899         if (!cfg->backend->no_unaligned_access && SIZEOF_REGISTER == 8) {
1900                 while (size >= 8) {
1901                         cur_reg = alloc_preg (cfg);
1902                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI8_MEMBASE, cur_reg, srcreg, soffset);
1903                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, doffset, cur_reg);
1904                         doffset += 8;
1905                         soffset += 8;
1906                         size -= 8;
1907                 }
1908         }       
1909
1910         while (size >= 4) {
1911                 cur_reg = alloc_preg (cfg);
1912                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, cur_reg, srcreg, soffset);
1913                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, doffset, cur_reg);
1914                 doffset += 4;
1915                 soffset += 4;
1916                 size -= 4;
1917         }
1918         while (size >= 2) {
1919                 cur_reg = alloc_preg (cfg);
1920                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, cur_reg, srcreg, soffset);
1921                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, doffset, cur_reg);
1922                 doffset += 2;
1923                 soffset += 2;
1924                 size -= 2;
1925         }
1926         while (size >= 1) {
1927                 cur_reg = alloc_preg (cfg);
1928                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1929                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1930                 doffset += 1;
1931                 soffset += 1;
1932                 size -= 1;
1933         }
1934 }
1935
1936 static void
1937 emit_tls_set (MonoCompile *cfg, int sreg1, int tls_key)
1938 {
1939         MonoInst *ins, *c;
1940
1941         if (cfg->compile_aot) {
1942                 EMIT_NEW_TLS_OFFSETCONST (cfg, c, tls_key);
1943                 MONO_INST_NEW (cfg, ins, OP_TLS_SET_REG);
1944                 ins->sreg1 = sreg1;
1945                 ins->sreg2 = c->dreg;
1946                 MONO_ADD_INS (cfg->cbb, ins);
1947         } else {
1948                 MONO_INST_NEW (cfg, ins, OP_TLS_SET);
1949                 ins->sreg1 = sreg1;
1950                 ins->inst_offset = mini_get_tls_offset (tls_key);
1951                 MONO_ADD_INS (cfg->cbb, ins);
1952         }
1953 }
1954
1955 /*
1956  * emit_push_lmf:
1957  *
1958  *   Emit IR to push the current LMF onto the LMF stack.
1959  */
1960 static void
1961 emit_push_lmf (MonoCompile *cfg)
1962 {
1963         /*
1964          * Emit IR to push the LMF:
1965          * lmf_addr = <lmf_addr from tls>
1966          * lmf->lmf_addr = lmf_addr
1967          * lmf->prev_lmf = *lmf_addr
1968          * *lmf_addr = lmf
1969          */
1970         int lmf_reg, prev_lmf_reg;
1971         MonoInst *ins, *lmf_ins;
1972
1973         if (!cfg->lmf_ir)
1974                 return;
1975
1976         if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
1977                 /* Load current lmf */
1978                 lmf_ins = mono_get_lmf_intrinsic (cfg);
1979                 g_assert (lmf_ins);
1980                 MONO_ADD_INS (cfg->cbb, lmf_ins);
1981                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
1982                 lmf_reg = ins->dreg;
1983                 /* Save previous_lmf */
1984                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), lmf_ins->dreg);
1985                 /* Set new LMF */
1986                 emit_tls_set (cfg, lmf_reg, TLS_KEY_LMF);
1987         } else {
1988                 /*
1989                  * Store lmf_addr in a variable, so it can be allocated to a global register.
1990                  */
1991                 if (!cfg->lmf_addr_var)
1992                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1993
1994 #ifdef HOST_WIN32
1995                 ins = mono_get_jit_tls_intrinsic (cfg);
1996                 if (ins) {
1997                         int jit_tls_dreg = ins->dreg;
1998
1999                         MONO_ADD_INS (cfg->cbb, ins);
2000                         lmf_reg = alloc_preg (cfg);
2001                         EMIT_NEW_BIALU_IMM (cfg, lmf_ins, OP_PADD_IMM, lmf_reg, jit_tls_dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, lmf));
2002                 } else {
2003                         lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
2004                 }
2005 #else
2006                 lmf_ins = mono_get_lmf_addr_intrinsic (cfg);
2007                 if (lmf_ins) {
2008                         MONO_ADD_INS (cfg->cbb, lmf_ins);
2009                 } else {
2010 #ifdef TARGET_IOS
2011                         MonoInst *args [16], *jit_tls_ins, *ins;
2012
2013                         /* Inline mono_get_lmf_addr () */
2014                         /* jit_tls = pthread_getspecific (mono_jit_tls_id); lmf_addr = &jit_tls->lmf; */
2015
2016                         /* Load mono_jit_tls_id */
2017                         if (cfg->compile_aot)
2018                                 EMIT_NEW_AOTCONST (cfg, args [0], MONO_PATCH_INFO_JIT_TLS_ID, NULL);
2019                         else
2020                                 EMIT_NEW_ICONST (cfg, args [0], mono_jit_tls_id);
2021                         /* call pthread_getspecific () */
2022                         jit_tls_ins = mono_emit_jit_icall (cfg, pthread_getspecific, args);
2023                         /* lmf_addr = &jit_tls->lmf */
2024                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, cfg->lmf_addr_var->dreg, jit_tls_ins->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, lmf));
2025                         lmf_ins = ins;
2026 #else
2027                         lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
2028 #endif
2029                 }
2030 #endif
2031                 lmf_ins->dreg = cfg->lmf_addr_var->dreg;
2032
2033                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2034                 lmf_reg = ins->dreg;
2035
2036                 prev_lmf_reg = alloc_preg (cfg);
2037                 /* Save previous_lmf */
2038                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, cfg->lmf_addr_var->dreg, 0);
2039                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), prev_lmf_reg);
2040                 /* Set new lmf */
2041                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, cfg->lmf_addr_var->dreg, 0, lmf_reg);
2042         }
2043 }
2044
2045 /*
2046  * emit_pop_lmf:
2047  *
2048  *   Emit IR to pop the current LMF from the LMF stack.
2049  */
2050 static void
2051 emit_pop_lmf (MonoCompile *cfg)
2052 {
2053         int lmf_reg, lmf_addr_reg, prev_lmf_reg;
2054         MonoInst *ins;
2055
2056         if (!cfg->lmf_ir)
2057                 return;
2058
2059         EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2060         lmf_reg = ins->dreg;
2061
2062         if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
2063                 /* Load previous_lmf */
2064                 prev_lmf_reg = alloc_preg (cfg);
2065                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
2066                 /* Set new LMF */
2067                 emit_tls_set (cfg, prev_lmf_reg, TLS_KEY_LMF);
2068         } else {
2069                 /*
2070                  * Emit IR to pop the LMF:
2071                  * *(lmf->lmf_addr) = lmf->prev_lmf
2072                  */
2073                 /* This could be called before emit_push_lmf () */
2074                 if (!cfg->lmf_addr_var)
2075                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2076                 lmf_addr_reg = cfg->lmf_addr_var->dreg;
2077
2078                 prev_lmf_reg = alloc_preg (cfg);
2079                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
2080                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_addr_reg, 0, prev_lmf_reg);
2081         }
2082 }
2083
2084 static void
2085 emit_instrumentation_call (MonoCompile *cfg, void *func)
2086 {
2087         MonoInst *iargs [1];
2088
2089         /*
2090          * Avoid instrumenting inlined methods since it can
2091          * distort profiling results.
2092          */
2093         if (cfg->method != cfg->current_method)
2094                 return;
2095
2096         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE) {
2097                 EMIT_NEW_METHODCONST (cfg, iargs [0], cfg->method);
2098                 mono_emit_jit_icall (cfg, func, iargs);
2099         }
2100 }
2101
2102 static int
2103 ret_type_to_call_opcode (MonoCompile *cfg, MonoType *type, int calli, int virt)
2104 {
2105 handle_enum:
2106         type = mini_get_underlying_type (type);
2107         switch (type->type) {
2108         case MONO_TYPE_VOID:
2109                 return calli? OP_VOIDCALL_REG: virt? OP_VOIDCALL_MEMBASE: OP_VOIDCALL;
2110         case MONO_TYPE_I1:
2111         case MONO_TYPE_U1:
2112         case MONO_TYPE_I2:
2113         case MONO_TYPE_U2:
2114         case MONO_TYPE_I4:
2115         case MONO_TYPE_U4:
2116                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2117         case MONO_TYPE_I:
2118         case MONO_TYPE_U:
2119         case MONO_TYPE_PTR:
2120         case MONO_TYPE_FNPTR:
2121                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2122         case MONO_TYPE_CLASS:
2123         case MONO_TYPE_STRING:
2124         case MONO_TYPE_OBJECT:
2125         case MONO_TYPE_SZARRAY:
2126         case MONO_TYPE_ARRAY:    
2127                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2128         case MONO_TYPE_I8:
2129         case MONO_TYPE_U8:
2130                 return calli? OP_LCALL_REG: virt? OP_LCALL_MEMBASE: OP_LCALL;
2131         case MONO_TYPE_R4:
2132                 if (cfg->r4fp)
2133                         return calli? OP_RCALL_REG: virt? OP_RCALL_MEMBASE: OP_RCALL;
2134                 else
2135                         return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
2136         case MONO_TYPE_R8:
2137                 return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
2138         case MONO_TYPE_VALUETYPE:
2139                 if (type->data.klass->enumtype) {
2140                         type = mono_class_enum_basetype (type->data.klass);
2141                         goto handle_enum;
2142                 } else
2143                         return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2144         case MONO_TYPE_TYPEDBYREF:
2145                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2146         case MONO_TYPE_GENERICINST:
2147                 type = &type->data.generic_class->container_class->byval_arg;
2148                 goto handle_enum;
2149         case MONO_TYPE_VAR:
2150         case MONO_TYPE_MVAR:
2151                 /* gsharedvt */
2152                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2153         default:
2154                 g_error ("unknown type 0x%02x in ret_type_to_call_opcode", type->type);
2155         }
2156         return -1;
2157 }
2158
2159 /*
2160  * target_type_is_incompatible:
2161  * @cfg: MonoCompile context
2162  *
2163  * Check that the item @arg on the evaluation stack can be stored
2164  * in the target type (can be a local, or field, etc).
2165  * The cfg arg can be used to check if we need verification or just
2166  * validity checks.
2167  *
2168  * Returns: non-0 value if arg can't be stored on a target.
2169  */
2170 static int
2171 target_type_is_incompatible (MonoCompile *cfg, MonoType *target, MonoInst *arg)
2172 {
2173         MonoType *simple_type;
2174         MonoClass *klass;
2175
2176         if (target->byref) {
2177                 /* FIXME: check that the pointed to types match */
2178                 if (arg->type == STACK_MP)
2179                         return target->type != MONO_TYPE_I && arg->klass != mono_class_from_mono_type (target);
2180                 if (arg->type == STACK_PTR)
2181                         return 0;
2182                 return 1;
2183         }
2184
2185         simple_type = mini_get_underlying_type (target);
2186         switch (simple_type->type) {
2187         case MONO_TYPE_VOID:
2188                 return 1;
2189         case MONO_TYPE_I1:
2190         case MONO_TYPE_U1:
2191         case MONO_TYPE_I2:
2192         case MONO_TYPE_U2:
2193         case MONO_TYPE_I4:
2194         case MONO_TYPE_U4:
2195                 if (arg->type != STACK_I4 && arg->type != STACK_PTR)
2196                         return 1;
2197                 return 0;
2198         case MONO_TYPE_PTR:
2199                 /* STACK_MP is needed when setting pinned locals */
2200                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2201                         return 1;
2202                 return 0;
2203         case MONO_TYPE_I:
2204         case MONO_TYPE_U:
2205         case MONO_TYPE_FNPTR:
2206                 /* 
2207                  * Some opcodes like ldloca returns 'transient pointers' which can be stored in
2208                  * in native int. (#688008).
2209                  */
2210                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2211                         return 1;
2212                 return 0;
2213         case MONO_TYPE_CLASS:
2214         case MONO_TYPE_STRING:
2215         case MONO_TYPE_OBJECT:
2216         case MONO_TYPE_SZARRAY:
2217         case MONO_TYPE_ARRAY:    
2218                 if (arg->type != STACK_OBJ)
2219                         return 1;
2220                 /* FIXME: check type compatibility */
2221                 return 0;
2222         case MONO_TYPE_I8:
2223         case MONO_TYPE_U8:
2224                 if (arg->type != STACK_I8)
2225                         return 1;
2226                 return 0;
2227         case MONO_TYPE_R4:
2228                 if (arg->type != cfg->r4_stack_type)
2229                         return 1;
2230                 return 0;
2231         case MONO_TYPE_R8:
2232                 if (arg->type != STACK_R8)
2233                         return 1;
2234                 return 0;
2235         case MONO_TYPE_VALUETYPE:
2236                 if (arg->type != STACK_VTYPE)
2237                         return 1;
2238                 klass = mono_class_from_mono_type (simple_type);
2239                 if (klass != arg->klass)
2240                         return 1;
2241                 return 0;
2242         case MONO_TYPE_TYPEDBYREF:
2243                 if (arg->type != STACK_VTYPE)
2244                         return 1;
2245                 klass = mono_class_from_mono_type (simple_type);
2246                 if (klass != arg->klass)
2247                         return 1;
2248                 return 0;
2249         case MONO_TYPE_GENERICINST:
2250                 if (mono_type_generic_inst_is_valuetype (simple_type)) {
2251                         if (arg->type != STACK_VTYPE)
2252                                 return 1;
2253                         klass = mono_class_from_mono_type (simple_type);
2254                         /* The second cases is needed when doing partial sharing */
2255                         if (klass != arg->klass && mono_class_from_mono_type (target) != arg->klass)
2256                                 return 1;
2257                         return 0;
2258                 } else {
2259                         if (arg->type != STACK_OBJ)
2260                                 return 1;
2261                         /* FIXME: check type compatibility */
2262                         return 0;
2263                 }
2264         case MONO_TYPE_VAR:
2265         case MONO_TYPE_MVAR:
2266                 g_assert (cfg->gshared);
2267                 if (mini_type_var_is_vt (simple_type)) {
2268                         if (arg->type != STACK_VTYPE)
2269                                 return 1;
2270                 } else {
2271                         if (arg->type != STACK_OBJ)
2272                                 return 1;
2273                 }
2274                 return 0;
2275         default:
2276                 g_error ("unknown type 0x%02x in target_type_is_incompatible", simple_type->type);
2277         }
2278         return 1;
2279 }
2280
2281 /*
2282  * Prepare arguments for passing to a function call.
2283  * Return a non-zero value if the arguments can't be passed to the given
2284  * signature.
2285  * The type checks are not yet complete and some conversions may need
2286  * casts on 32 or 64 bit architectures.
2287  *
2288  * FIXME: implement this using target_type_is_incompatible ()
2289  */
2290 static int
2291 check_call_signature (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args)
2292 {
2293         MonoType *simple_type;
2294         int i;
2295
2296         if (sig->hasthis) {
2297                 if (args [0]->type != STACK_OBJ && args [0]->type != STACK_MP && args [0]->type != STACK_PTR)
2298                         return 1;
2299                 args++;
2300         }
2301         for (i = 0; i < sig->param_count; ++i) {
2302                 if (sig->params [i]->byref) {
2303                         if (args [i]->type != STACK_MP && args [i]->type != STACK_PTR)
2304                                 return 1;
2305                         continue;
2306                 }
2307                 simple_type = mini_get_underlying_type (sig->params [i]);
2308 handle_enum:
2309                 switch (simple_type->type) {
2310                 case MONO_TYPE_VOID:
2311                         return 1;
2312                         continue;
2313                 case MONO_TYPE_I1:
2314                 case MONO_TYPE_U1:
2315                 case MONO_TYPE_I2:
2316                 case MONO_TYPE_U2:
2317                 case MONO_TYPE_I4:
2318                 case MONO_TYPE_U4:
2319                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR)
2320                                 return 1;
2321                         continue;
2322                 case MONO_TYPE_I:
2323                 case MONO_TYPE_U:
2324                 case MONO_TYPE_PTR:
2325                 case MONO_TYPE_FNPTR:
2326                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR && args [i]->type != STACK_MP && args [i]->type != STACK_OBJ)
2327                                 return 1;
2328                         continue;
2329                 case MONO_TYPE_CLASS:
2330                 case MONO_TYPE_STRING:
2331                 case MONO_TYPE_OBJECT:
2332                 case MONO_TYPE_SZARRAY:
2333                 case MONO_TYPE_ARRAY:    
2334                         if (args [i]->type != STACK_OBJ)
2335                                 return 1;
2336                         continue;
2337                 case MONO_TYPE_I8:
2338                 case MONO_TYPE_U8:
2339                         if (args [i]->type != STACK_I8)
2340                                 return 1;
2341                         continue;
2342                 case MONO_TYPE_R4:
2343                         if (args [i]->type != cfg->r4_stack_type)
2344                                 return 1;
2345                         continue;
2346                 case MONO_TYPE_R8:
2347                         if (args [i]->type != STACK_R8)
2348                                 return 1;
2349                         continue;
2350                 case MONO_TYPE_VALUETYPE:
2351                         if (simple_type->data.klass->enumtype) {
2352                                 simple_type = mono_class_enum_basetype (simple_type->data.klass);
2353                                 goto handle_enum;
2354                         }
2355                         if (args [i]->type != STACK_VTYPE)
2356                                 return 1;
2357                         continue;
2358                 case MONO_TYPE_TYPEDBYREF:
2359                         if (args [i]->type != STACK_VTYPE)
2360                                 return 1;
2361                         continue;
2362                 case MONO_TYPE_GENERICINST:
2363                         simple_type = &simple_type->data.generic_class->container_class->byval_arg;
2364                         goto handle_enum;
2365                 case MONO_TYPE_VAR:
2366                 case MONO_TYPE_MVAR:
2367                         /* gsharedvt */
2368                         if (args [i]->type != STACK_VTYPE)
2369                                 return 1;
2370                         continue;
2371                 default:
2372                         g_error ("unknown type 0x%02x in check_call_signature",
2373                                  simple_type->type);
2374                 }
2375         }
2376         return 0;
2377 }
2378
2379 static int
2380 callvirt_to_call (int opcode)
2381 {
2382         switch (opcode) {
2383         case OP_CALL_MEMBASE:
2384                 return OP_CALL;
2385         case OP_VOIDCALL_MEMBASE:
2386                 return OP_VOIDCALL;
2387         case OP_FCALL_MEMBASE:
2388                 return OP_FCALL;
2389         case OP_RCALL_MEMBASE:
2390                 return OP_RCALL;
2391         case OP_VCALL_MEMBASE:
2392                 return OP_VCALL;
2393         case OP_LCALL_MEMBASE:
2394                 return OP_LCALL;
2395         default:
2396                 g_assert_not_reached ();
2397         }
2398
2399         return -1;
2400 }
2401
2402 static int
2403 callvirt_to_call_reg (int opcode)
2404 {
2405         switch (opcode) {
2406         case OP_CALL_MEMBASE:
2407                 return OP_CALL_REG;
2408         case OP_VOIDCALL_MEMBASE:
2409                 return OP_VOIDCALL_REG;
2410         case OP_FCALL_MEMBASE:
2411                 return OP_FCALL_REG;
2412         case OP_RCALL_MEMBASE:
2413                 return OP_RCALL_REG;
2414         case OP_VCALL_MEMBASE:
2415                 return OP_VCALL_REG;
2416         case OP_LCALL_MEMBASE:
2417                 return OP_LCALL_REG;
2418         default:
2419                 g_assert_not_reached ();
2420         }
2421
2422         return -1;
2423 }
2424
2425 /* Either METHOD or IMT_ARG needs to be set */
2426 static void
2427 emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoMethod *method, MonoInst *imt_arg)
2428 {
2429         int method_reg;
2430
2431         if (COMPILE_LLVM (cfg)) {
2432                 method_reg = alloc_preg (cfg);
2433
2434                 if (imt_arg) {
2435                         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2436                 } else if (cfg->compile_aot) {
2437                         MONO_EMIT_NEW_AOTCONST (cfg, method_reg, method, MONO_PATCH_INFO_METHODCONST);
2438                 } else {
2439                         MonoInst *ins;
2440                         MONO_INST_NEW (cfg, ins, OP_PCONST);
2441                         ins->inst_p0 = method;
2442                         ins->dreg = method_reg;
2443                         MONO_ADD_INS (cfg->cbb, ins);
2444                 }
2445
2446 #ifdef ENABLE_LLVM
2447                 call->imt_arg_reg = method_reg;
2448 #endif
2449                 mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2450                 return;
2451         }
2452
2453         method_reg = alloc_preg (cfg);
2454
2455         if (imt_arg) {
2456                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2457         } else if (cfg->compile_aot) {
2458                 MONO_EMIT_NEW_AOTCONST (cfg, method_reg, method, MONO_PATCH_INFO_METHODCONST);
2459         } else {
2460                 MonoInst *ins;
2461                 MONO_INST_NEW (cfg, ins, OP_PCONST);
2462                 ins->inst_p0 = method;
2463                 ins->dreg = method_reg;
2464                 MONO_ADD_INS (cfg->cbb, ins);
2465         }
2466
2467         mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2468 }
2469
2470 static MonoJumpInfo *
2471 mono_patch_info_new (MonoMemPool *mp, int ip, MonoJumpInfoType type, gconstpointer target)
2472 {
2473         MonoJumpInfo *ji = mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
2474
2475         ji->ip.i = ip;
2476         ji->type = type;
2477         ji->data.target = target;
2478
2479         return ji;
2480 }
2481
2482 static int
2483 mini_class_check_context_used (MonoCompile *cfg, MonoClass *klass)
2484 {
2485         if (cfg->gshared)
2486                 return mono_class_check_context_used (klass);
2487         else
2488                 return 0;
2489 }
2490
2491 static int
2492 mini_method_check_context_used (MonoCompile *cfg, MonoMethod *method)
2493 {
2494         if (cfg->gshared)
2495                 return mono_method_check_context_used (method);
2496         else
2497                 return 0;
2498 }
2499
2500 /*
2501  * check_method_sharing:
2502  *
2503  *   Check whenever the vtable or an mrgctx needs to be passed when calling CMETHOD.
2504  */
2505 static void
2506 check_method_sharing (MonoCompile *cfg, MonoMethod *cmethod, gboolean *out_pass_vtable, gboolean *out_pass_mrgctx)
2507 {
2508         gboolean pass_vtable = FALSE;
2509         gboolean pass_mrgctx = FALSE;
2510
2511         if (((cmethod->flags & METHOD_ATTRIBUTE_STATIC) || cmethod->klass->valuetype) &&
2512                 (cmethod->klass->generic_class || cmethod->klass->generic_container)) {
2513                 gboolean sharable = FALSE;
2514
2515                 if (mono_method_is_generic_sharable_full (cmethod, TRUE, TRUE, TRUE))
2516                         sharable = TRUE;
2517
2518                 /*
2519                  * Pass vtable iff target method might
2520                  * be shared, which means that sharing
2521                  * is enabled for its class and its
2522                  * context is sharable (and it's not a
2523                  * generic method).
2524                  */
2525                 if (sharable && !(mini_method_get_context (cmethod) && mini_method_get_context (cmethod)->method_inst))
2526                         pass_vtable = TRUE;
2527         }
2528
2529         if (mini_method_get_context (cmethod) &&
2530                 mini_method_get_context (cmethod)->method_inst) {
2531                 g_assert (!pass_vtable);
2532
2533                 if (mono_method_is_generic_sharable_full (cmethod, TRUE, TRUE, TRUE)) {
2534                         pass_mrgctx = TRUE;
2535                 } else {
2536                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (mono_method_signature (cmethod)))
2537                                 pass_mrgctx = TRUE;
2538                 }
2539         }
2540
2541         if (out_pass_vtable)
2542                 *out_pass_vtable = pass_vtable;
2543         if (out_pass_mrgctx)
2544                 *out_pass_mrgctx = pass_mrgctx;
2545 }
2546
2547 inline static MonoCallInst *
2548 mono_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig, 
2549                                          MonoInst **args, int calli, int virtual, int tail, int rgctx, int unbox_trampoline)
2550 {
2551         MonoType *sig_ret;
2552         MonoCallInst *call;
2553 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2554         int i;
2555 #endif
2556
2557         if (cfg->llvm_only)
2558                 tail = FALSE;
2559
2560         if (tail) {
2561                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
2562
2563                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
2564         } else
2565                 MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (cfg, sig->ret, calli, virtual));
2566
2567         call->args = args;
2568         call->signature = sig;
2569         call->rgctx_reg = rgctx;
2570         sig_ret = mini_get_underlying_type (sig->ret);
2571
2572         type_to_eval_stack_type ((cfg), sig_ret, &call->inst);
2573
2574         if (tail) {
2575                 if (mini_type_is_vtype (sig_ret)) {
2576                         call->vret_var = cfg->vret_addr;
2577                         //g_assert_not_reached ();
2578                 }
2579         } else if (mini_type_is_vtype (sig_ret)) {
2580                 MonoInst *temp = mono_compile_create_var (cfg, sig_ret, OP_LOCAL);
2581                 MonoInst *loada;
2582
2583                 temp->backend.is_pinvoke = sig->pinvoke;
2584
2585                 /*
2586                  * We use a new opcode OP_OUTARG_VTRETADDR instead of LDADDR for emitting the
2587                  * address of return value to increase optimization opportunities.
2588                  * Before vtype decomposition, the dreg of the call ins itself represents the
2589                  * fact the call modifies the return value. After decomposition, the call will
2590                  * be transformed into one of the OP_VOIDCALL opcodes, and the VTRETADDR opcode
2591                  * will be transformed into an LDADDR.
2592                  */
2593                 MONO_INST_NEW (cfg, loada, OP_OUTARG_VTRETADDR);
2594                 loada->dreg = alloc_preg (cfg);
2595                 loada->inst_p0 = temp;
2596                 /* We reference the call too since call->dreg could change during optimization */
2597                 loada->inst_p1 = call;
2598                 MONO_ADD_INS (cfg->cbb, loada);
2599
2600                 call->inst.dreg = temp->dreg;
2601
2602                 call->vret_var = loada;
2603         } else if (!MONO_TYPE_IS_VOID (sig_ret))
2604                 call->inst.dreg = alloc_dreg (cfg, call->inst.type);
2605
2606 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2607         if (COMPILE_SOFT_FLOAT (cfg)) {
2608                 /* 
2609                  * If the call has a float argument, we would need to do an r8->r4 conversion using 
2610                  * an icall, but that cannot be done during the call sequence since it would clobber
2611                  * the call registers + the stack. So we do it before emitting the call.
2612                  */
2613                 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2614                         MonoType *t;
2615                         MonoInst *in = call->args [i];
2616
2617                         if (i >= sig->hasthis)
2618                                 t = sig->params [i - sig->hasthis];
2619                         else
2620                                 t = &mono_defaults.int_class->byval_arg;
2621                         t = mono_type_get_underlying_type (t);
2622
2623                         if (!t->byref && t->type == MONO_TYPE_R4) {
2624                                 MonoInst *iargs [1];
2625                                 MonoInst *conv;
2626
2627                                 iargs [0] = in;
2628                                 conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
2629
2630                                 /* The result will be in an int vreg */
2631                                 call->args [i] = conv;
2632                         }
2633                 }
2634         }
2635 #endif
2636
2637         call->need_unbox_trampoline = unbox_trampoline;
2638
2639 #ifdef ENABLE_LLVM
2640         if (COMPILE_LLVM (cfg))
2641                 mono_llvm_emit_call (cfg, call);
2642         else
2643                 mono_arch_emit_call (cfg, call);
2644 #else
2645         mono_arch_emit_call (cfg, call);
2646 #endif
2647
2648         cfg->param_area = MAX (cfg->param_area, call->stack_usage);
2649         cfg->flags |= MONO_CFG_HAS_CALLS;
2650         
2651         return call;
2652 }
2653
2654 static void
2655 set_rgctx_arg (MonoCompile *cfg, MonoCallInst *call, int rgctx_reg, MonoInst *rgctx_arg)
2656 {
2657         mono_call_inst_add_outarg_reg (cfg, call, rgctx_reg, MONO_ARCH_RGCTX_REG, FALSE);
2658         cfg->uses_rgctx_reg = TRUE;
2659         call->rgctx_reg = TRUE;
2660 #ifdef ENABLE_LLVM
2661         call->rgctx_arg_reg = rgctx_reg;
2662 #endif
2663 }       
2664
2665 inline static MonoInst*
2666 mono_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr, MonoInst *imt_arg, MonoInst *rgctx_arg)
2667 {
2668         MonoCallInst *call;
2669         MonoInst *ins;
2670         int rgctx_reg = -1;
2671         gboolean check_sp = FALSE;
2672
2673         if (cfg->check_pinvoke_callconv && cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
2674                 WrapperInfo *info = mono_marshal_get_wrapper_info (cfg->method);
2675
2676                 if (info && info->subtype == WRAPPER_SUBTYPE_PINVOKE)
2677                         check_sp = TRUE;
2678         }
2679
2680         if (rgctx_arg) {
2681                 rgctx_reg = mono_alloc_preg (cfg);
2682                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2683         }
2684
2685         if (check_sp) {
2686                 if (!cfg->stack_inbalance_var)
2687                         cfg->stack_inbalance_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2688
2689                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2690                 ins->dreg = cfg->stack_inbalance_var->dreg;
2691                 MONO_ADD_INS (cfg->cbb, ins);
2692         }
2693
2694         call = mono_emit_call_args (cfg, sig, args, TRUE, FALSE, FALSE, rgctx_arg ? TRUE : FALSE, FALSE);
2695
2696         call->inst.sreg1 = addr->dreg;
2697
2698         if (imt_arg)
2699                 emit_imt_argument (cfg, call, NULL, imt_arg);
2700
2701         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2702
2703         if (check_sp) {
2704                 int sp_reg;
2705
2706                 sp_reg = mono_alloc_preg (cfg);
2707
2708                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2709                 ins->dreg = sp_reg;
2710                 MONO_ADD_INS (cfg->cbb, ins);
2711
2712                 /* Restore the stack so we don't crash when throwing the exception */
2713                 MONO_INST_NEW (cfg, ins, OP_SET_SP);
2714                 ins->sreg1 = cfg->stack_inbalance_var->dreg;
2715                 MONO_ADD_INS (cfg->cbb, ins);
2716
2717                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, cfg->stack_inbalance_var->dreg, sp_reg);
2718                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ExecutionEngineException");
2719         }
2720
2721         if (rgctx_arg)
2722                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2723
2724         return (MonoInst*)call;
2725 }
2726
2727 static MonoInst*
2728 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2729
2730 static MonoInst*
2731 emit_get_rgctx_method (MonoCompile *cfg, int context_used, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type);
2732 static MonoInst*
2733 emit_get_rgctx_klass (MonoCompile *cfg, int context_used, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2734
2735 static MonoInst*
2736 mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSignature *sig, gboolean tail,
2737                                                         MonoInst **args, MonoInst *this_ins, MonoInst *imt_arg, MonoInst *rgctx_arg)
2738 {
2739 #ifndef DISABLE_REMOTING
2740         gboolean might_be_remote = FALSE;
2741 #endif
2742         gboolean virtual = this_ins != NULL;
2743         gboolean enable_for_aot = TRUE;
2744         int context_used;
2745         MonoCallInst *call;
2746         MonoInst *call_target = NULL;
2747         int rgctx_reg = 0;
2748         gboolean need_unbox_trampoline;
2749
2750         if (!sig)
2751                 sig = mono_method_signature (method);
2752
2753         if (cfg->llvm_only && (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2754                 MonoInst *icall_args [16];
2755                 MonoInst *ins;
2756
2757                 // FIXME: Optimize this
2758
2759                 guint32 imt_slot = mono_method_get_imt_slot (method);
2760
2761                 icall_args [0] = this_ins;
2762                 EMIT_NEW_ICONST (cfg, icall_args [1], imt_slot);
2763                 if (imt_arg) {
2764                         icall_args [2] = imt_arg;
2765                 } else {
2766                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_METHODCONST, method);
2767                         icall_args [2] = ins;
2768                 }
2769                 EMIT_NEW_PCONST (cfg, icall_args [3], NULL);
2770
2771                 call_target = mono_emit_jit_icall (cfg, mono_resolve_iface_call, icall_args);
2772         }
2773
2774         if (rgctx_arg) {
2775                 rgctx_reg = mono_alloc_preg (cfg);
2776                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2777         }
2778
2779         if (method->string_ctor) {
2780                 /* Create the real signature */
2781                 /* FIXME: Cache these */
2782                 MonoMethodSignature *ctor_sig = mono_metadata_signature_dup_mempool (cfg->mempool, sig);
2783                 ctor_sig->ret = &mono_defaults.string_class->byval_arg;
2784
2785                 sig = ctor_sig;
2786         }
2787
2788         context_used = mini_method_check_context_used (cfg, method);
2789
2790 #ifndef DISABLE_REMOTING
2791         might_be_remote = this_ins && sig->hasthis &&
2792                 (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) &&
2793                 !(method->flags & METHOD_ATTRIBUTE_VIRTUAL) && (!MONO_CHECK_THIS (this_ins) || context_used);
2794
2795         if (might_be_remote && context_used) {
2796                 MonoInst *addr;
2797
2798                 g_assert (cfg->gshared);
2799
2800                 addr = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK);
2801
2802                 return mono_emit_calli (cfg, sig, args, addr, NULL, NULL);
2803         }
2804 #endif
2805
2806         if (cfg->llvm_only && !call_target && virtual && (method->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
2807                 // FIXME: Vcall optimizations below
2808                 MonoInst *icall_args [16];
2809                 MonoInst *ins;
2810
2811                 if (sig->generic_param_count) {
2812                         /*
2813                          * Generic virtual call, pass the concrete method as the imt argument.
2814                          */
2815                         imt_arg = emit_get_rgctx_method (cfg, context_used,
2816                                                                                          method, MONO_RGCTX_INFO_METHOD);
2817                 }
2818
2819                 // FIXME: Optimize this
2820
2821                 int slot = mono_method_get_vtable_index (method);
2822
2823                 icall_args [0] = this_ins;
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->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->is_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
3146         if (!cfg->gen_write_barriers)
3147                 return;
3148
3149         card_table = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
3150
3151         mono_gc_get_nursery (&nursery_shift_bits, &nursery_size);
3152
3153         if (cfg->backend->have_card_table_wb && !cfg->compile_aot && card_table && nursery_shift_bits > 0 && !COMPILE_LLVM (cfg)) {
3154                 MonoInst *wbarrier;
3155
3156                 MONO_INST_NEW (cfg, wbarrier, OP_CARD_TABLE_WBARRIER);
3157                 wbarrier->sreg1 = ptr->dreg;
3158                 wbarrier->sreg2 = value->dreg;
3159                 MONO_ADD_INS (cfg->cbb, wbarrier);
3160         } else if (card_table && !cfg->compile_aot && !mono_gc_card_table_nursery_check ()) {
3161                 int offset_reg = alloc_preg (cfg);
3162                 int card_reg  = alloc_preg (cfg);
3163                 MonoInst *ins;
3164
3165                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, offset_reg, ptr->dreg, card_table_shift_bits);
3166                 if (card_table_mask)
3167                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, offset_reg, offset_reg, card_table_mask);
3168
3169                 /*We can't use PADD_IMM since the cardtable might end up in high addresses and amd64 doesn't support
3170                  * IMM's larger than 32bits.
3171                  */
3172                 if (cfg->compile_aot) {
3173                         MONO_EMIT_NEW_AOTCONST (cfg, card_reg, NULL, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR);
3174                 } else {
3175                         MONO_INST_NEW (cfg, ins, OP_PCONST);
3176                         ins->inst_p0 = card_table;
3177                         ins->dreg = card_reg;
3178                         MONO_ADD_INS (cfg->cbb, ins);
3179                 }
3180
3181                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, offset_reg, offset_reg, card_reg);
3182                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, offset_reg, 0, 1);
3183         } else {
3184                 MonoMethod *write_barrier = mono_gc_get_write_barrier ();
3185                 mono_emit_method_call (cfg, write_barrier, &ptr, NULL);
3186         }
3187
3188         EMIT_NEW_DUMMY_USE (cfg, dummy_use, value);
3189 }
3190
3191 static gboolean
3192 mono_emit_wb_aware_memcpy (MonoCompile *cfg, MonoClass *klass, MonoInst *iargs[4], int size, int align)
3193 {
3194         int dest_ptr_reg, tmp_reg, destreg, srcreg, offset;
3195         unsigned need_wb = 0;
3196
3197         if (align == 0)
3198                 align = 4;
3199
3200         /*types with references can't have alignment smaller than sizeof(void*) */
3201         if (align < SIZEOF_VOID_P)
3202                 return FALSE;
3203
3204         /*This value cannot be bigger than 32 due to the way we calculate the required wb bitmap.*/
3205         if (size > 32 * SIZEOF_VOID_P)
3206                 return FALSE;
3207
3208         create_write_barrier_bitmap (cfg, klass, &need_wb, 0);
3209
3210         /* We don't unroll more than 5 stores to avoid code bloat. */
3211         if (size > 5 * SIZEOF_VOID_P) {
3212                 /*This is harmless and simplify mono_gc_wbarrier_value_copy_bitmap */
3213                 size += (SIZEOF_VOID_P - 1);
3214                 size &= ~(SIZEOF_VOID_P - 1);
3215
3216                 EMIT_NEW_ICONST (cfg, iargs [2], size);
3217                 EMIT_NEW_ICONST (cfg, iargs [3], need_wb);
3218                 mono_emit_jit_icall (cfg, mono_gc_wbarrier_value_copy_bitmap, iargs);
3219                 return TRUE;
3220         }
3221
3222         destreg = iargs [0]->dreg;
3223         srcreg = iargs [1]->dreg;
3224         offset = 0;
3225
3226         dest_ptr_reg = alloc_preg (cfg);
3227         tmp_reg = alloc_preg (cfg);
3228
3229         /*tmp = dreg*/
3230         EMIT_NEW_UNALU (cfg, iargs [0], OP_MOVE, dest_ptr_reg, destreg);
3231
3232         while (size >= SIZEOF_VOID_P) {
3233                 MonoInst *load_inst;
3234                 MONO_INST_NEW (cfg, load_inst, OP_LOAD_MEMBASE);
3235                 load_inst->dreg = tmp_reg;
3236                 load_inst->inst_basereg = srcreg;
3237                 load_inst->inst_offset = offset;
3238                 MONO_ADD_INS (cfg->cbb, load_inst);
3239
3240                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, dest_ptr_reg, 0, tmp_reg);
3241
3242                 if (need_wb & 0x1)
3243                         emit_write_barrier (cfg, iargs [0], load_inst);
3244
3245                 offset += SIZEOF_VOID_P;
3246                 size -= SIZEOF_VOID_P;
3247                 need_wb >>= 1;
3248
3249                 /*tmp += sizeof (void*)*/
3250                 if (size >= SIZEOF_VOID_P) {
3251                         NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, dest_ptr_reg, dest_ptr_reg, SIZEOF_VOID_P);
3252                         MONO_ADD_INS (cfg->cbb, iargs [0]);
3253                 }
3254         }
3255
3256         /* Those cannot be references since size < sizeof (void*) */
3257         while (size >= 4) {
3258                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tmp_reg, srcreg, offset);
3259                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, tmp_reg);
3260                 offset += 4;
3261                 size -= 4;
3262         }
3263
3264         while (size >= 2) {
3265                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmp_reg, srcreg, offset);
3266                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, tmp_reg);
3267                 offset += 2;
3268                 size -= 2;
3269         }
3270
3271         while (size >= 1) {
3272                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmp_reg, srcreg, offset);
3273                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, tmp_reg);
3274                 offset += 1;
3275                 size -= 1;
3276         }
3277
3278         return TRUE;
3279 }
3280
3281 /*
3282  * Emit code to copy a valuetype of type @klass whose address is stored in
3283  * @src->dreg to memory whose address is stored at @dest->dreg.
3284  */
3285 void
3286 mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native)
3287 {
3288         MonoInst *iargs [4];
3289         int n;
3290         guint32 align = 0;
3291         MonoMethod *memcpy_method;
3292         MonoInst *size_ins = NULL;
3293         MonoInst *memcpy_ins = NULL;
3294
3295         g_assert (klass);
3296         if (cfg->gshared)
3297                 klass = mono_class_from_mono_type (mini_get_underlying_type (&klass->byval_arg));
3298
3299         /*
3300          * This check breaks with spilled vars... need to handle it during verification anyway.
3301          * g_assert (klass && klass == src->klass && klass == dest->klass);
3302          */
3303
3304         if (mini_is_gsharedvt_klass (klass)) {
3305                 g_assert (!native);
3306                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3307                 memcpy_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_MEMCPY);
3308         }
3309
3310         if (native)
3311                 n = mono_class_native_size (klass, &align);
3312         else
3313                 n = mono_class_value_size (klass, &align);
3314
3315         /* if native is true there should be no references in the struct */
3316         if (cfg->gen_write_barriers && (klass->has_references || size_ins) && !native) {
3317                 /* Avoid barriers when storing to the stack */
3318                 if (!((dest->opcode == OP_ADD_IMM && dest->sreg1 == cfg->frame_reg) ||
3319                           (dest->opcode == OP_LDADDR))) {
3320                         int context_used;
3321
3322                         iargs [0] = dest;
3323                         iargs [1] = src;
3324
3325                         context_used = mini_class_check_context_used (cfg, klass);
3326
3327                         /* It's ok to intrinsify under gsharing since shared code types are layout stable. */
3328                         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && mono_emit_wb_aware_memcpy (cfg, klass, iargs, n, align)) {
3329                                 return;
3330                         } else if (context_used) {
3331                                 iargs [2] = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3332                         }  else {
3333                                 if (cfg->compile_aot) {
3334                                         EMIT_NEW_CLASSCONST (cfg, iargs [2], klass);
3335                                 } else {
3336                                         EMIT_NEW_PCONST (cfg, iargs [2], klass);
3337                                         mono_class_compute_gc_descriptor (klass);
3338                                 }
3339                         }
3340
3341                         if (size_ins)
3342                                 mono_emit_jit_icall (cfg, mono_gsharedvt_value_copy, iargs);
3343                         else
3344                                 mono_emit_jit_icall (cfg, mono_value_copy, iargs);
3345                         return;
3346                 }
3347         }
3348
3349         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 8) {
3350                 /* FIXME: Optimize the case when src/dest is OP_LDADDR */
3351                 mini_emit_memcpy (cfg, dest->dreg, 0, src->dreg, 0, n, align);
3352         } else {
3353                 iargs [0] = dest;
3354                 iargs [1] = src;
3355                 if (size_ins)
3356                         iargs [2] = size_ins;
3357                 else
3358                         EMIT_NEW_ICONST (cfg, iargs [2], n);
3359                 
3360                 memcpy_method = get_memcpy_method ();
3361                 if (memcpy_ins)
3362                         mono_emit_calli (cfg, mono_method_signature (memcpy_method), iargs, memcpy_ins, NULL, NULL);
3363                 else
3364                         mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
3365         }
3366 }
3367
3368 static MonoMethod*
3369 get_memset_method (void)
3370 {
3371         static MonoMethod *memset_method = NULL;
3372         if (!memset_method) {
3373                 memset_method = mono_class_get_method_from_name (mono_defaults.string_class, "memset", 3);
3374                 if (!memset_method)
3375                         g_error ("Old corlib found. Install a new one");
3376         }
3377         return memset_method;
3378 }
3379
3380 void
3381 mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass)
3382 {
3383         MonoInst *iargs [3];
3384         int n;
3385         guint32 align;
3386         MonoMethod *memset_method;
3387         MonoInst *size_ins = NULL;
3388         MonoInst *bzero_ins = NULL;
3389         static MonoMethod *bzero_method;
3390
3391         /* FIXME: Optimize this for the case when dest is an LDADDR */
3392         mono_class_init (klass);
3393         if (mini_is_gsharedvt_klass (klass)) {
3394                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3395                 bzero_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_BZERO);
3396                 if (!bzero_method)
3397                         bzero_method = mono_class_get_method_from_name (mono_defaults.string_class, "bzero_aligned_1", 2);
3398                 g_assert (bzero_method);
3399                 iargs [0] = dest;
3400                 iargs [1] = size_ins;
3401                 mono_emit_calli (cfg, mono_method_signature (bzero_method), iargs, bzero_ins, NULL, NULL);
3402                 return;
3403         }
3404
3405         n = mono_class_value_size (klass, &align);
3406
3407         if (n <= sizeof (gpointer) * 8) {
3408                 mini_emit_memset (cfg, dest->dreg, 0, n, 0, align);
3409         }
3410         else {
3411                 memset_method = get_memset_method ();
3412                 iargs [0] = dest;
3413                 EMIT_NEW_ICONST (cfg, iargs [1], 0);
3414                 EMIT_NEW_ICONST (cfg, iargs [2], n);
3415                 mono_emit_method_call (cfg, memset_method, iargs, NULL);
3416         }
3417 }
3418
3419 /*
3420  * emit_get_rgctx:
3421  *
3422  *   Emit IR to return either the this pointer for instance method,
3423  * or the mrgctx for static methods.
3424  */
3425 static MonoInst*
3426 emit_get_rgctx (MonoCompile *cfg, MonoMethod *method, int context_used)
3427 {
3428         MonoInst *this_ins = NULL;
3429
3430         g_assert (cfg->gshared);
3431
3432         if (!(method->flags & METHOD_ATTRIBUTE_STATIC) &&
3433                         !(context_used & MONO_GENERIC_CONTEXT_USED_METHOD) &&
3434                         !method->klass->valuetype)
3435                 EMIT_NEW_ARGLOAD (cfg, this_ins, 0);
3436
3437         if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD) {
3438                 MonoInst *mrgctx_loc, *mrgctx_var;
3439
3440                 g_assert (!this_ins);
3441                 g_assert (method->is_inflated && mono_method_get_context (method)->method_inst);
3442
3443                 mrgctx_loc = mono_get_vtable_var (cfg);
3444                 EMIT_NEW_TEMPLOAD (cfg, mrgctx_var, mrgctx_loc->inst_c0);
3445
3446                 return mrgctx_var;
3447         } else if (method->flags & METHOD_ATTRIBUTE_STATIC || method->klass->valuetype) {
3448                 MonoInst *vtable_loc, *vtable_var;
3449
3450                 g_assert (!this_ins);
3451
3452                 vtable_loc = mono_get_vtable_var (cfg);
3453                 EMIT_NEW_TEMPLOAD (cfg, vtable_var, vtable_loc->inst_c0);
3454
3455                 if (method->is_inflated && mono_method_get_context (method)->method_inst) {
3456                         MonoInst *mrgctx_var = vtable_var;
3457                         int vtable_reg;
3458
3459                         vtable_reg = alloc_preg (cfg);
3460                         EMIT_NEW_LOAD_MEMBASE (cfg, vtable_var, OP_LOAD_MEMBASE, vtable_reg, mrgctx_var->dreg, MONO_STRUCT_OFFSET (MonoMethodRuntimeGenericContext, class_vtable));
3461                         vtable_var->type = STACK_PTR;
3462                 }
3463
3464                 return vtable_var;
3465         } else {
3466                 MonoInst *ins;
3467                 int vtable_reg;
3468         
3469                 vtable_reg = alloc_preg (cfg);
3470                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, vtable_reg, this_ins->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3471                 return ins;
3472         }
3473 }
3474
3475 static MonoJumpInfoRgctxEntry *
3476 mono_patch_info_rgctx_entry_new (MonoMemPool *mp, MonoMethod *method, gboolean in_mrgctx, MonoJumpInfoType patch_type, gconstpointer patch_data, MonoRgctxInfoType info_type)
3477 {
3478         MonoJumpInfoRgctxEntry *res = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoRgctxEntry));
3479         res->method = method;
3480         res->in_mrgctx = in_mrgctx;
3481         res->data = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo));
3482         res->data->type = patch_type;
3483         res->data->data.target = patch_data;
3484         res->info_type = info_type;
3485
3486         return res;
3487 }
3488
3489 static inline MonoInst*
3490 emit_rgctx_fetch_inline (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
3491 {
3492         MonoInst *args [16];
3493         MonoInst *call;
3494
3495         // FIXME: No fastpath since the slot is not a compile time constant
3496         args [0] = rgctx;
3497         EMIT_NEW_AOTCONST (cfg, args [1], MONO_PATCH_INFO_RGCTX_SLOT_INDEX, entry);
3498         if (entry->in_mrgctx)
3499                 call = mono_emit_jit_icall (cfg, mono_fill_method_rgctx, args);
3500         else
3501                 call = mono_emit_jit_icall (cfg, mono_fill_class_rgctx, args);
3502         return call;
3503 #if 0
3504         /*
3505          * FIXME: This can be called during decompose, which is a problem since it creates
3506          * new bblocks.
3507          * Also, the fastpath doesn't work since the slot number is dynamically allocated.
3508          */
3509         int i, slot, depth, index, rgctx_reg, val_reg, res_reg;
3510         gboolean mrgctx;
3511         MonoBasicBlock *is_null_bb, *end_bb;
3512         MonoInst *res, *ins, *call;
3513         MonoInst *args[16];
3514
3515         slot = mini_get_rgctx_entry_slot (entry);
3516
3517         mrgctx = MONO_RGCTX_SLOT_IS_MRGCTX (slot);
3518         index = MONO_RGCTX_SLOT_INDEX (slot);
3519         if (mrgctx)
3520                 index += MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
3521         for (depth = 0; ; ++depth) {
3522                 int size = mono_class_rgctx_get_array_size (depth, mrgctx);
3523
3524                 if (index < size - 1)
3525                         break;
3526                 index -= size - 1;
3527         }
3528
3529         NEW_BBLOCK (cfg, end_bb);
3530         NEW_BBLOCK (cfg, is_null_bb);
3531
3532         if (mrgctx) {
3533                 rgctx_reg = rgctx->dreg;
3534         } else {
3535                 rgctx_reg = alloc_preg (cfg);
3536
3537                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, rgctx_reg, rgctx->dreg, MONO_STRUCT_OFFSET (MonoVTable, runtime_generic_context));
3538                 // FIXME: Avoid this check by allocating the table when the vtable is created etc.
3539                 NEW_BBLOCK (cfg, is_null_bb);
3540
3541                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rgctx_reg, 0);
3542                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3543         }
3544
3545         for (i = 0; i < depth; ++i) {
3546                 int array_reg = alloc_preg (cfg);
3547
3548                 /* load ptr to next array */
3549                 if (mrgctx && i == 0)
3550                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, rgctx_reg, MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT);
3551                 else
3552                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, rgctx_reg, 0);
3553                 rgctx_reg = array_reg;
3554                 /* is the ptr null? */
3555                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rgctx_reg, 0);
3556                 /* if yes, jump to actual trampoline */
3557                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3558         }
3559
3560         /* fetch slot */
3561         val_reg = alloc_preg (cfg);
3562         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, val_reg, rgctx_reg, (index + 1) * sizeof (gpointer));
3563         /* is the slot null? */
3564         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, val_reg, 0);
3565         /* if yes, jump to actual trampoline */
3566         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3567
3568         /* Fastpath */
3569         res_reg = alloc_preg (cfg);
3570         MONO_INST_NEW (cfg, ins, OP_MOVE);
3571         ins->dreg = res_reg;
3572         ins->sreg1 = val_reg;
3573         MONO_ADD_INS (cfg->cbb, ins);
3574         res = ins;
3575         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3576
3577         /* Slowpath */
3578         MONO_START_BB (cfg, is_null_bb);
3579         args [0] = rgctx;
3580         EMIT_NEW_ICONST (cfg, args [1], index);
3581         if (mrgctx)
3582                 call = mono_emit_jit_icall (cfg, mono_fill_method_rgctx, args);
3583         else
3584                 call = mono_emit_jit_icall (cfg, mono_fill_class_rgctx, args);
3585         MONO_INST_NEW (cfg, ins, OP_MOVE);
3586         ins->dreg = res_reg;
3587         ins->sreg1 = call->dreg;
3588         MONO_ADD_INS (cfg->cbb, ins);
3589         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3590
3591         MONO_START_BB (cfg, end_bb);
3592
3593         return res;
3594 #endif
3595 }
3596
3597 /*
3598  * emit_rgctx_fetch:
3599  *
3600  *   Emit IR to load the value of the rgctx entry ENTRY from the rgctx
3601  * given by RGCTX.
3602  */
3603 static inline MonoInst*
3604 emit_rgctx_fetch (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
3605 {
3606         if (cfg->llvm_only)
3607                 return emit_rgctx_fetch_inline (cfg, rgctx, entry);
3608         else
3609                 return mono_emit_abs_call (cfg, MONO_PATCH_INFO_RGCTX_FETCH, entry, helper_sig_rgctx_lazy_fetch_trampoline, &rgctx);
3610 }
3611
3612 static MonoInst*
3613 emit_get_rgctx_klass (MonoCompile *cfg, int context_used,
3614                                           MonoClass *klass, MonoRgctxInfoType rgctx_type)
3615 {
3616         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);
3617         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3618
3619         return emit_rgctx_fetch (cfg, rgctx, entry);
3620 }
3621
3622 static MonoInst*
3623 emit_get_rgctx_sig (MonoCompile *cfg, int context_used,
3624                                         MonoMethodSignature *sig, MonoRgctxInfoType rgctx_type)
3625 {
3626         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);
3627         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3628
3629         return emit_rgctx_fetch (cfg, rgctx, entry);
3630 }
3631
3632 static MonoInst*
3633 emit_get_rgctx_gsharedvt_call (MonoCompile *cfg, int context_used,
3634                                                            MonoMethodSignature *sig, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3635 {
3636         MonoJumpInfoGSharedVtCall *call_info;
3637         MonoJumpInfoRgctxEntry *entry;
3638         MonoInst *rgctx;
3639
3640         call_info = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoGSharedVtCall));
3641         call_info->sig = sig;
3642         call_info->method = cmethod;
3643
3644         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);
3645         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3646
3647         return emit_rgctx_fetch (cfg, rgctx, entry);
3648 }
3649
3650 /*
3651  * emit_get_rgctx_virt_method:
3652  *
3653  *   Return data for method VIRT_METHOD for a receiver of type KLASS.
3654  */
3655 static MonoInst*
3656 emit_get_rgctx_virt_method (MonoCompile *cfg, int context_used,
3657                                                         MonoClass *klass, MonoMethod *virt_method, MonoRgctxInfoType rgctx_type)
3658 {
3659         MonoJumpInfoVirtMethod *info;
3660         MonoJumpInfoRgctxEntry *entry;
3661         MonoInst *rgctx;
3662
3663         info = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoVirtMethod));
3664         info->klass = klass;
3665         info->method = virt_method;
3666
3667         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);
3668         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3669
3670         return emit_rgctx_fetch (cfg, rgctx, entry);
3671 }
3672
3673 static MonoInst*
3674 emit_get_rgctx_gsharedvt_method (MonoCompile *cfg, int context_used,
3675                                                                  MonoMethod *cmethod, MonoGSharedVtMethodInfo *info)
3676 {
3677         MonoJumpInfoRgctxEntry *entry;
3678         MonoInst *rgctx;
3679
3680         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);
3681         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3682
3683         return emit_rgctx_fetch (cfg, rgctx, entry);
3684 }
3685
3686 /*
3687  * emit_get_rgctx_method:
3688  *
3689  *   Emit IR to load the property RGCTX_TYPE of CMETHOD. If context_used is 0, emit
3690  * normal constants, else emit a load from the rgctx.
3691  */
3692 static MonoInst*
3693 emit_get_rgctx_method (MonoCompile *cfg, int context_used,
3694                                            MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3695 {
3696         if (!context_used) {
3697                 MonoInst *ins;
3698
3699                 switch (rgctx_type) {
3700                 case MONO_RGCTX_INFO_METHOD:
3701                         EMIT_NEW_METHODCONST (cfg, ins, cmethod);
3702                         return ins;
3703                 case MONO_RGCTX_INFO_METHOD_RGCTX:
3704                         EMIT_NEW_METHOD_RGCTX_CONST (cfg, ins, cmethod);
3705                         return ins;
3706                 default:
3707                         g_assert_not_reached ();
3708                 }
3709         } else {
3710                 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);
3711                 MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3712
3713                 return emit_rgctx_fetch (cfg, rgctx, entry);
3714         }
3715 }
3716
3717 static MonoInst*
3718 emit_get_rgctx_field (MonoCompile *cfg, int context_used,
3719                                           MonoClassField *field, MonoRgctxInfoType rgctx_type)
3720 {
3721         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);
3722         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3723
3724         return emit_rgctx_fetch (cfg, rgctx, entry);
3725 }
3726
3727 static int
3728 get_gsharedvt_info_slot (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3729 {
3730         MonoGSharedVtMethodInfo *info = cfg->gsharedvt_info;
3731         MonoRuntimeGenericContextInfoTemplate *template;
3732         int i, idx;
3733
3734         g_assert (info);
3735
3736         for (i = 0; i < info->num_entries; ++i) {
3737                 MonoRuntimeGenericContextInfoTemplate *otemplate = &info->entries [i];
3738
3739                 if (otemplate->info_type == rgctx_type && otemplate->data == data && rgctx_type != MONO_RGCTX_INFO_LOCAL_OFFSET)
3740                         return i;
3741         }
3742
3743         if (info->num_entries == info->count_entries) {
3744                 MonoRuntimeGenericContextInfoTemplate *new_entries;
3745                 int new_count_entries = info->count_entries ? info->count_entries * 2 : 16;
3746
3747                 new_entries = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * new_count_entries);
3748
3749                 memcpy (new_entries, info->entries, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
3750                 info->entries = new_entries;
3751                 info->count_entries = new_count_entries;
3752         }
3753
3754         idx = info->num_entries;
3755         template = &info->entries [idx];
3756         template->info_type = rgctx_type;
3757         template->data = data;
3758
3759         info->num_entries ++;
3760
3761         return idx;
3762 }
3763
3764 /*
3765  * emit_get_gsharedvt_info:
3766  *
3767  *   This is similar to emit_get_rgctx_.., but loads the data from the gsharedvt info var instead of calling an rgctx fetch trampoline.
3768  */
3769 static MonoInst*
3770 emit_get_gsharedvt_info (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3771 {
3772         MonoInst *ins;
3773         int idx, dreg;
3774
3775         idx = get_gsharedvt_info_slot (cfg, data, rgctx_type);
3776         /* Load info->entries [idx] */
3777         dreg = alloc_preg (cfg);
3778         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, cfg->gsharedvt_info_var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
3779
3780         return ins;
3781 }
3782
3783 static MonoInst*
3784 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type)
3785 {
3786         return emit_get_gsharedvt_info (cfg, &klass->byval_arg, rgctx_type);
3787 }
3788
3789 /*
3790  * On return the caller must check @klass for load errors.
3791  */
3792 static void
3793 emit_class_init (MonoCompile *cfg, MonoClass *klass)
3794 {
3795         MonoInst *vtable_arg;
3796         int context_used;
3797
3798         context_used = mini_class_check_context_used (cfg, klass);
3799
3800         if (context_used) {
3801                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
3802                                                                                    klass, MONO_RGCTX_INFO_VTABLE);
3803         } else {
3804                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
3805
3806                 if (!vtable)
3807                         return;
3808                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
3809         }
3810
3811         if (!COMPILE_LLVM (cfg) && cfg->backend->have_op_generic_class_init) {
3812                 MonoInst *ins;
3813
3814                 /*
3815                  * Using an opcode instead of emitting IR here allows the hiding of the call inside the opcode,
3816                  * so this doesn't have to clobber any regs and it doesn't break basic blocks.
3817                  */
3818                 MONO_INST_NEW (cfg, ins, OP_GENERIC_CLASS_INIT);
3819                 ins->sreg1 = vtable_arg->dreg;
3820                 MONO_ADD_INS (cfg->cbb, ins);
3821         } else {
3822                 static int byte_offset = -1;
3823                 static guint8 bitmask;
3824                 int bits_reg, inited_reg;
3825                 MonoBasicBlock *inited_bb;
3826                 MonoInst *args [16];
3827
3828                 if (byte_offset < 0)
3829                         mono_marshal_find_bitfield_offset (MonoVTable, initialized, &byte_offset, &bitmask);
3830
3831                 bits_reg = alloc_ireg (cfg);
3832                 inited_reg = alloc_ireg (cfg);
3833
3834                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, bits_reg, vtable_arg->dreg, byte_offset);
3835                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, inited_reg, bits_reg, bitmask);
3836
3837                 NEW_BBLOCK (cfg, inited_bb);
3838
3839                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, inited_reg, 0);
3840                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, inited_bb);
3841
3842                 args [0] = vtable_arg;
3843                 mono_emit_jit_icall (cfg, mono_generic_class_init, args);
3844
3845                 MONO_START_BB (cfg, inited_bb);
3846         }
3847 }
3848
3849 static void
3850 emit_seq_point (MonoCompile *cfg, MonoMethod *method, guint8* ip, gboolean intr_loc, gboolean nonempty_stack)
3851 {
3852         MonoInst *ins;
3853
3854         if (cfg->gen_seq_points && cfg->method == method) {
3855                 NEW_SEQ_POINT (cfg, ins, ip - cfg->header->code, intr_loc);
3856                 if (nonempty_stack)
3857                         ins->flags |= MONO_INST_NONEMPTY_STACK;
3858                 MONO_ADD_INS (cfg->cbb, ins);
3859         }
3860 }
3861
3862 static void
3863 save_cast_details (MonoCompile *cfg, MonoClass *klass, int obj_reg, gboolean null_check)
3864 {
3865         if (mini_get_debug_options ()->better_cast_details) {
3866                 int vtable_reg = alloc_preg (cfg);
3867                 int klass_reg = alloc_preg (cfg);
3868                 MonoBasicBlock *is_null_bb = NULL;
3869                 MonoInst *tls_get;
3870                 int to_klass_reg, context_used;
3871
3872                 if (null_check) {
3873                         NEW_BBLOCK (cfg, is_null_bb);
3874
3875                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
3876                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3877                 }
3878
3879                 tls_get = mono_get_jit_tls_intrinsic (cfg);
3880                 if (!tls_get) {
3881                         fprintf (stderr, "error: --debug=casts not supported on this platform.\n.");
3882                         exit (1);
3883                 }
3884
3885                 MONO_ADD_INS (cfg->cbb, tls_get);
3886                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3887                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3888
3889                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), klass_reg);
3890
3891                 context_used = mini_class_check_context_used (cfg, klass);
3892                 if (context_used) {
3893                         MonoInst *class_ins;
3894
3895                         class_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3896                         to_klass_reg = class_ins->dreg;
3897                 } else {
3898                         to_klass_reg = alloc_preg (cfg);
3899                         MONO_EMIT_NEW_CLASSCONST (cfg, to_klass_reg, klass);
3900                 }
3901                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_to), to_klass_reg);
3902
3903                 if (null_check)
3904                         MONO_START_BB (cfg, is_null_bb);
3905         }
3906 }
3907
3908 static void
3909 reset_cast_details (MonoCompile *cfg)
3910 {
3911         /* Reset the variables holding the cast details */
3912         if (mini_get_debug_options ()->better_cast_details) {
3913                 MonoInst *tls_get = mono_get_jit_tls_intrinsic (cfg);
3914
3915                 MONO_ADD_INS (cfg->cbb, tls_get);
3916                 /* It is enough to reset the from field */
3917                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), 0);
3918         }
3919 }
3920
3921 /*
3922  * On return the caller must check @array_class for load errors
3923  */
3924 static void
3925 mini_emit_check_array_type (MonoCompile *cfg, MonoInst *obj, MonoClass *array_class)
3926 {
3927         int vtable_reg = alloc_preg (cfg);
3928         int context_used;
3929
3930         context_used = mini_class_check_context_used (cfg, array_class);
3931
3932         save_cast_details (cfg, array_class, obj->dreg, FALSE);
3933
3934         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3935
3936         if (cfg->opt & MONO_OPT_SHARED) {
3937                 int class_reg = alloc_preg (cfg);
3938                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, class_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3939                 if (cfg->compile_aot) {
3940                         int klass_reg = alloc_preg (cfg);
3941                         MONO_EMIT_NEW_CLASSCONST (cfg, klass_reg, array_class);
3942                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, class_reg, klass_reg);
3943                 } else {
3944                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, class_reg, array_class);
3945                 }
3946         } else if (context_used) {
3947                 MonoInst *vtable_ins;
3948
3949                 vtable_ins = emit_get_rgctx_klass (cfg, context_used, array_class, MONO_RGCTX_INFO_VTABLE);
3950                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vtable_ins->dreg);
3951         } else {
3952                 if (cfg->compile_aot) {
3953                         int vt_reg;
3954                         MonoVTable *vtable;
3955
3956                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3957                                 return;
3958                         vt_reg = alloc_preg (cfg);
3959                         MONO_EMIT_NEW_VTABLECONST (cfg, vt_reg, vtable);
3960                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vt_reg);
3961                 } else {
3962                         MonoVTable *vtable;
3963                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3964                                 return;
3965                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vtable);
3966                 }
3967         }
3968         
3969         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ArrayTypeMismatchException");
3970
3971         reset_cast_details (cfg);
3972 }
3973
3974 /**
3975  * Handles unbox of a Nullable<T>. If context_used is non zero, then shared 
3976  * generic code is generated.
3977  */
3978 static MonoInst*
3979 handle_unbox_nullable (MonoCompile* cfg, MonoInst* val, MonoClass* klass, int context_used)
3980 {
3981         MonoMethod* method = mono_class_get_method_from_name (klass, "Unbox", 1);
3982
3983         if (context_used) {
3984                 MonoInst *rgctx, *addr;
3985
3986                 /* FIXME: What if the class is shared?  We might not
3987                    have to get the address of the method from the
3988                    RGCTX. */
3989                 addr = emit_get_rgctx_method (cfg, context_used, method,
3990                                                                           MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
3991
3992                 rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3993
3994                 return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
3995         } else {
3996                 gboolean pass_vtable, pass_mrgctx;
3997                 MonoInst *rgctx_arg = NULL;
3998
3999                 check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
4000                 g_assert (!pass_mrgctx);
4001
4002                 if (pass_vtable) {
4003                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
4004
4005                         g_assert (vtable);
4006                         EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
4007                 }
4008
4009                 return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
4010         }
4011 }
4012
4013 static MonoInst*
4014 handle_unbox (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, int context_used)
4015 {
4016         MonoInst *add;
4017         int obj_reg;
4018         int vtable_reg = alloc_dreg (cfg ,STACK_PTR);
4019         int klass_reg = alloc_dreg (cfg ,STACK_PTR);
4020         int eclass_reg = alloc_dreg (cfg ,STACK_PTR);
4021         int rank_reg = alloc_dreg (cfg ,STACK_I4);
4022
4023         obj_reg = sp [0]->dreg;
4024         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4025         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
4026
4027         /* FIXME: generics */
4028         g_assert (klass->rank == 0);
4029                         
4030         // Check rank == 0
4031         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, 0);
4032         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4033
4034         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4035         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, element_class));
4036
4037         if (context_used) {
4038                 MonoInst *element_class;
4039
4040                 /* This assertion is from the unboxcast insn */
4041                 g_assert (klass->rank == 0);
4042
4043                 element_class = emit_get_rgctx_klass (cfg, context_used,
4044                                 klass, MONO_RGCTX_INFO_ELEMENT_KLASS);
4045
4046                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, eclass_reg, element_class->dreg);
4047                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4048         } else {
4049                 save_cast_details (cfg, klass->element_class, obj_reg, FALSE);
4050                 mini_emit_class_check (cfg, eclass_reg, klass->element_class);
4051                 reset_cast_details (cfg);
4052         }
4053
4054         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), obj_reg, sizeof (MonoObject));
4055         MONO_ADD_INS (cfg->cbb, add);
4056         add->type = STACK_MP;
4057         add->klass = klass;
4058
4059         return add;
4060 }
4061
4062 static MonoInst*
4063 handle_unbox_gsharedvt (MonoCompile *cfg, MonoClass *klass, MonoInst *obj)
4064 {
4065         MonoInst *addr, *klass_inst, *is_ref, *args[16];
4066         MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
4067         MonoInst *ins;
4068         int dreg, addr_reg;
4069
4070         klass_inst = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_KLASS);
4071
4072         /* obj */
4073         args [0] = obj;
4074
4075         /* klass */
4076         args [1] = klass_inst;
4077
4078         /* CASTCLASS */
4079         obj = mono_emit_jit_icall (cfg, mono_object_castclass_unbox, args);
4080
4081         NEW_BBLOCK (cfg, is_ref_bb);
4082         NEW_BBLOCK (cfg, is_nullable_bb);
4083         NEW_BBLOCK (cfg, end_bb);
4084         is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
4085         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 1);
4086         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
4087
4088         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 2);
4089         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
4090
4091         /* This will contain either the address of the unboxed vtype, or an address of the temporary where the ref is stored */
4092         addr_reg = alloc_dreg (cfg, STACK_MP);
4093
4094         /* Non-ref case */
4095         /* UNBOX */
4096         NEW_BIALU_IMM (cfg, addr, OP_ADD_IMM, addr_reg, obj->dreg, sizeof (MonoObject));
4097         MONO_ADD_INS (cfg->cbb, addr);
4098
4099         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4100
4101         /* Ref case */
4102         MONO_START_BB (cfg, is_ref_bb);
4103
4104         /* Save the ref to a temporary */
4105         dreg = alloc_ireg (cfg);
4106         EMIT_NEW_VARLOADA_VREG (cfg, addr, dreg, &klass->byval_arg);
4107         addr->dreg = addr_reg;
4108         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, obj->dreg);
4109         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4110
4111         /* Nullable case */
4112         MONO_START_BB (cfg, is_nullable_bb);
4113
4114         {
4115                 MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX);
4116                 MonoInst *unbox_call;
4117                 MonoMethodSignature *unbox_sig;
4118
4119                 unbox_sig = mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
4120                 unbox_sig->ret = &klass->byval_arg;
4121                 unbox_sig->param_count = 1;
4122                 unbox_sig->params [0] = &mono_defaults.object_class->byval_arg;
4123                 unbox_call = mono_emit_calli (cfg, unbox_sig, &obj, addr, NULL, NULL);
4124
4125                 EMIT_NEW_VARLOADA_VREG (cfg, addr, unbox_call->dreg, &klass->byval_arg);
4126                 addr->dreg = addr_reg;
4127         }
4128
4129         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4130
4131         /* End */
4132         MONO_START_BB (cfg, end_bb);
4133
4134         /* LDOBJ */
4135         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr_reg, 0);
4136
4137         return ins;
4138 }
4139
4140 /*
4141  * Returns NULL and set the cfg exception on error.
4142  */
4143 static MonoInst*
4144 handle_alloc (MonoCompile *cfg, MonoClass *klass, gboolean for_box, int context_used)
4145 {
4146         MonoInst *iargs [2];
4147         void *alloc_ftn;
4148
4149         if (context_used) {
4150                 MonoInst *data;
4151                 int rgctx_info;
4152                 MonoInst *iargs [2];
4153                 gboolean known_instance_size = !mini_is_gsharedvt_klass (klass);
4154
4155                 MonoMethod *managed_alloc = mono_gc_get_managed_allocator (klass, for_box, known_instance_size);
4156
4157                 if (cfg->opt & MONO_OPT_SHARED)
4158                         rgctx_info = MONO_RGCTX_INFO_KLASS;
4159                 else
4160                         rgctx_info = MONO_RGCTX_INFO_VTABLE;
4161                 data = emit_get_rgctx_klass (cfg, context_used, klass, rgctx_info);
4162
4163                 if (cfg->opt & MONO_OPT_SHARED) {
4164                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
4165                         iargs [1] = data;
4166                         alloc_ftn = mono_object_new;
4167                 } else {
4168                         iargs [0] = data;
4169                         alloc_ftn = mono_object_new_specific;
4170                 }
4171
4172                 if (managed_alloc && !(cfg->opt & MONO_OPT_SHARED)) {
4173                         if (known_instance_size) {
4174                                 int size = mono_class_instance_size (klass);
4175                                 if (size < sizeof (MonoObject))
4176                                         g_error ("Invalid size %d for class %s", size, mono_type_get_full_name (klass));
4177
4178                                 EMIT_NEW_ICONST (cfg, iargs [1], mono_gc_get_aligned_size_for_allocator (size));
4179                         }
4180                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
4181                 }
4182
4183                 return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
4184         }
4185
4186         if (cfg->opt & MONO_OPT_SHARED) {
4187                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
4188                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
4189
4190                 alloc_ftn = mono_object_new;
4191         } else if (cfg->compile_aot && cfg->cbb->out_of_line && klass->type_token && klass->image == mono_defaults.corlib && !klass->generic_class) {
4192                 /* This happens often in argument checking code, eg. throw new FooException... */
4193                 /* Avoid relocations and save some space by calling a helper function specialized to mscorlib */
4194                 EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (klass->type_token));
4195                 return mono_emit_jit_icall (cfg, mono_helper_newobj_mscorlib, iargs);
4196         } else {
4197                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
4198                 MonoMethod *managed_alloc = NULL;
4199                 gboolean pass_lw;
4200
4201                 if (!vtable) {
4202                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4203                         cfg->exception_ptr = klass;
4204                         return NULL;
4205                 }
4206
4207                 managed_alloc = mono_gc_get_managed_allocator (klass, for_box, TRUE);
4208
4209                 if (managed_alloc) {
4210                         int size = mono_class_instance_size (klass);
4211                         if (size < sizeof (MonoObject))
4212                                 g_error ("Invalid size %d for class %s", size, mono_type_get_full_name (klass));
4213
4214                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
4215                         EMIT_NEW_ICONST (cfg, iargs [1], mono_gc_get_aligned_size_for_allocator (size));
4216                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
4217                 }
4218                 alloc_ftn = mono_class_get_allocation_ftn (vtable, for_box, &pass_lw);
4219                 if (pass_lw) {
4220                         guint32 lw = vtable->klass->instance_size;
4221                         lw = ((lw + (sizeof (gpointer) - 1)) & ~(sizeof (gpointer) - 1)) / sizeof (gpointer);
4222                         EMIT_NEW_ICONST (cfg, iargs [0], lw);
4223                         EMIT_NEW_VTABLECONST (cfg, iargs [1], vtable);
4224                 }
4225                 else {
4226                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
4227                 }
4228         }
4229
4230         return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
4231 }
4232         
4233 /*
4234  * Returns NULL and set the cfg exception on error.
4235  */     
4236 static MonoInst*
4237 handle_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_used)
4238 {
4239         MonoInst *alloc, *ins;
4240
4241         if (mono_class_is_nullable (klass)) {
4242                 MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
4243
4244                 if (context_used) {
4245                         /* FIXME: What if the class is shared?  We might not
4246                            have to get the method address from the RGCTX. */
4247                         MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
4248                                                                                                         MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
4249                         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
4250
4251                         return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
4252                 } else {
4253                         gboolean pass_vtable, pass_mrgctx;
4254                         MonoInst *rgctx_arg = NULL;
4255
4256                         check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
4257                         g_assert (!pass_mrgctx);
4258
4259                         if (pass_vtable) {
4260                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
4261
4262                                 g_assert (vtable);
4263                                 EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
4264                         }
4265
4266                         return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
4267                 }
4268         }
4269
4270         if (mini_is_gsharedvt_klass (klass)) {
4271                 MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
4272                 MonoInst *res, *is_ref, *src_var, *addr;
4273                 int dreg;
4274
4275                 dreg = alloc_ireg (cfg);
4276
4277                 NEW_BBLOCK (cfg, is_ref_bb);
4278                 NEW_BBLOCK (cfg, is_nullable_bb);
4279                 NEW_BBLOCK (cfg, end_bb);
4280                 is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
4281                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 1);
4282                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
4283
4284                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 2);
4285                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
4286
4287                 /* Non-ref case */
4288                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4289                 if (!alloc)
4290                         return NULL;
4291                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4292                 ins->opcode = OP_STOREV_MEMBASE;
4293
4294                 EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, alloc->dreg);
4295                 res->type = STACK_OBJ;
4296                 res->klass = klass;
4297                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4298                 
4299                 /* Ref case */
4300                 MONO_START_BB (cfg, is_ref_bb);
4301
4302                 /* val is a vtype, so has to load the value manually */
4303                 src_var = get_vreg_to_inst (cfg, val->dreg);
4304                 if (!src_var)
4305                         src_var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, val->dreg);
4306                 EMIT_NEW_VARLOADA (cfg, addr, src_var, src_var->inst_vtype);
4307                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, addr->dreg, 0);
4308                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4309
4310                 /* Nullable case */
4311                 MONO_START_BB (cfg, is_nullable_bb);
4312
4313                 {
4314                         MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass,
4315                                                                                                         MONO_RGCTX_INFO_NULLABLE_CLASS_BOX);
4316                         MonoInst *box_call;
4317                         MonoMethodSignature *box_sig;
4318
4319                         /*
4320                          * klass is Nullable<T>, need to call Nullable<T>.Box () using a gsharedvt signature, but we cannot
4321                          * construct that method at JIT time, so have to do things by hand.
4322                          */
4323                         box_sig = mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
4324                         box_sig->ret = &mono_defaults.object_class->byval_arg;
4325                         box_sig->param_count = 1;
4326                         box_sig->params [0] = &klass->byval_arg;
4327                         box_call = mono_emit_calli (cfg, box_sig, &val, addr, NULL, NULL);
4328                         EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, box_call->dreg);
4329                         res->type = STACK_OBJ;
4330                         res->klass = klass;
4331                 }
4332
4333                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4334
4335                 MONO_START_BB (cfg, end_bb);
4336
4337                 return res;
4338         } else {
4339                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4340                 if (!alloc)
4341                         return NULL;
4342
4343                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4344                 return alloc;
4345         }
4346 }
4347
4348 static gboolean
4349 mini_class_has_reference_variant_generic_argument (MonoCompile *cfg, MonoClass *klass, int context_used)
4350 {
4351         int i;
4352         MonoGenericContainer *container;
4353         MonoGenericInst *ginst;
4354
4355         if (klass->generic_class) {
4356                 container = klass->generic_class->container_class->generic_container;
4357                 ginst = klass->generic_class->context.class_inst;
4358         } else if (klass->generic_container && context_used) {
4359                 container = klass->generic_container;
4360                 ginst = container->context.class_inst;
4361         } else {
4362                 return FALSE;
4363         }
4364
4365         for (i = 0; i < container->type_argc; ++i) {
4366                 MonoType *type;
4367                 if (!(mono_generic_container_get_param_info (container, i)->flags & (MONO_GEN_PARAM_VARIANT|MONO_GEN_PARAM_COVARIANT)))
4368                         continue;
4369                 type = ginst->type_argv [i];
4370                 if (mini_type_is_reference (type))
4371                         return TRUE;
4372         }
4373         return FALSE;
4374 }
4375
4376 static GHashTable* direct_icall_type_hash;
4377
4378 static gboolean
4379 icall_is_direct_callable (MonoCompile *cfg, MonoMethod *cmethod)
4380 {
4381         /* LLVM on amd64 can't handle calls to non-32 bit addresses */
4382         if (!direct_icalls_enabled (cfg))
4383                 return FALSE;
4384
4385         /*
4386          * An icall is directly callable if it doesn't directly or indirectly call mono_raise_exception ().
4387          * Whitelist a few icalls for now.
4388          */
4389         if (!direct_icall_type_hash) {
4390                 GHashTable *h = g_hash_table_new (g_str_hash, g_str_equal);
4391
4392                 g_hash_table_insert (h, (char*)"Decimal", GUINT_TO_POINTER (1));
4393                 g_hash_table_insert (h, (char*)"Number", GUINT_TO_POINTER (1));
4394                 g_hash_table_insert (h, (char*)"Buffer", GUINT_TO_POINTER (1));
4395                 g_hash_table_insert (h, (char*)"Monitor", GUINT_TO_POINTER (1));
4396                 mono_memory_barrier ();
4397                 direct_icall_type_hash = h;
4398         }
4399
4400         if (cmethod->klass == mono_defaults.math_class)
4401                 return TRUE;
4402         /* No locking needed */
4403         if (cmethod->klass->image == mono_defaults.corlib && g_hash_table_lookup (direct_icall_type_hash, cmethod->klass->name))
4404                 return TRUE;
4405         return FALSE;
4406 }
4407
4408 #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)
4409
4410 static MonoInst*
4411 emit_castclass_with_cache (MonoCompile *cfg, MonoClass *klass, MonoInst **args)
4412 {
4413         MonoMethod *mono_castclass;
4414         MonoInst *res;
4415
4416         mono_castclass = mono_marshal_get_castclass_with_cache ();
4417
4418         save_cast_details (cfg, klass, args [0]->dreg, TRUE);
4419         res = mono_emit_method_call (cfg, mono_castclass, args, NULL);
4420         reset_cast_details (cfg);
4421
4422         return res;
4423 }
4424
4425 static int
4426 get_castclass_cache_idx (MonoCompile *cfg)
4427 {
4428         /* Each CASTCLASS_CACHE patch needs a unique index which identifies the call site */
4429         cfg->castclass_cache_index ++;
4430         return (cfg->method_index << 16) | cfg->castclass_cache_index;
4431 }
4432
4433 static MonoInst*
4434 emit_castclass_with_cache_nonshared (MonoCompile *cfg, MonoInst *obj, MonoClass *klass)
4435 {
4436         MonoInst *args [3];
4437         int idx;
4438
4439         /* obj */
4440         args [0] = obj;
4441
4442         /* klass */
4443         EMIT_NEW_CLASSCONST (cfg, args [1], klass);
4444
4445         /* inline cache*/
4446         if (cfg->compile_aot) {
4447                 idx = get_castclass_cache_idx (cfg);
4448                 EMIT_NEW_AOTCONST (cfg, args [2], MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
4449         } else {
4450                 EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));
4451         }
4452
4453         /*The wrapper doesn't inline well so the bloat of inlining doesn't pay off.*/
4454         return emit_castclass_with_cache (cfg, klass, args);
4455 }
4456
4457 /*
4458  * Returns NULL and set the cfg exception on error.
4459  */
4460 static MonoInst*
4461 handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, guint8 *ip, int *inline_costs)
4462 {
4463         MonoBasicBlock *is_null_bb;
4464         int obj_reg = src->dreg;
4465         int vtable_reg = alloc_preg (cfg);
4466         int context_used;
4467         MonoInst *klass_inst = NULL, *res;
4468
4469         context_used = mini_class_check_context_used (cfg, klass);
4470
4471         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
4472                 res = emit_castclass_with_cache_nonshared (cfg, src, klass);
4473                 (*inline_costs) += 2;
4474                 return res;
4475         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
4476                 MonoMethod *mono_castclass;
4477                 MonoInst *iargs [1];
4478                 int costs;
4479
4480                 mono_castclass = mono_marshal_get_castclass (klass); 
4481                 iargs [0] = src;
4482                                 
4483                 save_cast_details (cfg, klass, src->dreg, TRUE);
4484                 costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), 
4485                                                            iargs, ip, cfg->real_offset, TRUE);
4486                 reset_cast_details (cfg);
4487                 CHECK_CFG_EXCEPTION;
4488                 g_assert (costs > 0);
4489                                 
4490                 cfg->real_offset += 5;
4491
4492                 (*inline_costs) += costs;
4493
4494                 return src;
4495         }
4496
4497         if (context_used) {
4498                 MonoInst *args [3];
4499
4500                 if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
4501                         MonoInst *cache_ins;
4502
4503                         cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
4504
4505                         /* obj */
4506                         args [0] = src;
4507
4508                         /* klass - it's the second element of the cache entry*/
4509                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
4510
4511                         /* cache */
4512                         args [2] = cache_ins;
4513
4514                         return emit_castclass_with_cache (cfg, klass, args);
4515                 }
4516
4517                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
4518         }
4519
4520         NEW_BBLOCK (cfg, is_null_bb);
4521
4522         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4523         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
4524
4525         save_cast_details (cfg, klass, obj_reg, FALSE);
4526
4527         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4528                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4529                 mini_emit_iface_cast (cfg, vtable_reg, klass, NULL, NULL);
4530         } else {
4531                 int klass_reg = alloc_preg (cfg);
4532
4533                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4534
4535                 if (!klass->rank && !cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
4536                         /* the remoting code is broken, access the class for now */
4537                         if (0) { /*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4538                                 MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4539                                 if (!vt) {
4540                                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4541                                         cfg->exception_ptr = klass;
4542                                         return NULL;
4543                                 }
4544                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4545                         } else {
4546                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4547                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4548                         }
4549                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4550                 } else {
4551                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4552                         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, klass_inst, is_null_bb);
4553                 }
4554         }
4555
4556         MONO_START_BB (cfg, is_null_bb);
4557
4558         reset_cast_details (cfg);
4559
4560         return src;
4561
4562 exception_exit:
4563         return NULL;
4564 }
4565
4566 /*
4567  * Returns NULL and set the cfg exception on error.
4568  */
4569 static MonoInst*
4570 handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
4571 {
4572         MonoInst *ins;
4573         MonoBasicBlock *is_null_bb, *false_bb, *end_bb;
4574         int obj_reg = src->dreg;
4575         int vtable_reg = alloc_preg (cfg);
4576         int res_reg = alloc_ireg_ref (cfg);
4577         MonoInst *klass_inst = NULL;
4578
4579         if (context_used) {
4580                 MonoInst *args [3];
4581
4582                 if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
4583                         MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
4584                         MonoInst *cache_ins;
4585
4586                         cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
4587
4588                         /* obj */
4589                         args [0] = src;
4590
4591                         /* klass - it's the second element of the cache entry*/
4592                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
4593
4594                         /* cache */
4595                         args [2] = cache_ins;
4596
4597                         return mono_emit_method_call (cfg, mono_isinst, args, NULL);
4598                 }
4599
4600                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
4601         }
4602
4603         NEW_BBLOCK (cfg, is_null_bb);
4604         NEW_BBLOCK (cfg, false_bb);
4605         NEW_BBLOCK (cfg, end_bb);
4606
4607         /* Do the assignment at the beginning, so the other assignment can be if converted */
4608         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, res_reg, obj_reg);
4609         ins->type = STACK_OBJ;
4610         ins->klass = klass;
4611
4612         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4613         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_null_bb);
4614
4615         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4616
4617         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4618                 g_assert (!context_used);
4619                 /* the is_null_bb target simply copies the input register to the output */
4620                 mini_emit_iface_cast (cfg, vtable_reg, klass, false_bb, is_null_bb);
4621         } else {
4622                 int klass_reg = alloc_preg (cfg);
4623
4624                 if (klass->rank) {
4625                         int rank_reg = alloc_preg (cfg);
4626                         int eclass_reg = alloc_preg (cfg);
4627
4628                         g_assert (!context_used);
4629                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
4630                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
4631                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4632                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4633                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
4634                         if (klass->cast_class == mono_defaults.object_class) {
4635                                 int parent_reg = alloc_preg (cfg);
4636                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
4637                                 mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, is_null_bb);
4638                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4639                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4640                         } else if (klass->cast_class == mono_defaults.enum_class->parent) {
4641                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, is_null_bb);
4642                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);                          
4643                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4644                         } else if (klass->cast_class == mono_defaults.enum_class) {
4645                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4646                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4647                         } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
4648                                 mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4649                         } else {
4650                                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY)) {
4651                                         /* Check that the object is a vector too */
4652                                         int bounds_reg = alloc_preg (cfg);
4653                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
4654                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
4655                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4656                                 }
4657
4658                                 /* the is_null_bb target simply copies the input register to the output */
4659                                 mini_emit_isninst_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4660                         }
4661                 } else if (mono_class_is_nullable (klass)) {
4662                         g_assert (!context_used);
4663                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4664                         /* the is_null_bb target simply copies the input register to the output */
4665                         mini_emit_isninst_cast (cfg, klass_reg, klass->cast_class, false_bb, is_null_bb);
4666                 } else {
4667                         if (!cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
4668                                 g_assert (!context_used);
4669                                 /* the remoting code is broken, access the class for now */
4670                                 if (0) {/*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4671                                         MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4672                                         if (!vt) {
4673                                                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4674                                                 cfg->exception_ptr = klass;
4675                                                 return NULL;
4676                                         }
4677                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4678                                 } else {
4679                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4680                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4681                                 }
4682                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4683                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, is_null_bb);
4684                         } else {
4685                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4686                                 /* the is_null_bb target simply copies the input register to the output */
4687                                 mini_emit_isninst_cast_inst (cfg, klass_reg, klass, klass_inst, false_bb, is_null_bb);
4688                         }
4689                 }
4690         }
4691
4692         MONO_START_BB (cfg, false_bb);
4693
4694         MONO_EMIT_NEW_PCONST (cfg, res_reg, 0);
4695         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4696
4697         MONO_START_BB (cfg, is_null_bb);
4698
4699         MONO_START_BB (cfg, end_bb);
4700
4701         return ins;
4702 }
4703
4704 static MonoInst*
4705 handle_cisinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4706 {
4707         /* This opcode takes as input an object reference and a class, and returns:
4708         0) if the object is an instance of the class,
4709         1) if the object is not instance of the class,
4710         2) if the object is a proxy whose type cannot be determined */
4711
4712         MonoInst *ins;
4713 #ifndef DISABLE_REMOTING
4714         MonoBasicBlock *true_bb, *false_bb, *false2_bb, *end_bb, *no_proxy_bb, *interface_fail_bb;
4715 #else
4716         MonoBasicBlock *true_bb, *false_bb, *end_bb;
4717 #endif
4718         int obj_reg = src->dreg;
4719         int dreg = alloc_ireg (cfg);
4720         int tmp_reg;
4721 #ifndef DISABLE_REMOTING
4722         int klass_reg = alloc_preg (cfg);
4723 #endif
4724
4725         NEW_BBLOCK (cfg, true_bb);
4726         NEW_BBLOCK (cfg, false_bb);
4727         NEW_BBLOCK (cfg, end_bb);
4728 #ifndef DISABLE_REMOTING
4729         NEW_BBLOCK (cfg, false2_bb);
4730         NEW_BBLOCK (cfg, no_proxy_bb);
4731 #endif
4732
4733         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4734         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, false_bb);
4735
4736         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4737 #ifndef DISABLE_REMOTING
4738                 NEW_BBLOCK (cfg, interface_fail_bb);
4739 #endif
4740
4741                 tmp_reg = alloc_preg (cfg);
4742                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4743 #ifndef DISABLE_REMOTING
4744                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, true_bb);
4745                 MONO_START_BB (cfg, interface_fail_bb);
4746                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4747                 
4748                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, false_bb);
4749
4750                 tmp_reg = alloc_preg (cfg);
4751                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4752                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4753                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false2_bb);                
4754 #else
4755                 mini_emit_iface_cast (cfg, tmp_reg, klass, false_bb, true_bb);
4756 #endif
4757         } else {
4758 #ifndef DISABLE_REMOTING
4759                 tmp_reg = alloc_preg (cfg);
4760                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4761                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4762
4763                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4764                 tmp_reg = alloc_preg (cfg);
4765                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4766                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4767
4768                 tmp_reg = alloc_preg (cfg);             
4769                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4770                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4771                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4772                 
4773                 mini_emit_isninst_cast (cfg, klass_reg, klass, false2_bb, true_bb);
4774                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false2_bb);
4775
4776                 MONO_START_BB (cfg, no_proxy_bb);
4777
4778                 mini_emit_isninst_cast (cfg, klass_reg, klass, false_bb, true_bb);
4779 #else
4780                 g_error ("transparent proxy support is disabled while trying to JIT code that uses it");
4781 #endif
4782         }
4783
4784         MONO_START_BB (cfg, false_bb);
4785
4786         MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4787         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4788
4789 #ifndef DISABLE_REMOTING
4790         MONO_START_BB (cfg, false2_bb);
4791
4792         MONO_EMIT_NEW_ICONST (cfg, dreg, 2);
4793         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4794 #endif
4795
4796         MONO_START_BB (cfg, true_bb);
4797
4798         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4799
4800         MONO_START_BB (cfg, end_bb);
4801
4802         /* FIXME: */
4803         MONO_INST_NEW (cfg, ins, OP_ICONST);
4804         ins->dreg = dreg;
4805         ins->type = STACK_I4;
4806
4807         return ins;
4808 }
4809
4810 static MonoInst*
4811 handle_ccastclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4812 {
4813         /* This opcode takes as input an object reference and a class, and returns:
4814         0) if the object is an instance of the class,
4815         1) if the object is a proxy whose type cannot be determined
4816         an InvalidCastException exception is thrown otherwhise*/
4817         
4818         MonoInst *ins;
4819 #ifndef DISABLE_REMOTING
4820         MonoBasicBlock *end_bb, *ok_result_bb, *no_proxy_bb, *interface_fail_bb, *fail_1_bb;
4821 #else
4822         MonoBasicBlock *ok_result_bb;
4823 #endif
4824         int obj_reg = src->dreg;
4825         int dreg = alloc_ireg (cfg);
4826         int tmp_reg = alloc_preg (cfg);
4827
4828 #ifndef DISABLE_REMOTING
4829         int klass_reg = alloc_preg (cfg);
4830         NEW_BBLOCK (cfg, end_bb);
4831 #endif
4832
4833         NEW_BBLOCK (cfg, ok_result_bb);
4834
4835         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4836         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, ok_result_bb);
4837
4838         save_cast_details (cfg, klass, obj_reg, FALSE);
4839
4840         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4841 #ifndef DISABLE_REMOTING
4842                 NEW_BBLOCK (cfg, interface_fail_bb);
4843         
4844                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4845                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, ok_result_bb);
4846                 MONO_START_BB (cfg, interface_fail_bb);
4847                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4848
4849                 mini_emit_class_check (cfg, klass_reg, mono_defaults.transparent_proxy_class);
4850
4851                 tmp_reg = alloc_preg (cfg);             
4852                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4853                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4854                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
4855                 
4856                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4857                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4858 #else
4859                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4860                 mini_emit_iface_cast (cfg, tmp_reg, klass, NULL, NULL);
4861                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, ok_result_bb);
4862 #endif
4863         } else {
4864 #ifndef DISABLE_REMOTING
4865                 NEW_BBLOCK (cfg, no_proxy_bb);
4866
4867                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4868                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4869                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4870
4871                 tmp_reg = alloc_preg (cfg);
4872                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4873                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4874
4875                 tmp_reg = alloc_preg (cfg);
4876                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4877                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4878                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4879
4880                 NEW_BBLOCK (cfg, fail_1_bb);
4881                 
4882                 mini_emit_isninst_cast (cfg, klass_reg, klass, fail_1_bb, ok_result_bb);
4883
4884                 MONO_START_BB (cfg, fail_1_bb);
4885
4886                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4887                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4888
4889                 MONO_START_BB (cfg, no_proxy_bb);
4890
4891                 mini_emit_castclass (cfg, obj_reg, klass_reg, klass, ok_result_bb);
4892 #else
4893                 g_error ("Transparent proxy support is disabled while trying to JIT code that uses it");
4894 #endif
4895         }
4896
4897         MONO_START_BB (cfg, ok_result_bb);
4898
4899         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4900
4901 #ifndef DISABLE_REMOTING
4902         MONO_START_BB (cfg, end_bb);
4903 #endif
4904
4905         /* FIXME: */
4906         MONO_INST_NEW (cfg, ins, OP_ICONST);
4907         ins->dreg = dreg;
4908         ins->type = STACK_I4;
4909
4910         return ins;
4911 }
4912
4913 static G_GNUC_UNUSED MonoInst*
4914 handle_enum_has_flag (MonoCompile *cfg, MonoClass *klass, MonoInst *enum_this, MonoInst *enum_flag)
4915 {
4916         MonoType *enum_type = mono_type_get_underlying_type (&klass->byval_arg);
4917         guint32 load_opc = mono_type_to_load_membase (cfg, enum_type);
4918         gboolean is_i4;
4919
4920         switch (enum_type->type) {
4921         case MONO_TYPE_I8:
4922         case MONO_TYPE_U8:
4923 #if SIZEOF_REGISTER == 8
4924         case MONO_TYPE_I:
4925         case MONO_TYPE_U:
4926 #endif
4927                 is_i4 = FALSE;
4928                 break;
4929         default:
4930                 is_i4 = TRUE;
4931                 break;
4932         }
4933
4934         {
4935                 MonoInst *load, *and, *cmp, *ceq;
4936                 int enum_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
4937                 int and_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
4938                 int dest_reg = alloc_ireg (cfg);
4939
4940                 EMIT_NEW_LOAD_MEMBASE (cfg, load, load_opc, enum_reg, enum_this->dreg, 0);
4941                 EMIT_NEW_BIALU (cfg, and, is_i4 ? OP_IAND : OP_LAND, and_reg, enum_reg, enum_flag->dreg);
4942                 EMIT_NEW_BIALU (cfg, cmp, is_i4 ? OP_ICOMPARE : OP_LCOMPARE, -1, and_reg, enum_flag->dreg);
4943                 EMIT_NEW_UNALU (cfg, ceq, is_i4 ? OP_ICEQ : OP_LCEQ, dest_reg, -1);
4944
4945                 ceq->type = STACK_I4;
4946
4947                 if (!is_i4) {
4948                         load = mono_decompose_opcode (cfg, load);
4949                         and = mono_decompose_opcode (cfg, and);
4950                         cmp = mono_decompose_opcode (cfg, cmp);
4951                         ceq = mono_decompose_opcode (cfg, ceq);
4952                 }
4953
4954                 return ceq;
4955         }
4956 }
4957
4958 /*
4959  * Returns NULL and set the cfg exception on error.
4960  */
4961 static G_GNUC_UNUSED MonoInst*
4962 handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, MonoMethod *method, int context_used, gboolean virtual)
4963 {
4964         MonoInst *ptr;
4965         int dreg;
4966         gpointer trampoline;
4967         MonoInst *obj, *method_ins, *tramp_ins;
4968         MonoDomain *domain;
4969         guint8 **code_slot;
4970
4971         if (virtual && !cfg->llvm_only) {
4972                 MonoMethod *invoke = mono_get_delegate_invoke (klass);
4973                 g_assert (invoke);
4974
4975                 if (!mono_get_delegate_virtual_invoke_impl (mono_method_signature (invoke), context_used ? NULL : method))
4976                         return NULL;
4977         }
4978
4979         obj = handle_alloc (cfg, klass, FALSE, mono_class_check_context_used (klass));
4980         if (!obj)
4981                 return NULL;
4982
4983         if (cfg->llvm_only) {
4984                 MonoInst *args [16];
4985
4986                 /*
4987                  * If the method to be called needs an rgctx, we can't fall back to mono_delegate_ctor (), since it might receive
4988                  * the address of a gshared method. So use a JIT icall.
4989                  * FIXME: Optimize this.
4990                  */
4991                 args [0] = obj;
4992                 args [1] = target;
4993                 args [2] = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
4994                 mono_emit_jit_icall (cfg, virtual ? mono_init_delegate_virtual : mono_init_delegate, args);
4995
4996                 return obj;
4997         }
4998
4999         /* Inline the contents of mono_delegate_ctor */
5000
5001         /* Set target field */
5002         /* Optimize away setting of NULL target */
5003         if (!(target->opcode == OP_PCONST && target->inst_p0 == 0)) {
5004                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target), target->dreg);
5005                 if (cfg->gen_write_barriers) {
5006                         dreg = alloc_preg (cfg);
5007                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target));
5008                         emit_write_barrier (cfg, ptr, target);
5009                 }
5010         }
5011
5012         /* Set method field */
5013         method_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
5014         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method), method_ins->dreg);
5015
5016         /* 
5017          * To avoid looking up the compiled code belonging to the target method
5018          * in mono_delegate_trampoline (), we allocate a per-domain memory slot to
5019          * store it, and we fill it after the method has been compiled.
5020          */
5021         if (!method->dynamic && !(cfg->opt & MONO_OPT_SHARED)) {
5022                 MonoInst *code_slot_ins;
5023
5024                 if (context_used) {
5025                         code_slot_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD_DELEGATE_CODE);
5026                 } else {
5027                         domain = mono_domain_get ();
5028                         mono_domain_lock (domain);
5029                         if (!domain_jit_info (domain)->method_code_hash)
5030                                 domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
5031                         code_slot = g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, method);
5032                         if (!code_slot) {
5033                                 code_slot = mono_domain_alloc0 (domain, sizeof (gpointer));
5034                                 g_hash_table_insert (domain_jit_info (domain)->method_code_hash, method, code_slot);
5035                         }
5036                         mono_domain_unlock (domain);
5037
5038                         if (cfg->compile_aot)
5039                                 EMIT_NEW_AOTCONST (cfg, code_slot_ins, MONO_PATCH_INFO_METHOD_CODE_SLOT, method);
5040                         else
5041                                 EMIT_NEW_PCONST (cfg, code_slot_ins, code_slot);
5042                 }
5043                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_code), code_slot_ins->dreg);                
5044         }
5045
5046         if (cfg->compile_aot) {
5047                 MonoDelegateClassMethodPair *del_tramp;
5048
5049                 del_tramp = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoDelegateClassMethodPair));
5050                 del_tramp->klass = klass;
5051                 del_tramp->method = context_used ? NULL : method;
5052                 del_tramp->is_virtual = virtual;
5053                 EMIT_NEW_AOTCONST (cfg, tramp_ins, MONO_PATCH_INFO_DELEGATE_TRAMPOLINE, del_tramp);
5054         } else {
5055                 if (virtual)
5056                         trampoline = mono_create_delegate_virtual_trampoline (cfg->domain, klass, context_used ? NULL : method);
5057                 else
5058                         trampoline = mono_create_delegate_trampoline_info (cfg->domain, klass, context_used ? NULL : method);
5059                 EMIT_NEW_PCONST (cfg, tramp_ins, trampoline);
5060         }
5061
5062         /* Set invoke_impl field */
5063         if (virtual) {
5064                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), tramp_ins->dreg);
5065         } else {
5066                 dreg = alloc_preg (cfg);
5067                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, invoke_impl));
5068                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), dreg);
5069
5070                 dreg = alloc_preg (cfg);
5071                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, method_ptr));
5072                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr), dreg);
5073         }
5074
5075         dreg = alloc_preg (cfg);
5076         MONO_EMIT_NEW_ICONST (cfg, dreg, virtual ? 1 : 0);
5077         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_is_virtual), dreg);
5078
5079         /* All the checks which are in mono_delegate_ctor () are done by the delegate trampoline */
5080
5081         return obj;
5082 }
5083
5084 static MonoInst*
5085 handle_array_new (MonoCompile *cfg, int rank, MonoInst **sp, unsigned char *ip)
5086 {
5087         MonoJitICallInfo *info;
5088
5089         /* Need to register the icall so it gets an icall wrapper */
5090         info = mono_get_array_new_va_icall (rank);
5091
5092         cfg->flags |= MONO_CFG_HAS_VARARGS;
5093
5094         /* mono_array_new_va () needs a vararg calling convention */
5095         cfg->disable_llvm = TRUE;
5096
5097         /* FIXME: This uses info->sig, but it should use the signature of the wrapper */
5098         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, sp);
5099 }
5100
5101 /*
5102  * handle_constrained_gsharedvt_call:
5103  *
5104  *   Handle constrained calls where the receiver is a gsharedvt type.
5105  * Return the instruction representing the call. Set the cfg exception on failure.
5106  */
5107 static MonoInst*
5108 handle_constrained_gsharedvt_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp, MonoClass *constrained_class,
5109                                                                    gboolean *ref_emit_widen)
5110 {
5111         MonoInst *ins = NULL;
5112         gboolean emit_widen = *ref_emit_widen;
5113
5114         /*
5115          * Constrained calls need to behave differently at runtime dependending on whenever the receiver is instantiated as ref type or as a vtype.
5116          * 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
5117          * pack the arguments into an array, and do the rest of the work in in an icall.
5118          */
5119         if (((cmethod->klass == mono_defaults.object_class) || (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) || (!cmethod->klass->valuetype && cmethod->klass->image != mono_defaults.corlib)) &&
5120                 (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)) &&
5121                 (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]))))) {
5122                 MonoInst *args [16];
5123
5124                 /*
5125                  * This case handles calls to
5126                  * - object:ToString()/Equals()/GetHashCode(),
5127                  * - System.IComparable<T>:CompareTo()
5128                  * - System.IEquatable<T>:Equals ()
5129                  * plus some simple interface calls enough to support AsyncTaskMethodBuilder.
5130                  */
5131
5132                 args [0] = sp [0];
5133                 if (mono_method_check_context_used (cmethod))
5134                         args [1] = emit_get_rgctx_method (cfg, mono_method_check_context_used (cmethod), cmethod, MONO_RGCTX_INFO_METHOD);
5135                 else
5136                         EMIT_NEW_METHODCONST (cfg, args [1], cmethod);
5137                 args [2] = emit_get_rgctx_klass (cfg, mono_class_check_context_used (constrained_class), constrained_class, MONO_RGCTX_INFO_KLASS);
5138
5139                 /* !fsig->hasthis is for the wrapper for the Object.GetType () icall */
5140                 if (fsig->hasthis && fsig->param_count) {
5141                         /* Pass the arguments using a localloc-ed array using the format expected by runtime_invoke () */
5142                         MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
5143                         ins->dreg = alloc_preg (cfg);
5144                         ins->inst_imm = fsig->param_count * sizeof (mgreg_t);
5145                         MONO_ADD_INS (cfg->cbb, ins);
5146                         args [4] = ins;
5147
5148                         if (mini_is_gsharedvt_type (fsig->params [0])) {
5149                                 int addr_reg;
5150
5151                                 args [3] = emit_get_gsharedvt_info_klass (cfg, mono_class_from_mono_type (fsig->params [0]), MONO_RGCTX_INFO_CLASS_BOX_TYPE);
5152
5153                                 EMIT_NEW_VARLOADA_VREG (cfg, ins, sp [1]->dreg, fsig->params [0]);
5154                                 addr_reg = ins->dreg;
5155                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, addr_reg);
5156                         } else {
5157                                 EMIT_NEW_ICONST (cfg, args [3], 0);
5158                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, sp [1]->dreg);
5159                         }
5160                 } else {
5161                         EMIT_NEW_ICONST (cfg, args [3], 0);
5162                         EMIT_NEW_ICONST (cfg, args [4], 0);
5163                 }
5164                 ins = mono_emit_jit_icall (cfg, mono_gsharedvt_constrained_call, args);
5165                 emit_widen = FALSE;
5166
5167                 if (mini_is_gsharedvt_type (fsig->ret)) {
5168                         ins = handle_unbox_gsharedvt (cfg, mono_class_from_mono_type (fsig->ret), ins);
5169                 } else if (MONO_TYPE_IS_PRIMITIVE (fsig->ret) || MONO_TYPE_ISSTRUCT (fsig->ret)) {
5170                         MonoInst *add;
5171
5172                         /* Unbox */
5173                         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), ins->dreg, sizeof (MonoObject));
5174                         MONO_ADD_INS (cfg->cbb, add);
5175                         /* Load value */
5176                         NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, add->dreg, 0);
5177                         MONO_ADD_INS (cfg->cbb, ins);
5178                         /* ins represents the call result */
5179                 }
5180         } else {
5181                 GSHAREDVT_FAILURE (CEE_CALLVIRT);
5182         }
5183
5184         *ref_emit_widen = emit_widen;
5185
5186         return ins;
5187
5188  exception_exit:
5189         return NULL;
5190 }
5191
5192 static void
5193 mono_emit_load_got_addr (MonoCompile *cfg)
5194 {
5195         MonoInst *getaddr, *dummy_use;
5196
5197         if (!cfg->got_var || cfg->got_var_allocated)
5198                 return;
5199
5200         MONO_INST_NEW (cfg, getaddr, OP_LOAD_GOTADDR);
5201         getaddr->cil_code = cfg->header->code;
5202         getaddr->dreg = cfg->got_var->dreg;
5203
5204         /* Add it to the start of the first bblock */
5205         if (cfg->bb_entry->code) {
5206                 getaddr->next = cfg->bb_entry->code;
5207                 cfg->bb_entry->code = getaddr;
5208         }
5209         else
5210                 MONO_ADD_INS (cfg->bb_entry, getaddr);
5211
5212         cfg->got_var_allocated = TRUE;
5213
5214         /* 
5215          * Add a dummy use to keep the got_var alive, since real uses might
5216          * only be generated by the back ends.
5217          * Add it to end_bblock, so the variable's lifetime covers the whole
5218          * method.
5219          * It would be better to make the usage of the got var explicit in all
5220          * cases when the backend needs it (i.e. calls, throw etc.), so this
5221          * wouldn't be needed.
5222          */
5223         NEW_DUMMY_USE (cfg, dummy_use, cfg->got_var);
5224         MONO_ADD_INS (cfg->bb_exit, dummy_use);
5225 }
5226
5227 static int inline_limit;
5228 static gboolean inline_limit_inited;
5229
5230 static gboolean
5231 mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
5232 {
5233         MonoMethodHeaderSummary header;
5234         MonoVTable *vtable;
5235 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
5236         MonoMethodSignature *sig = mono_method_signature (method);
5237         int i;
5238 #endif
5239
5240         if (cfg->disable_inline)
5241                 return FALSE;
5242         if (cfg->gshared)
5243                 return FALSE;
5244
5245         if (cfg->inline_depth > 10)
5246                 return FALSE;
5247
5248         if (!mono_method_get_header_summary (method, &header))
5249                 return FALSE;
5250
5251         /*runtime, icall and pinvoke are checked by summary call*/
5252         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
5253             (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
5254             (mono_class_is_marshalbyref (method->klass)) ||
5255             header.has_clauses)
5256                 return FALSE;
5257
5258         /* also consider num_locals? */
5259         /* Do the size check early to avoid creating vtables */
5260         if (!inline_limit_inited) {
5261                 if (g_getenv ("MONO_INLINELIMIT"))
5262                         inline_limit = atoi (g_getenv ("MONO_INLINELIMIT"));
5263                 else
5264                         inline_limit = INLINE_LENGTH_LIMIT;
5265                 inline_limit_inited = TRUE;
5266         }
5267         if (header.code_size >= inline_limit && !(method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))
5268                 return FALSE;
5269
5270         /*
5271          * if we can initialize the class of the method right away, we do,
5272          * otherwise we don't allow inlining if the class needs initialization,
5273          * since it would mean inserting a call to mono_runtime_class_init()
5274          * inside the inlined code
5275          */
5276         if (!(cfg->opt & MONO_OPT_SHARED)) {
5277                 /* The AggressiveInlining hint is a good excuse to force that cctor to run. */
5278                 if (method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING) {
5279                         vtable = mono_class_vtable (cfg->domain, method->klass);
5280                         if (!vtable)
5281                                 return FALSE;
5282                         if (!cfg->compile_aot)
5283                                 mono_runtime_class_init (vtable);
5284                 } else if (method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
5285                         if (cfg->run_cctors && method->klass->has_cctor) {
5286                                 /*FIXME it would easier and lazier to just use mono_class_try_get_vtable */
5287                                 if (!method->klass->runtime_info)
5288                                         /* No vtable created yet */
5289                                         return FALSE;
5290                                 vtable = mono_class_vtable (cfg->domain, method->klass);
5291                                 if (!vtable)
5292                                         return FALSE;
5293                                 /* This makes so that inline cannot trigger */
5294                                 /* .cctors: too many apps depend on them */
5295                                 /* running with a specific order... */
5296                                 if (! vtable->initialized)
5297                                         return FALSE;
5298                                 mono_runtime_class_init (vtable);
5299                         }
5300                 } else if (mono_class_needs_cctor_run (method->klass, NULL)) {
5301                         if (!method->klass->runtime_info)
5302                                 /* No vtable created yet */
5303                                 return FALSE;
5304                         vtable = mono_class_vtable (cfg->domain, method->klass);
5305                         if (!vtable)
5306                                 return FALSE;
5307                         if (!vtable->initialized)
5308                                 return FALSE;
5309                 }
5310         } else {
5311                 /* 
5312                  * If we're compiling for shared code
5313                  * the cctor will need to be run at aot method load time, for example,
5314                  * or at the end of the compilation of the inlining method.
5315                  */
5316                 if (mono_class_needs_cctor_run (method->klass, NULL) && !((method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)))
5317                         return FALSE;
5318         }
5319
5320 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
5321         if (mono_arch_is_soft_float ()) {
5322                 /* FIXME: */
5323                 if (sig->ret && sig->ret->type == MONO_TYPE_R4)
5324                         return FALSE;
5325                 for (i = 0; i < sig->param_count; ++i)
5326                         if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_R4)
5327                                 return FALSE;
5328         }
5329 #endif
5330
5331         if (g_list_find (cfg->dont_inline, method))
5332                 return FALSE;
5333
5334         return TRUE;
5335 }
5336
5337 static gboolean
5338 mini_field_access_needs_cctor_run (MonoCompile *cfg, MonoMethod *method, MonoClass *klass, MonoVTable *vtable)
5339 {
5340         if (!cfg->compile_aot) {
5341                 g_assert (vtable);
5342                 if (vtable->initialized)
5343                         return FALSE;
5344         }
5345
5346         if (klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
5347                 if (cfg->method == method)
5348                         return FALSE;
5349         }
5350
5351         if (!mono_class_needs_cctor_run (klass, method))
5352                 return FALSE;
5353
5354         if (! (method->flags & METHOD_ATTRIBUTE_STATIC) && (klass == method->klass))
5355                 /* The initialization is already done before the method is called */
5356                 return FALSE;
5357
5358         return TRUE;
5359 }
5360
5361 static MonoInst*
5362 mini_emit_ldelema_1_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index, gboolean bcheck)
5363 {
5364         MonoInst *ins;
5365         guint32 size;
5366         int mult_reg, add_reg, array_reg, index_reg, index2_reg;
5367         int context_used;
5368
5369         if (mini_is_gsharedvt_variable_klass (klass)) {
5370                 size = -1;
5371         } else {
5372                 mono_class_init (klass);
5373                 size = mono_class_array_element_size (klass);
5374         }
5375
5376         mult_reg = alloc_preg (cfg);
5377         array_reg = arr->dreg;
5378         index_reg = index->dreg;
5379
5380 #if SIZEOF_REGISTER == 8
5381         /* The array reg is 64 bits but the index reg is only 32 */
5382         if (COMPILE_LLVM (cfg)) {
5383                 /* Not needed */
5384                 index2_reg = index_reg;
5385         } else {
5386                 index2_reg = alloc_preg (cfg);
5387                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index2_reg, index_reg);
5388         }
5389 #else
5390         if (index->type == STACK_I8) {
5391                 index2_reg = alloc_preg (cfg);
5392                 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I4, index2_reg, index_reg);
5393         } else {
5394                 index2_reg = index_reg;
5395         }
5396 #endif
5397
5398         if (bcheck)
5399                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index2_reg);
5400
5401 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5402         if (size == 1 || size == 2 || size == 4 || size == 8) {
5403                 static const int fast_log2 [] = { 1, 0, 1, -1, 2, -1, -1, -1, 3 };
5404
5405                 EMIT_NEW_X86_LEA (cfg, ins, array_reg, index2_reg, fast_log2 [size], MONO_STRUCT_OFFSET (MonoArray, vector));
5406                 ins->klass = mono_class_get_element_class (klass);
5407                 ins->type = STACK_MP;
5408
5409                 return ins;
5410         }
5411 #endif          
5412
5413         add_reg = alloc_ireg_mp (cfg);
5414
5415         if (size == -1) {
5416                 MonoInst *rgctx_ins;
5417
5418                 /* gsharedvt */
5419                 g_assert (cfg->gshared);
5420                 context_used = mini_class_check_context_used (cfg, klass);
5421                 g_assert (context_used);
5422                 rgctx_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE);
5423                 MONO_EMIT_NEW_BIALU (cfg, OP_IMUL, mult_reg, index2_reg, rgctx_ins->dreg);
5424         } else {
5425                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MUL_IMM, mult_reg, index2_reg, size);
5426         }
5427         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, array_reg, mult_reg);
5428         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
5429         ins->klass = mono_class_get_element_class (klass);
5430         ins->type = STACK_MP;
5431         MONO_ADD_INS (cfg->cbb, ins);
5432
5433         return ins;
5434 }
5435
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
5510 static MonoInst*
5511 mini_emit_ldelema_ins (MonoCompile *cfg, MonoMethod *cmethod, MonoInst **sp, unsigned char *ip, gboolean is_set)
5512 {
5513         int rank;
5514         MonoInst *addr;
5515         MonoMethod *addr_method;
5516         int element_size;
5517         MonoClass *eclass = cmethod->klass->element_class;
5518
5519         rank = mono_method_signature (cmethod)->param_count - (is_set? 1: 0);
5520
5521         if (rank == 1)
5522                 return mini_emit_ldelema_1_ins (cfg, eclass, sp [0], sp [1], TRUE);
5523
5524         /* emit_ldelema_2 depends on OP_LMUL */
5525         if (!cfg->backend->emulate_mul_div && rank == 2 && (cfg->opt & MONO_OPT_INTRINS) && !mini_is_gsharedvt_variable_klass (eclass)) {
5526                 return mini_emit_ldelema_2_ins (cfg, eclass, sp [0], sp [1], sp [2]);
5527         }
5528
5529         if (mini_is_gsharedvt_variable_klass (eclass))
5530                 element_size = 0;
5531         else
5532                 element_size = mono_class_array_element_size (eclass);
5533         addr_method = mono_marshal_get_array_address (rank, element_size);
5534         addr = mono_emit_method_call (cfg, addr_method, sp, NULL);
5535
5536         return addr;
5537 }
5538
5539 static MonoBreakPolicy
5540 always_insert_breakpoint (MonoMethod *method)
5541 {
5542         return MONO_BREAK_POLICY_ALWAYS;
5543 }
5544
5545 static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
5546
5547 /**
5548  * mono_set_break_policy:
5549  * policy_callback: the new callback function
5550  *
5551  * Allow embedders to decide wherther to actually obey breakpoint instructions
5552  * (both break IL instructions and Debugger.Break () method calls), for example
5553  * to not allow an app to be aborted by a perfectly valid IL opcode when executing
5554  * untrusted or semi-trusted code.
5555  *
5556  * @policy_callback will be called every time a break point instruction needs to
5557  * be inserted with the method argument being the method that calls Debugger.Break()
5558  * or has the IL break instruction. The callback should return #MONO_BREAK_POLICY_NEVER
5559  * if it wants the breakpoint to not be effective in the given method.
5560  * #MONO_BREAK_POLICY_ALWAYS is the default.
5561  */
5562 void
5563 mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
5564 {
5565         if (policy_callback)
5566                 break_policy_func = policy_callback;
5567         else
5568                 break_policy_func = always_insert_breakpoint;
5569 }
5570
5571 static gboolean
5572 should_insert_brekpoint (MonoMethod *method) {
5573         switch (break_policy_func (method)) {
5574         case MONO_BREAK_POLICY_ALWAYS:
5575                 return TRUE;
5576         case MONO_BREAK_POLICY_NEVER:
5577                 return FALSE;
5578         case MONO_BREAK_POLICY_ON_DBG:
5579                 g_warning ("mdb no longer supported");
5580                 return FALSE;
5581         default:
5582                 g_warning ("Incorrect value returned from break policy callback");
5583                 return FALSE;
5584         }
5585 }
5586
5587 /* optimize the simple GetGenericValueImpl/SetGenericValueImpl generic icalls */
5588 static MonoInst*
5589 emit_array_generic_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
5590 {
5591         MonoInst *addr, *store, *load;
5592         MonoClass *eklass = mono_class_from_mono_type (fsig->params [2]);
5593
5594         /* the bounds check is already done by the callers */
5595         addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
5596         if (is_set) {
5597                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, args [2]->dreg, 0);
5598                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, addr->dreg, 0, load->dreg);
5599                 if (mini_type_is_reference (fsig->params [2]))
5600                         emit_write_barrier (cfg, addr, load);
5601         } else {
5602                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, addr->dreg, 0);
5603                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, args [2]->dreg, 0, load->dreg);
5604         }
5605         return store;
5606 }
5607
5608
5609 static gboolean
5610 generic_class_is_reference_type (MonoCompile *cfg, MonoClass *klass)
5611 {
5612         return mini_type_is_reference (&klass->byval_arg);
5613 }
5614
5615 static MonoInst*
5616 emit_array_store (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, gboolean safety_checks)
5617 {
5618         if (safety_checks && generic_class_is_reference_type (cfg, klass) &&
5619                 !(sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL)) {
5620                 MonoClass *obj_array = mono_array_class_get_cached (mono_defaults.object_class, 1);
5621                 MonoMethod *helper = mono_marshal_get_virtual_stelemref (obj_array);
5622                 MonoInst *iargs [3];
5623
5624                 if (!helper->slot)
5625                         mono_class_setup_vtable (obj_array);
5626                 g_assert (helper->slot);
5627
5628                 if (sp [0]->type != STACK_OBJ)
5629                         return NULL;
5630                 if (sp [2]->type != STACK_OBJ)
5631                         return NULL;
5632
5633                 iargs [2] = sp [2];
5634                 iargs [1] = sp [1];
5635                 iargs [0] = sp [0];
5636
5637                 return mono_emit_method_call (cfg, helper, iargs, sp [0]);
5638         } else {
5639                 MonoInst *ins;
5640
5641                 if (mini_is_gsharedvt_variable_klass (klass)) {
5642                         MonoInst *addr;
5643
5644                         // FIXME-VT: OP_ICONST optimization
5645                         addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
5646                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5647                         ins->opcode = OP_STOREV_MEMBASE;
5648                 } else if (sp [1]->opcode == OP_ICONST) {
5649                         int array_reg = sp [0]->dreg;
5650                         int index_reg = sp [1]->dreg;
5651                         int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
5652
5653                         if (safety_checks)
5654                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
5655                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset, sp [2]->dreg);
5656                 } else {
5657                         MonoInst *addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], safety_checks);
5658                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5659                         if (generic_class_is_reference_type (cfg, klass))
5660                                 emit_write_barrier (cfg, addr, sp [2]);
5661                 }
5662                 return ins;
5663         }
5664 }
5665
5666 static MonoInst*
5667 emit_array_unsafe_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
5668 {
5669         MonoClass *eklass;
5670         
5671         if (is_set)
5672                 eklass = mono_class_from_mono_type (fsig->params [2]);
5673         else
5674                 eklass = mono_class_from_mono_type (fsig->ret);
5675
5676         if (is_set) {
5677                 return emit_array_store (cfg, eklass, args, FALSE);
5678         } else {
5679                 MonoInst *ins, *addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
5680                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &eklass->byval_arg, addr->dreg, 0);
5681                 return ins;
5682         }
5683 }
5684
5685 static gboolean
5686 is_unsafe_mov_compatible (MonoCompile *cfg, MonoClass *param_klass, MonoClass *return_klass)
5687 {
5688         uint32_t align;
5689         int param_size, return_size;
5690
5691         param_klass = mono_class_from_mono_type (mini_get_underlying_type (&param_klass->byval_arg));
5692         return_klass = mono_class_from_mono_type (mini_get_underlying_type (&return_klass->byval_arg));
5693
5694         if (cfg->verbose_level > 3)
5695                 printf ("[UNSAFE-MOV-INTRISIC] %s <- %s\n", return_klass->name, param_klass->name);
5696
5697         //Only allow for valuetypes
5698         if (!param_klass->valuetype || !return_klass->valuetype) {
5699                 if (cfg->verbose_level > 3)
5700                         printf ("[UNSAFE-MOV-INTRISIC]\tone of the args is not a valuetype\n");
5701                 return FALSE;
5702         }
5703
5704         //That are blitable
5705         if (param_klass->has_references || return_klass->has_references)
5706                 return FALSE;
5707
5708         /* Avoid mixing structs and primitive types/enums, they need to be handled differently in the JIT */
5709         if ((MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && !MONO_TYPE_ISSTRUCT (&return_klass->byval_arg)) ||
5710                 (!MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && MONO_TYPE_ISSTRUCT (&return_klass->byval_arg))) {
5711                         if (cfg->verbose_level > 3)
5712                                 printf ("[UNSAFE-MOV-INTRISIC]\tmixing structs and scalars\n");
5713                 return FALSE;
5714         }
5715
5716         if (param_klass->byval_arg.type == MONO_TYPE_R4 || param_klass->byval_arg.type == MONO_TYPE_R8 ||
5717                 return_klass->byval_arg.type == MONO_TYPE_R4 || return_klass->byval_arg.type == MONO_TYPE_R8) {
5718                 if (cfg->verbose_level > 3)
5719                         printf ("[UNSAFE-MOV-INTRISIC]\tfloat or double are not supported\n");
5720                 return FALSE;
5721         }
5722
5723         param_size = mono_class_value_size (param_klass, &align);
5724         return_size = mono_class_value_size (return_klass, &align);
5725
5726         //We can do it if sizes match
5727         if (param_size == return_size) {
5728                 if (cfg->verbose_level > 3)
5729                         printf ("[UNSAFE-MOV-INTRISIC]\tsame size\n");
5730                 return TRUE;
5731         }
5732
5733         //No simple way to handle struct if sizes don't match
5734         if (MONO_TYPE_ISSTRUCT (&param_klass->byval_arg)) {
5735                 if (cfg->verbose_level > 3)
5736                         printf ("[UNSAFE-MOV-INTRISIC]\tsize mismatch and type is a struct\n");
5737                 return FALSE;
5738         }
5739
5740         /*
5741          * Same reg size category.
5742          * A quick note on why we don't require widening here.
5743          * The intrinsic is "R Array.UnsafeMov<S,R> (S s)".
5744          *
5745          * Since the source value comes from a function argument, the JIT will already have
5746          * the value in a VREG and performed any widening needed before (say, when loading from a field).
5747          */
5748         if (param_size <= 4 && return_size <= 4) {
5749                 if (cfg->verbose_level > 3)
5750                         printf ("[UNSAFE-MOV-INTRISIC]\tsize mismatch but both are of the same reg class\n");
5751                 return TRUE;
5752         }
5753
5754         return FALSE;
5755 }
5756
5757 static MonoInst*
5758 emit_array_unsafe_mov (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args)
5759 {
5760         MonoClass *param_klass = mono_class_from_mono_type (fsig->params [0]);
5761         MonoClass *return_klass = mono_class_from_mono_type (fsig->ret);
5762
5763         //Valuetypes that are semantically equivalent or numbers than can be widened to
5764         if (is_unsafe_mov_compatible (cfg, param_klass, return_klass))
5765                 return args [0];
5766
5767         //Arrays of valuetypes that are semantically equivalent
5768         if (param_klass->rank == 1 && return_klass->rank == 1 && is_unsafe_mov_compatible (cfg, param_klass->element_class, return_klass->element_class))
5769                 return args [0];
5770
5771         return NULL;
5772 }
5773
5774 static MonoInst*
5775 mini_emit_inst_for_ctor (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5776 {
5777 #ifdef MONO_ARCH_SIMD_INTRINSICS
5778         MonoInst *ins = NULL;
5779
5780         if (cfg->opt & MONO_OPT_SIMD) {
5781                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
5782                 if (ins)
5783                         return ins;
5784         }
5785 #endif
5786
5787         return mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
5788 }
5789
5790 static MonoInst*
5791 emit_memory_barrier (MonoCompile *cfg, int kind)
5792 {
5793         MonoInst *ins = NULL;
5794         MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
5795         MONO_ADD_INS (cfg->cbb, ins);
5796         ins->backend.memory_barrier_kind = kind;
5797
5798         return ins;
5799 }
5800
5801 static MonoInst*
5802 llvm_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5803 {
5804         MonoInst *ins = NULL;
5805         int opcode = 0;
5806
5807         /* The LLVM backend supports these intrinsics */
5808         if (cmethod->klass == mono_defaults.math_class) {
5809                 if (strcmp (cmethod->name, "Sin") == 0) {
5810                         opcode = OP_SIN;
5811                 } else if (strcmp (cmethod->name, "Cos") == 0) {
5812                         opcode = OP_COS;
5813                 } else if (strcmp (cmethod->name, "Sqrt") == 0) {
5814                         opcode = OP_SQRT;
5815                 } else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8) {
5816                         opcode = OP_ABS;
5817                 }
5818
5819                 if (opcode && fsig->param_count == 1) {
5820                         MONO_INST_NEW (cfg, ins, opcode);
5821                         ins->type = STACK_R8;
5822                         ins->dreg = mono_alloc_freg (cfg);
5823                         ins->sreg1 = args [0]->dreg;
5824                         MONO_ADD_INS (cfg->cbb, ins);
5825                 }
5826
5827                 opcode = 0;
5828                 if (cfg->opt & MONO_OPT_CMOV) {
5829                         if (strcmp (cmethod->name, "Min") == 0) {
5830                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5831                                         opcode = OP_IMIN;
5832                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5833                                         opcode = OP_IMIN_UN;
5834                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5835                                         opcode = OP_LMIN;
5836                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5837                                         opcode = OP_LMIN_UN;
5838                         } else if (strcmp (cmethod->name, "Max") == 0) {
5839                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5840                                         opcode = OP_IMAX;
5841                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5842                                         opcode = OP_IMAX_UN;
5843                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5844                                         opcode = OP_LMAX;
5845                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5846                                         opcode = OP_LMAX_UN;
5847                         }
5848                 }
5849
5850                 if (opcode && fsig->param_count == 2) {
5851                         MONO_INST_NEW (cfg, ins, opcode);
5852                         ins->type = fsig->params [0]->type == MONO_TYPE_I4 ? STACK_I4 : STACK_I8;
5853                         ins->dreg = mono_alloc_ireg (cfg);
5854                         ins->sreg1 = args [0]->dreg;
5855                         ins->sreg2 = args [1]->dreg;
5856                         MONO_ADD_INS (cfg->cbb, ins);
5857                 }
5858         }
5859
5860         return ins;
5861 }
5862
5863 static MonoInst*
5864 mini_emit_inst_for_sharable_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5865 {
5866         if (cmethod->klass == mono_defaults.array_class) {
5867                 if (strcmp (cmethod->name, "UnsafeStore") == 0)
5868                         return emit_array_unsafe_access (cfg, fsig, args, TRUE);
5869                 else if (strcmp (cmethod->name, "UnsafeLoad") == 0)
5870                         return emit_array_unsafe_access (cfg, fsig, args, FALSE);
5871                 else if (strcmp (cmethod->name, "UnsafeMov") == 0)
5872                         return emit_array_unsafe_mov (cfg, fsig, args);
5873         }
5874
5875         return NULL;
5876 }
5877
5878 static MonoInst*
5879 mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5880 {
5881         MonoInst *ins = NULL;
5882
5883         static MonoClass *runtime_helpers_class = NULL;
5884         if (! runtime_helpers_class)
5885                 runtime_helpers_class = mono_class_from_name (mono_defaults.corlib,
5886                         "System.Runtime.CompilerServices", "RuntimeHelpers");
5887
5888         if (cmethod->klass == mono_defaults.string_class) {
5889                 if (strcmp (cmethod->name, "get_Chars") == 0 && fsig->param_count + fsig->hasthis == 2) {
5890                         int dreg = alloc_ireg (cfg);
5891                         int index_reg = alloc_preg (cfg);
5892                         int add_reg = alloc_preg (cfg);
5893
5894 #if SIZEOF_REGISTER == 8
5895                         /* The array reg is 64 bits but the index reg is only 32 */
5896                         MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index_reg, args [1]->dreg);
5897 #else
5898                         index_reg = args [1]->dreg;
5899 #endif  
5900                         MONO_EMIT_BOUNDS_CHECK (cfg, args [0]->dreg, MonoString, length, index_reg);
5901
5902 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5903                         EMIT_NEW_X86_LEA (cfg, ins, args [0]->dreg, index_reg, 1, MONO_STRUCT_OFFSET (MonoString, chars));
5904                         add_reg = ins->dreg;
5905                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5906                                                                    add_reg, 0);
5907 #else
5908                         int mult_reg = alloc_preg (cfg);
5909                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, index_reg, 1);
5910                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
5911                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5912                                                                    add_reg, MONO_STRUCT_OFFSET (MonoString, chars));
5913 #endif
5914                         type_from_op (cfg, ins, NULL, NULL);
5915                         return ins;
5916                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count + fsig->hasthis == 1) {
5917                         int dreg = alloc_ireg (cfg);
5918                         /* Decompose later to allow more optimizations */
5919                         EMIT_NEW_UNALU (cfg, ins, OP_STRLEN, dreg, args [0]->dreg);
5920                         ins->type = STACK_I4;
5921                         ins->flags |= MONO_INST_FAULT;
5922                         cfg->cbb->has_array_access = TRUE;
5923                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
5924
5925                         return ins;
5926                 } else 
5927                         return NULL;
5928         } else if (cmethod->klass == mono_defaults.object_class) {
5929
5930                 if (strcmp (cmethod->name, "GetType") == 0 && fsig->param_count + fsig->hasthis == 1) {
5931                         int dreg = alloc_ireg_ref (cfg);
5932                         int vt_reg = alloc_preg (cfg);
5933                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vt_reg, args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
5934                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, vt_reg, MONO_STRUCT_OFFSET (MonoVTable, type));
5935                         type_from_op (cfg, ins, NULL, NULL);
5936
5937                         return ins;
5938                 } else if (!cfg->backend->emulate_mul_div && strcmp (cmethod->name, "InternalGetHashCode") == 0 && fsig->param_count == 1 && !mono_gc_is_moving ()) {
5939                         int dreg = alloc_ireg (cfg);
5940                         int t1 = alloc_ireg (cfg);
5941         
5942                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, t1, args [0]->dreg, 3);
5943                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_MUL_IMM, dreg, t1, 2654435761u);
5944                         ins->type = STACK_I4;
5945
5946                         return ins;
5947                 } else if (strcmp (cmethod->name, ".ctor") == 0 && fsig->param_count == 0) {
5948                         MONO_INST_NEW (cfg, ins, OP_NOP);
5949                         MONO_ADD_INS (cfg->cbb, ins);
5950                         return ins;
5951                 } else
5952                         return NULL;
5953         } else if (cmethod->klass == mono_defaults.array_class) {
5954                 if (strcmp (cmethod->name, "GetGenericValueImpl") == 0 && fsig->param_count + fsig->hasthis == 3 && !cfg->gsharedvt)
5955                         return emit_array_generic_access (cfg, fsig, args, FALSE);
5956                 else if (strcmp (cmethod->name, "SetGenericValueImpl") == 0 && fsig->param_count + fsig->hasthis == 3 && !cfg->gsharedvt)
5957                         return emit_array_generic_access (cfg, fsig, args, TRUE);
5958
5959 #ifndef MONO_BIG_ARRAYS
5960                 /*
5961                  * This is an inline version of GetLength/GetLowerBound(0) used frequently in
5962                  * Array methods.
5963                  */
5964                 else if (((strcmp (cmethod->name, "GetLength") == 0 && fsig->param_count + fsig->hasthis == 2) ||
5965                          (strcmp (cmethod->name, "GetLowerBound") == 0 && fsig->param_count + fsig->hasthis == 2)) &&
5966                          args [1]->opcode == OP_ICONST && args [1]->inst_c0 == 0) {
5967                         int dreg = alloc_ireg (cfg);
5968                         int bounds_reg = alloc_ireg_mp (cfg);
5969                         MonoBasicBlock *end_bb, *szarray_bb;
5970                         gboolean get_length = strcmp (cmethod->name, "GetLength") == 0;
5971
5972                         NEW_BBLOCK (cfg, end_bb);
5973                         NEW_BBLOCK (cfg, szarray_bb);
5974
5975                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOAD_MEMBASE, bounds_reg,
5976                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
5977                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
5978                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, szarray_bb);
5979                         /* Non-szarray case */
5980                         if (get_length)
5981                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5982                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5983                         else
5984                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5985                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5986                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
5987                         MONO_START_BB (cfg, szarray_bb);
5988                         /* Szarray case */
5989                         if (get_length)
5990                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5991                                                                            args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
5992                         else
5993                                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
5994                         MONO_START_BB (cfg, end_bb);
5995
5996                         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, dreg, dreg);
5997                         ins->type = STACK_I4;
5998                         
5999                         return ins;
6000                 }
6001 #endif
6002
6003                 if (cmethod->name [0] != 'g')
6004                         return NULL;
6005
6006                 if (strcmp (cmethod->name, "get_Rank") == 0 && fsig->param_count + fsig->hasthis == 1) {
6007                         int dreg = alloc_ireg (cfg);
6008                         int vtable_reg = alloc_preg (cfg);
6009                         MONO_EMIT_NEW_LOAD_MEMBASE_OP_FAULT (cfg, OP_LOAD_MEMBASE, vtable_reg, 
6010                                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
6011                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU1_MEMBASE, dreg,
6012                                                                    vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
6013                         type_from_op (cfg, ins, NULL, NULL);
6014
6015                         return ins;
6016                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count + fsig->hasthis == 1) {
6017                         int dreg = alloc_ireg (cfg);
6018
6019                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOADI4_MEMBASE, dreg, 
6020                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
6021                         type_from_op (cfg, ins, NULL, NULL);
6022
6023                         return ins;
6024                 } else
6025                         return NULL;
6026         } else if (cmethod->klass == runtime_helpers_class) {
6027
6028                 if (strcmp (cmethod->name, "get_OffsetToStringData") == 0 && fsig->param_count == 0) {
6029                         EMIT_NEW_ICONST (cfg, ins, MONO_STRUCT_OFFSET (MonoString, chars));
6030                         return ins;
6031                 } else
6032                         return NULL;
6033         } else if (cmethod->klass == mono_defaults.thread_class) {
6034                 if (strcmp (cmethod->name, "SpinWait_nop") == 0 && fsig->param_count == 0) {
6035                         MONO_INST_NEW (cfg, ins, OP_RELAXED_NOP);
6036                         MONO_ADD_INS (cfg->cbb, ins);
6037                         return ins;
6038                 } else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0) {
6039                         return emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6040                 } else if (!strcmp (cmethod->name, "VolatileRead") && fsig->param_count == 1) {
6041                         guint32 opcode = 0;
6042                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6043
6044                         if (fsig->params [0]->type == MONO_TYPE_I1)
6045                                 opcode = OP_LOADI1_MEMBASE;
6046                         else if (fsig->params [0]->type == MONO_TYPE_U1)
6047                                 opcode = OP_LOADU1_MEMBASE;
6048                         else if (fsig->params [0]->type == MONO_TYPE_I2)
6049                                 opcode = OP_LOADI2_MEMBASE;
6050                         else if (fsig->params [0]->type == MONO_TYPE_U2)
6051                                 opcode = OP_LOADU2_MEMBASE;
6052                         else if (fsig->params [0]->type == MONO_TYPE_I4)
6053                                 opcode = OP_LOADI4_MEMBASE;
6054                         else if (fsig->params [0]->type == MONO_TYPE_U4)
6055                                 opcode = OP_LOADU4_MEMBASE;
6056                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
6057                                 opcode = OP_LOADI8_MEMBASE;
6058                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6059                                 opcode = OP_LOADR4_MEMBASE;
6060                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6061                                 opcode = OP_LOADR8_MEMBASE;
6062                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
6063                                 opcode = OP_LOAD_MEMBASE;
6064
6065                         if (opcode) {
6066                                 MONO_INST_NEW (cfg, ins, opcode);
6067                                 ins->inst_basereg = args [0]->dreg;
6068                                 ins->inst_offset = 0;
6069                                 MONO_ADD_INS (cfg->cbb, ins);
6070
6071                                 switch (fsig->params [0]->type) {
6072                                 case MONO_TYPE_I1:
6073                                 case MONO_TYPE_U1:
6074                                 case MONO_TYPE_I2:
6075                                 case MONO_TYPE_U2:
6076                                 case MONO_TYPE_I4:
6077                                 case MONO_TYPE_U4:
6078                                         ins->dreg = mono_alloc_ireg (cfg);
6079                                         ins->type = STACK_I4;
6080                                         break;
6081                                 case MONO_TYPE_I8:
6082                                 case MONO_TYPE_U8:
6083                                         ins->dreg = mono_alloc_lreg (cfg);
6084                                         ins->type = STACK_I8;
6085                                         break;
6086                                 case MONO_TYPE_I:
6087                                 case MONO_TYPE_U:
6088                                         ins->dreg = mono_alloc_ireg (cfg);
6089 #if SIZEOF_REGISTER == 8
6090                                         ins->type = STACK_I8;
6091 #else
6092                                         ins->type = STACK_I4;
6093 #endif
6094                                         break;
6095                                 case MONO_TYPE_R4:
6096                                 case MONO_TYPE_R8:
6097                                         ins->dreg = mono_alloc_freg (cfg);
6098                                         ins->type = STACK_R8;
6099                                         break;
6100                                 default:
6101                                         g_assert (mini_type_is_reference (fsig->params [0]));
6102                                         ins->dreg = mono_alloc_ireg_ref (cfg);
6103                                         ins->type = STACK_OBJ;
6104                                         break;
6105                                 }
6106
6107                                 if (opcode == OP_LOADI8_MEMBASE)
6108                                         ins = mono_decompose_opcode (cfg, ins);
6109
6110                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
6111
6112                                 return ins;
6113                         }
6114                 } else if (!strcmp (cmethod->name, "VolatileWrite") && fsig->param_count == 2) {
6115                         guint32 opcode = 0;
6116                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6117
6118                         if (fsig->params [0]->type == MONO_TYPE_I1 || fsig->params [0]->type == MONO_TYPE_U1)
6119                                 opcode = OP_STOREI1_MEMBASE_REG;
6120                         else if (fsig->params [0]->type == MONO_TYPE_I2 || fsig->params [0]->type == MONO_TYPE_U2)
6121                                 opcode = OP_STOREI2_MEMBASE_REG;
6122                         else if (fsig->params [0]->type == MONO_TYPE_I4 || fsig->params [0]->type == MONO_TYPE_U4)
6123                                 opcode = OP_STOREI4_MEMBASE_REG;
6124                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
6125                                 opcode = OP_STOREI8_MEMBASE_REG;
6126                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6127                                 opcode = OP_STORER4_MEMBASE_REG;
6128                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6129                                 opcode = OP_STORER8_MEMBASE_REG;
6130                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
6131                                 opcode = OP_STORE_MEMBASE_REG;
6132
6133                         if (opcode) {
6134                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
6135
6136                                 MONO_INST_NEW (cfg, ins, opcode);
6137                                 ins->sreg1 = args [1]->dreg;
6138                                 ins->inst_destbasereg = args [0]->dreg;
6139                                 ins->inst_offset = 0;
6140                                 MONO_ADD_INS (cfg->cbb, ins);
6141
6142                                 if (opcode == OP_STOREI8_MEMBASE_REG)
6143                                         ins = mono_decompose_opcode (cfg, ins);
6144
6145                                 return ins;
6146                         }
6147                 }
6148         } else if (cmethod->klass->image == mono_defaults.corlib &&
6149                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
6150                            (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
6151                 ins = NULL;
6152
6153 #if SIZEOF_REGISTER == 8
6154                 if (!cfg->llvm_only && strcmp (cmethod->name, "Read") == 0 && fsig->param_count == 1 && (fsig->params [0]->type == MONO_TYPE_I8)) {
6155                         if (!cfg->llvm_only && mono_arch_opcode_supported (OP_ATOMIC_LOAD_I8)) {
6156                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_LOAD_I8);
6157                                 ins->dreg = mono_alloc_preg (cfg);
6158                                 ins->sreg1 = args [0]->dreg;
6159                                 ins->type = STACK_I8;
6160                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_SEQ;
6161                                 MONO_ADD_INS (cfg->cbb, ins);
6162                         } else {
6163                                 MonoInst *load_ins;
6164
6165                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6166
6167                                 /* 64 bit reads are already atomic */
6168                                 MONO_INST_NEW (cfg, load_ins, OP_LOADI8_MEMBASE);
6169                                 load_ins->dreg = mono_alloc_preg (cfg);
6170                                 load_ins->inst_basereg = args [0]->dreg;
6171                                 load_ins->inst_offset = 0;
6172                                 load_ins->type = STACK_I8;
6173                                 MONO_ADD_INS (cfg->cbb, load_ins);
6174
6175                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6176
6177                                 ins = load_ins;
6178                         }
6179                 }
6180 #endif
6181
6182                 if (strcmp (cmethod->name, "Increment") == 0 && fsig->param_count == 1) {
6183                         MonoInst *ins_iconst;
6184                         guint32 opcode = 0;
6185
6186                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6187                                 opcode = OP_ATOMIC_ADD_I4;
6188                                 cfg->has_atomic_add_i4 = TRUE;
6189                         }
6190 #if SIZEOF_REGISTER == 8
6191                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6192                                 opcode = OP_ATOMIC_ADD_I8;
6193 #endif
6194                         if (opcode) {
6195                                 if (!mono_arch_opcode_supported (opcode))
6196                                         return NULL;
6197                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
6198                                 ins_iconst->inst_c0 = 1;
6199                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
6200                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
6201
6202                                 MONO_INST_NEW (cfg, ins, opcode);
6203                                 ins->dreg = mono_alloc_ireg (cfg);
6204                                 ins->inst_basereg = args [0]->dreg;
6205                                 ins->inst_offset = 0;
6206                                 ins->sreg2 = ins_iconst->dreg;
6207                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6208                                 MONO_ADD_INS (cfg->cbb, ins);
6209                         }
6210                 } else if (strcmp (cmethod->name, "Decrement") == 0 && fsig->param_count == 1) {
6211                         MonoInst *ins_iconst;
6212                         guint32 opcode = 0;
6213
6214                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6215                                 opcode = OP_ATOMIC_ADD_I4;
6216                                 cfg->has_atomic_add_i4 = TRUE;
6217                         }
6218 #if SIZEOF_REGISTER == 8
6219                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6220                                 opcode = OP_ATOMIC_ADD_I8;
6221 #endif
6222                         if (opcode) {
6223                                 if (!mono_arch_opcode_supported (opcode))
6224                                         return NULL;
6225                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
6226                                 ins_iconst->inst_c0 = -1;
6227                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
6228                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
6229
6230                                 MONO_INST_NEW (cfg, ins, opcode);
6231                                 ins->dreg = mono_alloc_ireg (cfg);
6232                                 ins->inst_basereg = args [0]->dreg;
6233                                 ins->inst_offset = 0;
6234                                 ins->sreg2 = ins_iconst->dreg;
6235                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6236                                 MONO_ADD_INS (cfg->cbb, ins);
6237                         }
6238                 } else if (strcmp (cmethod->name, "Add") == 0 && fsig->param_count == 2) {
6239                         guint32 opcode = 0;
6240
6241                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6242                                 opcode = OP_ATOMIC_ADD_I4;
6243                                 cfg->has_atomic_add_i4 = TRUE;
6244                         }
6245 #if SIZEOF_REGISTER == 8
6246                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6247                                 opcode = OP_ATOMIC_ADD_I8;
6248 #endif
6249                         if (opcode) {
6250                                 if (!mono_arch_opcode_supported (opcode))
6251                                         return NULL;
6252                                 MONO_INST_NEW (cfg, ins, opcode);
6253                                 ins->dreg = mono_alloc_ireg (cfg);
6254                                 ins->inst_basereg = args [0]->dreg;
6255                                 ins->inst_offset = 0;
6256                                 ins->sreg2 = args [1]->dreg;
6257                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6258                                 MONO_ADD_INS (cfg->cbb, ins);
6259                         }
6260                 }
6261                 else if (strcmp (cmethod->name, "Exchange") == 0 && fsig->param_count == 2) {
6262                         MonoInst *f2i = NULL, *i2f;
6263                         guint32 opcode, f2i_opcode, i2f_opcode;
6264                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6265                         gboolean is_float = fsig->params [0]->type == MONO_TYPE_R4 || fsig->params [0]->type == MONO_TYPE_R8;
6266
6267                         if (fsig->params [0]->type == MONO_TYPE_I4 ||
6268                             fsig->params [0]->type == MONO_TYPE_R4) {
6269                                 opcode = OP_ATOMIC_EXCHANGE_I4;
6270                                 f2i_opcode = OP_MOVE_F_TO_I4;
6271                                 i2f_opcode = OP_MOVE_I4_TO_F;
6272                                 cfg->has_atomic_exchange_i4 = TRUE;
6273                         }
6274 #if SIZEOF_REGISTER == 8
6275                         else if (is_ref ||
6276                                  fsig->params [0]->type == MONO_TYPE_I8 ||
6277                                  fsig->params [0]->type == MONO_TYPE_R8 ||
6278                                  fsig->params [0]->type == MONO_TYPE_I) {
6279                                 opcode = OP_ATOMIC_EXCHANGE_I8;
6280                                 f2i_opcode = OP_MOVE_F_TO_I8;
6281                                 i2f_opcode = OP_MOVE_I8_TO_F;
6282                         }
6283 #else
6284                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I) {
6285                                 opcode = OP_ATOMIC_EXCHANGE_I4;
6286                                 cfg->has_atomic_exchange_i4 = TRUE;
6287                         }
6288 #endif
6289                         else
6290                                 return NULL;
6291
6292                         if (!mono_arch_opcode_supported (opcode))
6293                                 return NULL;
6294
6295                         if (is_float) {
6296                                 /* TODO: Decompose these opcodes instead of bailing here. */
6297                                 if (COMPILE_SOFT_FLOAT (cfg))
6298                                         return NULL;
6299
6300                                 MONO_INST_NEW (cfg, f2i, f2i_opcode);
6301                                 f2i->dreg = mono_alloc_ireg (cfg);
6302                                 f2i->sreg1 = args [1]->dreg;
6303                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6304                                         f2i->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6305                                 MONO_ADD_INS (cfg->cbb, f2i);
6306                         }
6307
6308                         MONO_INST_NEW (cfg, ins, opcode);
6309                         ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : mono_alloc_ireg (cfg);
6310                         ins->inst_basereg = args [0]->dreg;
6311                         ins->inst_offset = 0;
6312                         ins->sreg2 = is_float ? f2i->dreg : args [1]->dreg;
6313                         MONO_ADD_INS (cfg->cbb, ins);
6314
6315                         switch (fsig->params [0]->type) {
6316                         case MONO_TYPE_I4:
6317                                 ins->type = STACK_I4;
6318                                 break;
6319                         case MONO_TYPE_I8:
6320                                 ins->type = STACK_I8;
6321                                 break;
6322                         case MONO_TYPE_I:
6323 #if SIZEOF_REGISTER == 8
6324                                 ins->type = STACK_I8;
6325 #else
6326                                 ins->type = STACK_I4;
6327 #endif
6328                                 break;
6329                         case MONO_TYPE_R4:
6330                         case MONO_TYPE_R8:
6331                                 ins->type = STACK_R8;
6332                                 break;
6333                         default:
6334                                 g_assert (mini_type_is_reference (fsig->params [0]));
6335                                 ins->type = STACK_OBJ;
6336                                 break;
6337                         }
6338
6339                         if (is_float) {
6340                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
6341                                 i2f->dreg = mono_alloc_freg (cfg);
6342                                 i2f->sreg1 = ins->dreg;
6343                                 i2f->type = STACK_R8;
6344                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
6345                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6346                                 MONO_ADD_INS (cfg->cbb, i2f);
6347
6348                                 ins = i2f;
6349                         }
6350
6351                         if (cfg->gen_write_barriers && is_ref)
6352                                 emit_write_barrier (cfg, args [0], args [1]);
6353                 }
6354                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 3) {
6355                         MonoInst *f2i_new = NULL, *f2i_cmp = NULL, *i2f;
6356                         guint32 opcode, f2i_opcode, i2f_opcode;
6357                         gboolean is_ref = mini_type_is_reference (fsig->params [1]);
6358                         gboolean is_float = fsig->params [1]->type == MONO_TYPE_R4 || fsig->params [1]->type == MONO_TYPE_R8;
6359
6360                         if (fsig->params [1]->type == MONO_TYPE_I4 ||
6361                             fsig->params [1]->type == MONO_TYPE_R4) {
6362                                 opcode = OP_ATOMIC_CAS_I4;
6363                                 f2i_opcode = OP_MOVE_F_TO_I4;
6364                                 i2f_opcode = OP_MOVE_I4_TO_F;
6365                                 cfg->has_atomic_cas_i4 = TRUE;
6366                         }
6367 #if SIZEOF_REGISTER == 8
6368                         else if (is_ref ||
6369                                  fsig->params [1]->type == MONO_TYPE_I8 ||
6370                                  fsig->params [1]->type == MONO_TYPE_R8 ||
6371                                  fsig->params [1]->type == MONO_TYPE_I) {
6372                                 opcode = OP_ATOMIC_CAS_I8;
6373                                 f2i_opcode = OP_MOVE_F_TO_I8;
6374                                 i2f_opcode = OP_MOVE_I8_TO_F;
6375                         }
6376 #else
6377                         else if (is_ref || fsig->params [1]->type == MONO_TYPE_I) {
6378                                 opcode = OP_ATOMIC_CAS_I4;
6379                                 cfg->has_atomic_cas_i4 = TRUE;
6380                         }
6381 #endif
6382                         else
6383                                 return NULL;
6384
6385                         if (!mono_arch_opcode_supported (opcode))
6386                                 return NULL;
6387
6388                         if (is_float) {
6389                                 /* TODO: Decompose these opcodes instead of bailing here. */
6390                                 if (COMPILE_SOFT_FLOAT (cfg))
6391                                         return NULL;
6392
6393                                 MONO_INST_NEW (cfg, f2i_new, f2i_opcode);
6394                                 f2i_new->dreg = mono_alloc_ireg (cfg);
6395                                 f2i_new->sreg1 = args [1]->dreg;
6396                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6397                                         f2i_new->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6398                                 MONO_ADD_INS (cfg->cbb, f2i_new);
6399
6400                                 MONO_INST_NEW (cfg, f2i_cmp, f2i_opcode);
6401                                 f2i_cmp->dreg = mono_alloc_ireg (cfg);
6402                                 f2i_cmp->sreg1 = args [2]->dreg;
6403                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6404                                         f2i_cmp->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6405                                 MONO_ADD_INS (cfg->cbb, f2i_cmp);
6406                         }
6407
6408                         MONO_INST_NEW (cfg, ins, opcode);
6409                         ins->dreg = is_ref ? alloc_ireg_ref (cfg) : alloc_ireg (cfg);
6410                         ins->sreg1 = args [0]->dreg;
6411                         ins->sreg2 = is_float ? f2i_new->dreg : args [1]->dreg;
6412                         ins->sreg3 = is_float ? f2i_cmp->dreg : args [2]->dreg;
6413                         MONO_ADD_INS (cfg->cbb, ins);
6414
6415                         switch (fsig->params [1]->type) {
6416                         case MONO_TYPE_I4:
6417                                 ins->type = STACK_I4;
6418                                 break;
6419                         case MONO_TYPE_I8:
6420                                 ins->type = STACK_I8;
6421                                 break;
6422                         case MONO_TYPE_I:
6423 #if SIZEOF_REGISTER == 8
6424                                 ins->type = STACK_I8;
6425 #else
6426                                 ins->type = STACK_I4;
6427 #endif
6428                                 break;
6429                         case MONO_TYPE_R4:
6430                                 ins->type = cfg->r4_stack_type;
6431                                 break;
6432                         case MONO_TYPE_R8:
6433                                 ins->type = STACK_R8;
6434                                 break;
6435                         default:
6436                                 g_assert (mini_type_is_reference (fsig->params [1]));
6437                                 ins->type = STACK_OBJ;
6438                                 break;
6439                         }
6440
6441                         if (is_float) {
6442                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
6443                                 i2f->dreg = mono_alloc_freg (cfg);
6444                                 i2f->sreg1 = ins->dreg;
6445                                 i2f->type = STACK_R8;
6446                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
6447                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6448                                 MONO_ADD_INS (cfg->cbb, i2f);
6449
6450                                 ins = i2f;
6451                         }
6452
6453                         if (cfg->gen_write_barriers && is_ref)
6454                                 emit_write_barrier (cfg, args [0], args [1]);
6455                 }
6456                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 4 &&
6457                          fsig->params [1]->type == MONO_TYPE_I4) {
6458                         MonoInst *cmp, *ceq;
6459
6460                         if (!mono_arch_opcode_supported (OP_ATOMIC_CAS_I4))
6461                                 return NULL;
6462
6463                         /* int32 r = CAS (location, value, comparand); */
6464                         MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I4);
6465                         ins->dreg = alloc_ireg (cfg);
6466                         ins->sreg1 = args [0]->dreg;
6467                         ins->sreg2 = args [1]->dreg;
6468                         ins->sreg3 = args [2]->dreg;
6469                         ins->type = STACK_I4;
6470                         MONO_ADD_INS (cfg->cbb, ins);
6471
6472                         /* bool result = r == comparand; */
6473                         MONO_INST_NEW (cfg, cmp, OP_ICOMPARE);
6474                         cmp->sreg1 = ins->dreg;
6475                         cmp->sreg2 = args [2]->dreg;
6476                         cmp->type = STACK_I4;
6477                         MONO_ADD_INS (cfg->cbb, cmp);
6478
6479                         MONO_INST_NEW (cfg, ceq, OP_ICEQ);
6480                         ceq->dreg = alloc_ireg (cfg);
6481                         ceq->type = STACK_I4;
6482                         MONO_ADD_INS (cfg->cbb, ceq);
6483
6484                         /* *success = result; */
6485                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, args [3]->dreg, 0, ceq->dreg);
6486
6487                         cfg->has_atomic_cas_i4 = TRUE;
6488                 }
6489                 else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0)
6490                         ins = emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6491
6492                 if (ins)
6493                         return ins;
6494         } else if (cmethod->klass->image == mono_defaults.corlib &&
6495                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
6496                            (strcmp (cmethod->klass->name, "Volatile") == 0)) {
6497                 ins = NULL;
6498
6499                 if (!cfg->llvm_only && !strcmp (cmethod->name, "Read") && fsig->param_count == 1) {
6500                         guint32 opcode = 0;
6501                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6502                         gboolean is_float = fsig->params [0]->type == MONO_TYPE_R4 || fsig->params [0]->type == MONO_TYPE_R8;
6503
6504                         if (fsig->params [0]->type == MONO_TYPE_I1)
6505                                 opcode = OP_ATOMIC_LOAD_I1;
6506                         else if (fsig->params [0]->type == MONO_TYPE_U1 || fsig->params [0]->type == MONO_TYPE_BOOLEAN)
6507                                 opcode = OP_ATOMIC_LOAD_U1;
6508                         else if (fsig->params [0]->type == MONO_TYPE_I2)
6509                                 opcode = OP_ATOMIC_LOAD_I2;
6510                         else if (fsig->params [0]->type == MONO_TYPE_U2)
6511                                 opcode = OP_ATOMIC_LOAD_U2;
6512                         else if (fsig->params [0]->type == MONO_TYPE_I4)
6513                                 opcode = OP_ATOMIC_LOAD_I4;
6514                         else if (fsig->params [0]->type == MONO_TYPE_U4)
6515                                 opcode = OP_ATOMIC_LOAD_U4;
6516                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6517                                 opcode = OP_ATOMIC_LOAD_R4;
6518                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6519                                 opcode = OP_ATOMIC_LOAD_R8;
6520 #if SIZEOF_REGISTER == 8
6521                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_I)
6522                                 opcode = OP_ATOMIC_LOAD_I8;
6523                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_U8 || fsig->params [0]->type == MONO_TYPE_U)
6524                                 opcode = OP_ATOMIC_LOAD_U8;
6525 #else
6526                         else if (fsig->params [0]->type == MONO_TYPE_I)
6527                                 opcode = OP_ATOMIC_LOAD_I4;
6528                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_U)
6529                                 opcode = OP_ATOMIC_LOAD_U4;
6530 #endif
6531
6532                         if (opcode) {
6533                                 if (!mono_arch_opcode_supported (opcode))
6534                                         return NULL;
6535
6536                                 MONO_INST_NEW (cfg, ins, opcode);
6537                                 ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : (is_float ? mono_alloc_freg (cfg) : mono_alloc_ireg (cfg));
6538                                 ins->sreg1 = args [0]->dreg;
6539                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_ACQ;
6540                                 MONO_ADD_INS (cfg->cbb, ins);
6541
6542                                 switch (fsig->params [0]->type) {
6543                                 case MONO_TYPE_BOOLEAN:
6544                                 case MONO_TYPE_I1:
6545                                 case MONO_TYPE_U1:
6546                                 case MONO_TYPE_I2:
6547                                 case MONO_TYPE_U2:
6548                                 case MONO_TYPE_I4:
6549                                 case MONO_TYPE_U4:
6550                                         ins->type = STACK_I4;
6551                                         break;
6552                                 case MONO_TYPE_I8:
6553                                 case MONO_TYPE_U8:
6554                                         ins->type = STACK_I8;
6555                                         break;
6556                                 case MONO_TYPE_I:
6557                                 case MONO_TYPE_U:
6558 #if SIZEOF_REGISTER == 8
6559                                         ins->type = STACK_I8;
6560 #else
6561                                         ins->type = STACK_I4;
6562 #endif
6563                                         break;
6564                                 case MONO_TYPE_R4:
6565                                         ins->type = cfg->r4_stack_type;
6566                                         break;
6567                                 case MONO_TYPE_R8:
6568                                         ins->type = STACK_R8;
6569                                         break;
6570                                 default:
6571                                         g_assert (mini_type_is_reference (fsig->params [0]));
6572                                         ins->type = STACK_OBJ;
6573                                         break;
6574                                 }
6575                         }
6576                 }
6577
6578                 if (!cfg->llvm_only && !strcmp (cmethod->name, "Write") && fsig->param_count == 2) {
6579                         guint32 opcode = 0;
6580                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6581
6582                         if (fsig->params [0]->type == MONO_TYPE_I1)
6583                                 opcode = OP_ATOMIC_STORE_I1;
6584                         else if (fsig->params [0]->type == MONO_TYPE_U1 || fsig->params [0]->type == MONO_TYPE_BOOLEAN)
6585                                 opcode = OP_ATOMIC_STORE_U1;
6586                         else if (fsig->params [0]->type == MONO_TYPE_I2)
6587                                 opcode = OP_ATOMIC_STORE_I2;
6588                         else if (fsig->params [0]->type == MONO_TYPE_U2)
6589                                 opcode = OP_ATOMIC_STORE_U2;
6590                         else if (fsig->params [0]->type == MONO_TYPE_I4)
6591                                 opcode = OP_ATOMIC_STORE_I4;
6592                         else if (fsig->params [0]->type == MONO_TYPE_U4)
6593                                 opcode = OP_ATOMIC_STORE_U4;
6594                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6595                                 opcode = OP_ATOMIC_STORE_R4;
6596                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6597                                 opcode = OP_ATOMIC_STORE_R8;
6598 #if SIZEOF_REGISTER == 8
6599                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_I)
6600                                 opcode = OP_ATOMIC_STORE_I8;
6601                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_U8 || fsig->params [0]->type == MONO_TYPE_U)
6602                                 opcode = OP_ATOMIC_STORE_U8;
6603 #else
6604                         else if (fsig->params [0]->type == MONO_TYPE_I)
6605                                 opcode = OP_ATOMIC_STORE_I4;
6606                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_U)
6607                                 opcode = OP_ATOMIC_STORE_U4;
6608 #endif
6609
6610                         if (opcode) {
6611                                 if (!mono_arch_opcode_supported (opcode))
6612                                         return NULL;
6613
6614                                 MONO_INST_NEW (cfg, ins, opcode);
6615                                 ins->dreg = args [0]->dreg;
6616                                 ins->sreg1 = args [1]->dreg;
6617                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_REL;
6618                                 MONO_ADD_INS (cfg->cbb, ins);
6619
6620                                 if (cfg->gen_write_barriers && is_ref)
6621                                         emit_write_barrier (cfg, args [0], args [1]);
6622                         }
6623                 }
6624
6625                 if (ins)
6626                         return ins;
6627         } else if (cmethod->klass->image == mono_defaults.corlib &&
6628                            (strcmp (cmethod->klass->name_space, "System.Diagnostics") == 0) &&
6629                            (strcmp (cmethod->klass->name, "Debugger") == 0)) {
6630                 if (!strcmp (cmethod->name, "Break") && fsig->param_count == 0) {
6631                         if (should_insert_brekpoint (cfg->method)) {
6632                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
6633                         } else {
6634                                 MONO_INST_NEW (cfg, ins, OP_NOP);
6635                                 MONO_ADD_INS (cfg->cbb, ins);
6636                         }
6637                         return ins;
6638                 }
6639         } else if (cmethod->klass->image == mono_defaults.corlib &&
6640                    (strcmp (cmethod->klass->name_space, "System") == 0) &&
6641                    (strcmp (cmethod->klass->name, "Environment") == 0)) {
6642                 if (!strcmp (cmethod->name, "get_IsRunningOnWindows") && fsig->param_count == 0) {
6643 #ifdef TARGET_WIN32
6644                         EMIT_NEW_ICONST (cfg, ins, 1);
6645 #else
6646                         EMIT_NEW_ICONST (cfg, ins, 0);
6647 #endif
6648                 }
6649         } else if (cmethod->klass->image == mono_defaults.corlib &&
6650                            (strcmp (cmethod->klass->name_space, "System.Reflection") == 0) &&
6651                            (strcmp (cmethod->klass->name, "Assembly") == 0)) {
6652                 if (cfg->llvm_only && !strcmp (cmethod->name, "GetExecutingAssembly")) {
6653                         /* No stack walks are current available, so implement this as an intrinsic */
6654                         MonoInst *assembly_ins;
6655
6656                         EMIT_NEW_AOTCONST (cfg, assembly_ins, MONO_PATCH_INFO_IMAGE, cfg->method->klass->image);
6657                         ins = mono_emit_jit_icall (cfg, mono_get_assembly_object, &assembly_ins);
6658                         return ins;
6659                 }
6660         } else if (cmethod->klass == mono_defaults.math_class) {
6661                 /* 
6662                  * There is general branchless code for Min/Max, but it does not work for 
6663                  * all inputs:
6664                  * http://everything2.com/?node_id=1051618
6665                  */
6666         } else if (((!strcmp (cmethod->klass->image->assembly->aname.name, "MonoMac") ||
6667                     !strcmp (cmethod->klass->image->assembly->aname.name, "monotouch")) &&
6668                                 !strcmp (cmethod->klass->name_space, "XamCore.ObjCRuntime") &&
6669                                 !strcmp (cmethod->klass->name, "Selector")) ||
6670                            (!strcmp (cmethod->klass->image->assembly->aname.name, "Xamarin.iOS") &&
6671                                 !strcmp (cmethod->klass->name_space, "ObjCRuntime") &&
6672                                 !strcmp (cmethod->klass->name, "Selector"))
6673                            ) {
6674                 if (cfg->backend->have_objc_get_selector &&
6675                         !strcmp (cmethod->name, "GetHandle") && fsig->param_count == 1 &&
6676                     (args [0]->opcode == OP_GOT_ENTRY || args [0]->opcode == OP_AOTCONST) &&
6677                     cfg->compile_aot) {
6678                         MonoInst *pi;
6679                         MonoJumpInfoToken *ji;
6680                         MonoString *s;
6681
6682                         cfg->disable_llvm = TRUE;
6683
6684                         if (args [0]->opcode == OP_GOT_ENTRY) {
6685                                 pi = args [0]->inst_p1;
6686                                 g_assert (pi->opcode == OP_PATCH_INFO);
6687                                 g_assert (GPOINTER_TO_INT (pi->inst_p1) == MONO_PATCH_INFO_LDSTR);
6688                                 ji = pi->inst_p0;
6689                         } else {
6690                                 g_assert (GPOINTER_TO_INT (args [0]->inst_p1) == MONO_PATCH_INFO_LDSTR);
6691                                 ji = args [0]->inst_p0;
6692                         }
6693
6694                         NULLIFY_INS (args [0]);
6695
6696                         // FIXME: Ugly
6697                         s = mono_ldstr (cfg->domain, ji->image, mono_metadata_token_index (ji->token));
6698                         MONO_INST_NEW (cfg, ins, OP_OBJC_GET_SELECTOR);
6699                         ins->dreg = mono_alloc_ireg (cfg);
6700                         // FIXME: Leaks
6701                         ins->inst_p0 = mono_string_to_utf8 (s);
6702                         MONO_ADD_INS (cfg->cbb, ins);
6703                         return ins;
6704                 }
6705         }
6706
6707 #ifdef MONO_ARCH_SIMD_INTRINSICS
6708         if (cfg->opt & MONO_OPT_SIMD) {
6709                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
6710                 if (ins)
6711                         return ins;
6712         }
6713 #endif
6714
6715         ins = mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
6716         if (ins)
6717                 return ins;
6718
6719         if (COMPILE_LLVM (cfg)) {
6720                 ins = llvm_emit_inst_for_method (cfg, cmethod, fsig, args);
6721                 if (ins)
6722                         return ins;
6723         }
6724
6725         return mono_arch_emit_inst_for_method (cfg, cmethod, fsig, args);
6726 }
6727
6728 /*
6729  * This entry point could be used later for arbitrary method
6730  * redirection.
6731  */
6732 inline static MonoInst*
6733 mini_redirect_call (MonoCompile *cfg, MonoMethod *method,  
6734                                         MonoMethodSignature *signature, MonoInst **args, MonoInst *this_ins)
6735 {
6736         if (method->klass == mono_defaults.string_class) {
6737                 /* managed string allocation support */
6738                 if (strcmp (method->name, "InternalAllocateStr") == 0 && !(mono_profiler_events & MONO_PROFILE_ALLOCATIONS) && !(cfg->opt & MONO_OPT_SHARED)) {
6739                         MonoInst *iargs [2];
6740                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
6741                         MonoMethod *managed_alloc = NULL;
6742
6743                         g_assert (vtable); /*Should not fail since it System.String*/
6744 #ifndef MONO_CROSS_COMPILE
6745                         managed_alloc = mono_gc_get_managed_allocator (method->klass, FALSE, FALSE);
6746 #endif
6747                         if (!managed_alloc)
6748                                 return NULL;
6749                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
6750                         iargs [1] = args [0];
6751                         return mono_emit_method_call (cfg, managed_alloc, iargs, this_ins);
6752                 }
6753         }
6754         return NULL;
6755 }
6756
6757 static void
6758 mono_save_args (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **sp)
6759 {
6760         MonoInst *store, *temp;
6761         int i;
6762
6763         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
6764                 MonoType *argtype = (sig->hasthis && (i == 0)) ? type_from_stack_type (*sp) : sig->params [i - sig->hasthis];
6765
6766                 /*
6767                  * FIXME: We should use *args++ = sp [0], but that would mean the arg
6768                  * would be different than the MonoInst's used to represent arguments, and
6769                  * the ldelema implementation can't deal with that.
6770                  * Solution: When ldelema is used on an inline argument, create a var for 
6771                  * it, emit ldelema on that var, and emit the saving code below in
6772                  * inline_method () if needed.
6773                  */
6774                 temp = mono_compile_create_var (cfg, argtype, OP_LOCAL);
6775                 cfg->args [i] = temp;
6776                 /* This uses cfg->args [i] which is set by the preceeding line */
6777                 EMIT_NEW_ARGSTORE (cfg, store, i, *sp);
6778                 store->cil_code = sp [0]->cil_code;
6779                 sp++;
6780         }
6781 }
6782
6783 #define MONO_INLINE_CALLED_LIMITED_METHODS 1
6784 #define MONO_INLINE_CALLER_LIMITED_METHODS 1
6785
6786 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
6787 static gboolean
6788 check_inline_called_method_name_limit (MonoMethod *called_method)
6789 {
6790         int strncmp_result;
6791         static const char *limit = NULL;
6792         
6793         if (limit == NULL) {
6794                 const char *limit_string = g_getenv ("MONO_INLINE_CALLED_METHOD_NAME_LIMIT");
6795
6796                 if (limit_string != NULL)
6797                         limit = limit_string;
6798                 else
6799                         limit = "";
6800         }
6801
6802         if (limit [0] != '\0') {
6803                 char *called_method_name = mono_method_full_name (called_method, TRUE);
6804
6805                 strncmp_result = strncmp (called_method_name, limit, strlen (limit));
6806                 g_free (called_method_name);
6807         
6808                 //return (strncmp_result <= 0);
6809                 return (strncmp_result == 0);
6810         } else {
6811                 return TRUE;
6812         }
6813 }
6814 #endif
6815
6816 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
6817 static gboolean
6818 check_inline_caller_method_name_limit (MonoMethod *caller_method)
6819 {
6820         int strncmp_result;
6821         static const char *limit = NULL;
6822         
6823         if (limit == NULL) {
6824                 const char *limit_string = g_getenv ("MONO_INLINE_CALLER_METHOD_NAME_LIMIT");
6825                 if (limit_string != NULL) {
6826                         limit = limit_string;
6827                 } else {
6828                         limit = "";
6829                 }
6830         }
6831
6832         if (limit [0] != '\0') {
6833                 char *caller_method_name = mono_method_full_name (caller_method, TRUE);
6834
6835                 strncmp_result = strncmp (caller_method_name, limit, strlen (limit));
6836                 g_free (caller_method_name);
6837         
6838                 //return (strncmp_result <= 0);
6839                 return (strncmp_result == 0);
6840         } else {
6841                 return TRUE;
6842         }
6843 }
6844 #endif
6845
6846 static void
6847 emit_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
6848 {
6849         static double r8_0 = 0.0;
6850         static float r4_0 = 0.0;
6851         MonoInst *ins;
6852         int t;
6853
6854         rtype = mini_get_underlying_type (rtype);
6855         t = rtype->type;
6856
6857         if (rtype->byref) {
6858                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
6859         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
6860                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
6861         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
6862                 MONO_EMIT_NEW_I8CONST (cfg, dreg, 0);
6863         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
6864                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
6865                 ins->type = STACK_R4;
6866                 ins->inst_p0 = (void*)&r4_0;
6867                 ins->dreg = dreg;
6868                 MONO_ADD_INS (cfg->cbb, ins);
6869         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
6870                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
6871                 ins->type = STACK_R8;
6872                 ins->inst_p0 = (void*)&r8_0;
6873                 ins->dreg = dreg;
6874                 MONO_ADD_INS (cfg->cbb, ins);
6875         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
6876                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
6877                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
6878         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (rtype)) {
6879                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
6880         } else {
6881                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
6882         }
6883 }
6884
6885 static void
6886 emit_dummy_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
6887 {
6888         int t;
6889
6890         rtype = mini_get_underlying_type (rtype);
6891         t = rtype->type;
6892
6893         if (rtype->byref) {
6894                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_PCONST);
6895         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
6896                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_ICONST);
6897         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
6898                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_I8CONST);
6899         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
6900                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R4CONST);
6901         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
6902                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R8CONST);
6903         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
6904                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
6905                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
6906         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (rtype)) {
6907                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
6908         } else {
6909                 emit_init_rvar (cfg, dreg, rtype);
6910         }
6911 }
6912
6913 /* If INIT is FALSE, emit dummy initialization statements to keep the IR valid */
6914 static void
6915 emit_init_local (MonoCompile *cfg, int local, MonoType *type, gboolean init)
6916 {
6917         MonoInst *var = cfg->locals [local];
6918         if (COMPILE_SOFT_FLOAT (cfg)) {
6919                 MonoInst *store;
6920                 int reg = alloc_dreg (cfg, var->type);
6921                 emit_init_rvar (cfg, reg, type);
6922                 EMIT_NEW_LOCSTORE (cfg, store, local, cfg->cbb->last_ins);
6923         } else {
6924                 if (init)
6925                         emit_init_rvar (cfg, var->dreg, type);
6926                 else
6927                         emit_dummy_init_rvar (cfg, var->dreg, type);
6928         }
6929 }
6930
6931 /*
6932  * inline_method:
6933  *
6934  *   Return the cost of inlining CMETHOD.
6935  */
6936 static int
6937 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
6938                            guchar *ip, guint real_offset, gboolean inline_always)
6939 {
6940         MonoInst *ins, *rvar = NULL;
6941         MonoMethodHeader *cheader;
6942         MonoBasicBlock *ebblock, *sbblock;
6943         int i, costs;
6944         MonoMethod *prev_inlined_method;
6945         MonoInst **prev_locals, **prev_args;
6946         MonoType **prev_arg_types;
6947         guint prev_real_offset;
6948         GHashTable *prev_cbb_hash;
6949         MonoBasicBlock **prev_cil_offset_to_bb;
6950         MonoBasicBlock *prev_cbb;
6951         unsigned char* prev_cil_start;
6952         guint32 prev_cil_offset_to_bb_len;
6953         MonoMethod *prev_current_method;
6954         MonoGenericContext *prev_generic_context;
6955         gboolean ret_var_set, prev_ret_var_set, prev_disable_inline, virtual = FALSE;
6956
6957         g_assert (cfg->exception_type == MONO_EXCEPTION_NONE);
6958
6959 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
6960         if ((! inline_always) && ! check_inline_called_method_name_limit (cmethod))
6961                 return 0;
6962 #endif
6963 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
6964         if ((! inline_always) && ! check_inline_caller_method_name_limit (cfg->method))
6965                 return 0;
6966 #endif
6967
6968         if (!fsig)
6969                 fsig = mono_method_signature (cmethod);
6970
6971         if (cfg->verbose_level > 2)
6972                 printf ("INLINE START %p %s -> %s\n", cmethod,  mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
6973
6974         if (!cmethod->inline_info) {
6975                 cfg->stat_inlineable_methods++;
6976                 cmethod->inline_info = 1;
6977         }
6978
6979         /* allocate local variables */
6980         cheader = mono_method_get_header (cmethod);
6981
6982         if (cheader == NULL || mono_loader_get_last_error ()) {
6983                 MonoLoaderError *error = mono_loader_get_last_error ();
6984
6985                 if (cheader)
6986                         mono_metadata_free_mh (cheader);
6987                 if (inline_always && error)
6988                         mono_cfg_set_exception (cfg, error->exception_type);
6989
6990                 mono_loader_clear_error ();
6991                 return 0;
6992         }
6993
6994         /*Must verify before creating locals as it can cause the JIT to assert.*/
6995         if (mono_compile_is_broken (cfg, cmethod, FALSE)) {
6996                 mono_metadata_free_mh (cheader);
6997                 return 0;
6998         }
6999
7000         /* allocate space to store the return value */
7001         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
7002                 rvar = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
7003         }
7004
7005         prev_locals = cfg->locals;
7006         cfg->locals = mono_mempool_alloc0 (cfg->mempool, cheader->num_locals * sizeof (MonoInst*));     
7007         for (i = 0; i < cheader->num_locals; ++i)
7008                 cfg->locals [i] = mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
7009
7010         /* allocate start and end blocks */
7011         /* This is needed so if the inline is aborted, we can clean up */
7012         NEW_BBLOCK (cfg, sbblock);
7013         sbblock->real_offset = real_offset;
7014
7015         NEW_BBLOCK (cfg, ebblock);
7016         ebblock->block_num = cfg->num_bblocks++;
7017         ebblock->real_offset = real_offset;
7018
7019         prev_args = cfg->args;
7020         prev_arg_types = cfg->arg_types;
7021         prev_inlined_method = cfg->inlined_method;
7022         cfg->inlined_method = cmethod;
7023         cfg->ret_var_set = FALSE;
7024         cfg->inline_depth ++;
7025         prev_real_offset = cfg->real_offset;
7026         prev_cbb_hash = cfg->cbb_hash;
7027         prev_cil_offset_to_bb = cfg->cil_offset_to_bb;
7028         prev_cil_offset_to_bb_len = cfg->cil_offset_to_bb_len;
7029         prev_cil_start = cfg->cil_start;
7030         prev_cbb = cfg->cbb;
7031         prev_current_method = cfg->current_method;
7032         prev_generic_context = cfg->generic_context;
7033         prev_ret_var_set = cfg->ret_var_set;
7034         prev_disable_inline = cfg->disable_inline;
7035
7036         if (ip && *ip == CEE_CALLVIRT && !(cmethod->flags & METHOD_ATTRIBUTE_STATIC))
7037                 virtual = TRUE;
7038
7039         costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, rvar, sp, real_offset, virtual);
7040
7041         ret_var_set = cfg->ret_var_set;
7042
7043         cfg->inlined_method = prev_inlined_method;
7044         cfg->real_offset = prev_real_offset;
7045         cfg->cbb_hash = prev_cbb_hash;
7046         cfg->cil_offset_to_bb = prev_cil_offset_to_bb;
7047         cfg->cil_offset_to_bb_len = prev_cil_offset_to_bb_len;
7048         cfg->cil_start = prev_cil_start;
7049         cfg->locals = prev_locals;
7050         cfg->args = prev_args;
7051         cfg->arg_types = prev_arg_types;
7052         cfg->current_method = prev_current_method;
7053         cfg->generic_context = prev_generic_context;
7054         cfg->ret_var_set = prev_ret_var_set;
7055         cfg->disable_inline = prev_disable_inline;
7056         cfg->inline_depth --;
7057
7058         if ((costs >= 0 && costs < 60) || inline_always || (costs >= 0 && (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))) {
7059                 if (cfg->verbose_level > 2)
7060                         printf ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
7061                 
7062                 cfg->stat_inlined_methods++;
7063
7064                 /* always add some code to avoid block split failures */
7065                 MONO_INST_NEW (cfg, ins, OP_NOP);
7066                 MONO_ADD_INS (prev_cbb, ins);
7067
7068                 prev_cbb->next_bb = sbblock;
7069                 link_bblock (cfg, prev_cbb, sbblock);
7070
7071                 /* 
7072                  * Get rid of the begin and end bblocks if possible to aid local
7073                  * optimizations.
7074                  */
7075                 mono_merge_basic_blocks (cfg, prev_cbb, sbblock);
7076
7077                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] != ebblock))
7078                         mono_merge_basic_blocks (cfg, prev_cbb, prev_cbb->out_bb [0]);
7079
7080                 if ((ebblock->in_count == 1) && ebblock->in_bb [0]->out_count == 1) {
7081                         MonoBasicBlock *prev = ebblock->in_bb [0];
7082                         mono_merge_basic_blocks (cfg, prev, ebblock);
7083                         cfg->cbb = prev;
7084                         if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] == prev)) {
7085                                 mono_merge_basic_blocks (cfg, prev_cbb, prev);
7086                                 cfg->cbb = prev_cbb;
7087                         }
7088                 } else {
7089                         /* 
7090                          * Its possible that the rvar is set in some prev bblock, but not in others.
7091                          * (#1835).
7092                          */
7093                         if (rvar) {
7094                                 MonoBasicBlock *bb;
7095
7096                                 for (i = 0; i < ebblock->in_count; ++i) {
7097                                         bb = ebblock->in_bb [i];
7098
7099                                         if (bb->last_ins && bb->last_ins->opcode == OP_NOT_REACHED) {
7100                                                 cfg->cbb = bb;
7101
7102                                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
7103                                         }
7104                                 }
7105                         }
7106
7107                         cfg->cbb = ebblock;
7108                 }
7109
7110                 if (rvar) {
7111                         /*
7112                          * If the inlined method contains only a throw, then the ret var is not 
7113                          * set, so set it to a dummy value.
7114                          */
7115                         if (!ret_var_set)
7116                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
7117
7118                         EMIT_NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
7119                         *sp++ = ins;
7120                 }
7121                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
7122                 return costs + 1;
7123         } else {
7124                 if (cfg->verbose_level > 2)
7125                         printf ("INLINE ABORTED %s (cost %d)\n", mono_method_full_name (cmethod, TRUE), costs);
7126                 cfg->exception_type = MONO_EXCEPTION_NONE;
7127                 mono_loader_clear_error ();
7128
7129                 /* This gets rid of the newly added bblocks */
7130                 cfg->cbb = prev_cbb;
7131         }
7132         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
7133         return 0;
7134 }
7135
7136 /*
7137  * Some of these comments may well be out-of-date.
7138  * Design decisions: we do a single pass over the IL code (and we do bblock 
7139  * splitting/merging in the few cases when it's required: a back jump to an IL
7140  * address that was not already seen as bblock starting point).
7141  * Code is validated as we go (full verification is still better left to metadata/verify.c).
7142  * Complex operations are decomposed in simpler ones right away. We need to let the 
7143  * arch-specific code peek and poke inside this process somehow (except when the 
7144  * optimizations can take advantage of the full semantic info of coarse opcodes).
7145  * All the opcodes of the form opcode.s are 'normalized' to opcode.
7146  * MonoInst->opcode initially is the IL opcode or some simplification of that 
7147  * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific 
7148  * opcode with value bigger than OP_LAST.
7149  * At this point the IR can be handed over to an interpreter, a dumb code generator
7150  * or to the optimizing code generator that will translate it to SSA form.
7151  *
7152  * Profiling directed optimizations.
7153  * We may compile by default with few or no optimizations and instrument the code
7154  * or the user may indicate what methods to optimize the most either in a config file
7155  * or through repeated runs where the compiler applies offline the optimizations to 
7156  * each method and then decides if it was worth it.
7157  */
7158
7159 #define CHECK_TYPE(ins) if (!(ins)->type) UNVERIFIED
7160 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) UNVERIFIED
7161 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) UNVERIFIED
7162 #define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) UNVERIFIED
7163 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
7164 #define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
7165 #define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
7166 #define CHECK_TYPELOAD(klass) if (!(klass) || (klass)->exception_type) TYPE_LOAD_ERROR ((klass))
7167
7168 /* offset from br.s -> br like opcodes */
7169 #define BIG_BRANCH_OFFSET 13
7170
7171 static gboolean
7172 ip_in_bb (MonoCompile *cfg, MonoBasicBlock *bb, const guint8* ip)
7173 {
7174         MonoBasicBlock *b = cfg->cil_offset_to_bb [ip - cfg->cil_start];
7175
7176         return b == NULL || b == bb;
7177 }
7178
7179 static int
7180 get_basic_blocks (MonoCompile *cfg, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
7181 {
7182         unsigned char *ip = start;
7183         unsigned char *target;
7184         int i;
7185         guint cli_addr;
7186         MonoBasicBlock *bblock;
7187         const MonoOpcode *opcode;
7188
7189         while (ip < end) {
7190                 cli_addr = ip - start;
7191                 i = mono_opcode_value ((const guint8 **)&ip, end);
7192                 if (i < 0)
7193                         UNVERIFIED;
7194                 opcode = &mono_opcodes [i];
7195                 switch (opcode->argument) {
7196                 case MonoInlineNone:
7197                         ip++; 
7198                         break;
7199                 case MonoInlineString:
7200                 case MonoInlineType:
7201                 case MonoInlineField:
7202                 case MonoInlineMethod:
7203                 case MonoInlineTok:
7204                 case MonoInlineSig:
7205                 case MonoShortInlineR:
7206                 case MonoInlineI:
7207                         ip += 5;
7208                         break;
7209                 case MonoInlineVar:
7210                         ip += 3;
7211                         break;
7212                 case MonoShortInlineVar:
7213                 case MonoShortInlineI:
7214                         ip += 2;
7215                         break;
7216                 case MonoShortInlineBrTarget:
7217                         target = start + cli_addr + 2 + (signed char)ip [1];
7218                         GET_BBLOCK (cfg, bblock, target);
7219                         ip += 2;
7220                         if (ip < end)
7221                                 GET_BBLOCK (cfg, bblock, ip);
7222                         break;
7223                 case MonoInlineBrTarget:
7224                         target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
7225                         GET_BBLOCK (cfg, bblock, target);
7226                         ip += 5;
7227                         if (ip < end)
7228                                 GET_BBLOCK (cfg, bblock, ip);
7229                         break;
7230                 case MonoInlineSwitch: {
7231                         guint32 n = read32 (ip + 1);
7232                         guint32 j;
7233                         ip += 5;
7234                         cli_addr += 5 + 4 * n;
7235                         target = start + cli_addr;
7236                         GET_BBLOCK (cfg, bblock, target);
7237                         
7238                         for (j = 0; j < n; ++j) {
7239                                 target = start + cli_addr + (gint32)read32 (ip);
7240                                 GET_BBLOCK (cfg, bblock, target);
7241                                 ip += 4;
7242                         }
7243                         break;
7244                 }
7245                 case MonoInlineR:
7246                 case MonoInlineI8:
7247                         ip += 9;
7248                         break;
7249                 default:
7250                         g_assert_not_reached ();
7251                 }
7252
7253                 if (i == CEE_THROW) {
7254                         unsigned char *bb_start = ip - 1;
7255                         
7256                         /* Find the start of the bblock containing the throw */
7257                         bblock = NULL;
7258                         while ((bb_start >= start) && !bblock) {
7259                                 bblock = cfg->cil_offset_to_bb [(bb_start) - start];
7260                                 bb_start --;
7261                         }
7262                         if (bblock)
7263                                 bblock->out_of_line = 1;
7264                 }
7265         }
7266         return 0;
7267 unverified:
7268 exception_exit:
7269         *pos = ip;
7270         return 1;
7271 }
7272
7273 static inline MonoMethod *
7274 mini_get_method_allow_open (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
7275 {
7276         MonoMethod *method;
7277
7278         if (m->wrapper_type != MONO_WRAPPER_NONE) {
7279                 method = mono_method_get_wrapper_data (m, token);
7280                 if (context) {
7281                         MonoError error;
7282                         method = mono_class_inflate_generic_method_checked (method, context, &error);
7283                         g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
7284                 }
7285         } else {
7286                 method = mono_get_method_full (m->klass->image, token, klass, context);
7287         }
7288
7289         return method;
7290 }
7291
7292 static inline MonoMethod *
7293 mini_get_method (MonoCompile *cfg, MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
7294 {
7295         MonoMethod *method = mini_get_method_allow_open (m, token, klass, context);
7296
7297         if (method && cfg && !cfg->gshared && mono_class_is_open_constructed_type (&method->klass->byval_arg))
7298                 return NULL;
7299
7300         return method;
7301 }
7302
7303 static inline MonoClass*
7304 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
7305 {
7306         MonoError error;
7307         MonoClass *klass;
7308
7309         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7310                 klass = mono_method_get_wrapper_data (method, token);
7311                 if (context)
7312                         klass = mono_class_inflate_generic_class (klass, context);
7313         } else {
7314                 klass = mono_class_get_and_inflate_typespec_checked (method->klass->image, token, context, &error);
7315                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
7316         }
7317         if (klass)
7318                 mono_class_init (klass);
7319         return klass;
7320 }
7321
7322 static inline MonoMethodSignature*
7323 mini_get_signature (MonoMethod *method, guint32 token, MonoGenericContext *context)
7324 {
7325         MonoMethodSignature *fsig;
7326
7327         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7328                 fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
7329         } else {
7330                 fsig = mono_metadata_parse_signature (method->klass->image, token);
7331         }
7332         if (context) {
7333                 MonoError error;
7334                 fsig = mono_inflate_generic_signature(fsig, context, &error);
7335                 // FIXME:
7336                 g_assert(mono_error_ok(&error));
7337         }
7338         return fsig;
7339 }
7340
7341 static MonoMethod*
7342 throw_exception (void)
7343 {
7344         static MonoMethod *method = NULL;
7345
7346         if (!method) {
7347                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
7348                 method = mono_class_get_method_from_name (secman->securitymanager, "ThrowException", 1);
7349         }
7350         g_assert (method);
7351         return method;
7352 }
7353
7354 static void
7355 emit_throw_exception (MonoCompile *cfg, MonoException *ex)
7356 {
7357         MonoMethod *thrower = throw_exception ();
7358         MonoInst *args [1];
7359
7360         EMIT_NEW_PCONST (cfg, args [0], ex);
7361         mono_emit_method_call (cfg, thrower, args, NULL);
7362 }
7363
7364 /*
7365  * Return the original method is a wrapper is specified. We can only access 
7366  * the custom attributes from the original method.
7367  */
7368 static MonoMethod*
7369 get_original_method (MonoMethod *method)
7370 {
7371         if (method->wrapper_type == MONO_WRAPPER_NONE)
7372                 return method;
7373
7374         /* native code (which is like Critical) can call any managed method XXX FIXME XXX to validate all usages */
7375         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)
7376                 return NULL;
7377
7378         /* in other cases we need to find the original method */
7379         return mono_marshal_method_from_wrapper (method);
7380 }
7381
7382 static void
7383 ensure_method_is_allowed_to_access_field (MonoCompile *cfg, MonoMethod *caller, MonoClassField *field)
7384 {
7385         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
7386         MonoException *ex = mono_security_core_clr_is_field_access_allowed (get_original_method (caller), field);
7387         if (ex)
7388                 emit_throw_exception (cfg, ex);
7389 }
7390
7391 static void
7392 ensure_method_is_allowed_to_call_method (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee)
7393 {
7394         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
7395         MonoException *ex = mono_security_core_clr_is_call_allowed (get_original_method (caller), callee);
7396         if (ex)
7397                 emit_throw_exception (cfg, ex);
7398 }
7399
7400 /*
7401  * Check that the IL instructions at ip are the array initialization
7402  * sequence and return the pointer to the data and the size.
7403  */
7404 static const char*
7405 initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, MonoClass *klass, guint32 len, int *out_size, guint32 *out_field_token)
7406 {
7407         /*
7408          * newarr[System.Int32]
7409          * dup
7410          * ldtoken field valuetype ...
7411          * call void class [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle)
7412          */
7413         if (ip [0] == CEE_DUP && ip [1] == CEE_LDTOKEN && ip [5] == 0x4 && ip [6] == CEE_CALL) {
7414                 MonoError error;
7415                 guint32 token = read32 (ip + 7);
7416                 guint32 field_token = read32 (ip + 2);
7417                 guint32 field_index = field_token & 0xffffff;
7418                 guint32 rva;
7419                 const char *data_ptr;
7420                 int size = 0;
7421                 MonoMethod *cmethod;
7422                 MonoClass *dummy_class;
7423                 MonoClassField *field = mono_field_from_token_checked (method->klass->image, field_token, &dummy_class, NULL, &error);
7424                 int dummy_align;
7425
7426                 if (!field) {
7427                         mono_error_cleanup (&error); /* FIXME don't swallow the error */
7428                         return NULL;
7429                 }
7430
7431                 *out_field_token = field_token;
7432
7433                 cmethod = mini_get_method (NULL, method, token, NULL, NULL);
7434                 if (!cmethod)
7435                         return NULL;
7436                 if (strcmp (cmethod->name, "InitializeArray") || strcmp (cmethod->klass->name, "RuntimeHelpers") || cmethod->klass->image != mono_defaults.corlib)
7437                         return NULL;
7438                 switch (mono_type_get_underlying_type (&klass->byval_arg)->type) {
7439                 case MONO_TYPE_BOOLEAN:
7440                 case MONO_TYPE_I1:
7441                 case MONO_TYPE_U1:
7442                         size = 1; break;
7443                 /* we need to swap on big endian, so punt. Should we handle R4 and R8 as well? */
7444 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
7445                 case MONO_TYPE_CHAR:
7446                 case MONO_TYPE_I2:
7447                 case MONO_TYPE_U2:
7448                         size = 2; break;
7449                 case MONO_TYPE_I4:
7450                 case MONO_TYPE_U4:
7451                 case MONO_TYPE_R4:
7452                         size = 4; break;
7453                 case MONO_TYPE_R8:
7454                 case MONO_TYPE_I8:
7455                 case MONO_TYPE_U8:
7456                         size = 8; break;
7457 #endif
7458                 default:
7459                         return NULL;
7460                 }
7461                 size *= len;
7462                 if (size > mono_type_size (field->type, &dummy_align))
7463                     return NULL;
7464                 *out_size = size;
7465                 /*g_print ("optimized in %s: size: %d, numelems: %d\n", method->name, size, newarr->inst_newa_len->inst_c0);*/
7466                 if (!image_is_dynamic (method->klass->image)) {
7467                         field_index = read32 (ip + 2) & 0xffffff;
7468                         mono_metadata_field_info (method->klass->image, field_index - 1, NULL, &rva, NULL);
7469                         data_ptr = mono_image_rva_map (method->klass->image, rva);
7470                         /*g_print ("field: 0x%08x, rva: %d, rva_ptr: %p\n", read32 (ip + 2), rva, data_ptr);*/
7471                         /* for aot code we do the lookup on load */
7472                         if (aot && data_ptr)
7473                                 return GUINT_TO_POINTER (rva);
7474                 } else {
7475                         /*FIXME is it possible to AOT a SRE assembly not meant to be saved? */ 
7476                         g_assert (!aot);
7477                         data_ptr = mono_field_get_data (field);
7478                 }
7479                 return data_ptr;
7480         }
7481         return NULL;
7482 }
7483
7484 static void
7485 set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsigned char *ip)
7486 {
7487         char *method_fname = mono_method_full_name (method, TRUE);
7488         char *method_code;
7489         MonoMethodHeader *header = mono_method_get_header (method);
7490
7491         if (header->code_size == 0)
7492                 method_code = g_strdup ("method body is empty.");
7493         else
7494                 method_code = mono_disasm_code_one (NULL, method, ip, NULL);
7495         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
7496         cfg->exception_message = g_strdup_printf ("Invalid IL code in %s: %s\n", method_fname, method_code);
7497         g_free (method_fname);
7498         g_free (method_code);
7499         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
7500 }
7501
7502 static void
7503 set_exception_object (MonoCompile *cfg, MonoException *exception)
7504 {
7505         mono_cfg_set_exception (cfg, MONO_EXCEPTION_OBJECT_SUPPLIED);
7506         MONO_GC_REGISTER_ROOT_SINGLE (cfg->exception_ptr, MONO_ROOT_SOURCE_JIT, "jit exception");
7507         cfg->exception_ptr = exception;
7508 }
7509
7510 static void
7511 emit_stloc_ir (MonoCompile *cfg, MonoInst **sp, MonoMethodHeader *header, int n)
7512 {
7513         MonoInst *ins;
7514         guint32 opcode = mono_type_to_regmove (cfg, header->locals [n]);
7515         if ((opcode == OP_MOVE) && cfg->cbb->last_ins == sp [0]  &&
7516                         ((sp [0]->opcode == OP_ICONST) || (sp [0]->opcode == OP_I8CONST))) {
7517                 /* Optimize reg-reg moves away */
7518                 /* 
7519                  * Can't optimize other opcodes, since sp[0] might point to
7520                  * the last ins of a decomposed opcode.
7521                  */
7522                 sp [0]->dreg = (cfg)->locals [n]->dreg;
7523         } else {
7524                 EMIT_NEW_LOCSTORE (cfg, ins, n, *sp);
7525         }
7526 }
7527
7528 /*
7529  * ldloca inhibits many optimizations so try to get rid of it in common
7530  * cases.
7531  */
7532 static inline unsigned char *
7533 emit_optimized_ldloca_ir (MonoCompile *cfg, unsigned char *ip, unsigned char *end, int size)
7534 {
7535         int local, token;
7536         MonoClass *klass;
7537         MonoType *type;
7538
7539         if (size == 1) {
7540                 local = ip [1];
7541                 ip += 2;
7542         } else {
7543                 local = read16 (ip + 2);
7544                 ip += 4;
7545         }
7546         
7547         if (ip + 6 < end && (ip [0] == CEE_PREFIX1) && (ip [1] == CEE_INITOBJ) && ip_in_bb (cfg, cfg->cbb, ip + 1)) {
7548                 /* From the INITOBJ case */
7549                 token = read32 (ip + 2);
7550                 klass = mini_get_class (cfg->current_method, token, cfg->generic_context);
7551                 CHECK_TYPELOAD (klass);
7552                 type = mini_get_underlying_type (&klass->byval_arg);
7553                 emit_init_local (cfg, local, type, TRUE);
7554                 return ip + 6;
7555         }
7556  exception_exit:
7557         return NULL;
7558 }
7559
7560 static void
7561 emit_runtime_constant (MonoCompile *cfg, MonoInst **ins, MonoJumpInfoType patch_type)
7562 {
7563         if (cfg->compile_aot) {
7564                 EMIT_NEW_AOTCONST (cfg, *ins, patch_type, NULL);
7565         } else {
7566                 MonoJumpInfo ji;
7567                 gpointer target;
7568
7569                 ji.type = patch_type;
7570                 target = mono_resolve_patch_target (NULL, NULL, NULL, &ji, FALSE);
7571
7572                 EMIT_NEW_PCONST (cfg, *ins, target);
7573         }
7574 }
7575
7576 static gboolean
7577 is_exception_class (MonoClass *klass)
7578 {
7579         while (klass) {
7580                 if (klass == mono_defaults.exception_class)
7581                         return TRUE;
7582                 klass = klass->parent;
7583         }
7584         return FALSE;
7585 }
7586
7587 /*
7588  * is_jit_optimizer_disabled:
7589  *
7590  *   Determine whenever M's assembly has a DebuggableAttribute with the
7591  * IsJITOptimizerDisabled flag set.
7592  */
7593 static gboolean
7594 is_jit_optimizer_disabled (MonoMethod *m)
7595 {
7596         MonoAssembly *ass = m->klass->image->assembly;
7597         MonoCustomAttrInfo* attrs;
7598         static MonoClass *klass;
7599         int i;
7600         gboolean val = FALSE;
7601
7602         g_assert (ass);
7603         if (ass->jit_optimizer_disabled_inited)
7604                 return ass->jit_optimizer_disabled;
7605
7606         if (!klass)
7607                 klass = mono_class_from_name (mono_defaults.corlib, "System.Diagnostics", "DebuggableAttribute");
7608         if (!klass) {
7609                 /* Linked away */
7610                 ass->jit_optimizer_disabled = FALSE;
7611                 mono_memory_barrier ();
7612                 ass->jit_optimizer_disabled_inited = TRUE;
7613                 return FALSE;
7614         }
7615
7616         attrs = mono_custom_attrs_from_assembly (ass);
7617         if (attrs) {
7618                 for (i = 0; i < attrs->num_attrs; ++i) {
7619                         MonoCustomAttrEntry *attr = &attrs->attrs [i];
7620                         const gchar *p;
7621                         MonoMethodSignature *sig;
7622
7623                         if (!attr->ctor || attr->ctor->klass != klass)
7624                                 continue;
7625                         /* Decode the attribute. See reflection.c */
7626                         p = (const char*)attr->data;
7627                         g_assert (read16 (p) == 0x0001);
7628                         p += 2;
7629
7630                         // FIXME: Support named parameters
7631                         sig = mono_method_signature (attr->ctor);
7632                         if (sig->param_count != 2 || sig->params [0]->type != MONO_TYPE_BOOLEAN || sig->params [1]->type != MONO_TYPE_BOOLEAN)
7633                                 continue;
7634                         /* Two boolean arguments */
7635                         p ++;
7636                         val = *p;
7637                 }
7638                 mono_custom_attrs_free (attrs);
7639         }
7640
7641         ass->jit_optimizer_disabled = val;
7642         mono_memory_barrier ();
7643         ass->jit_optimizer_disabled_inited = TRUE;
7644
7645         return val;
7646 }
7647
7648 static gboolean
7649 is_supported_tail_call (MonoCompile *cfg, MonoMethod *method, MonoMethod *cmethod, MonoMethodSignature *fsig, int call_opcode)
7650 {
7651         gboolean supported_tail_call;
7652         int i;
7653
7654         supported_tail_call = mono_arch_tail_call_supported (cfg, mono_method_signature (method), mono_method_signature (cmethod));
7655
7656         for (i = 0; i < fsig->param_count; ++i) {
7657                 if (fsig->params [i]->byref || fsig->params [i]->type == MONO_TYPE_PTR || fsig->params [i]->type == MONO_TYPE_FNPTR)
7658                         /* These can point to the current method's stack */
7659                         supported_tail_call = FALSE;
7660         }
7661         if (fsig->hasthis && cmethod->klass->valuetype)
7662                 /* this might point to the current method's stack */
7663                 supported_tail_call = FALSE;
7664         if (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
7665                 supported_tail_call = FALSE;
7666         if (cfg->method->save_lmf)
7667                 supported_tail_call = FALSE;
7668         if (cmethod->wrapper_type && cmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD)
7669                 supported_tail_call = FALSE;
7670         if (call_opcode != CEE_CALL)
7671                 supported_tail_call = FALSE;
7672
7673         /* Debugging support */
7674 #if 0
7675         if (supported_tail_call) {
7676                 if (!mono_debug_count ())
7677                         supported_tail_call = FALSE;
7678         }
7679 #endif
7680
7681         return supported_tail_call;
7682 }
7683
7684 /*
7685  * handle_ctor_call:
7686  *
7687  *   Handle calls made to ctors from NEWOBJ opcodes.
7688  */
7689 static void
7690 handle_ctor_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used,
7691                                   MonoInst **sp, guint8 *ip, int *inline_costs)
7692 {
7693         MonoInst *vtable_arg = NULL, *callvirt_this_arg = NULL, *ins;
7694
7695         if (cmethod->klass->valuetype && mono_class_generic_sharing_enabled (cmethod->klass) &&
7696                                         mono_method_is_generic_sharable (cmethod, TRUE)) {
7697                 if (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst) {
7698                         mono_class_vtable (cfg->domain, cmethod->klass);
7699                         CHECK_TYPELOAD (cmethod->klass);
7700
7701                         vtable_arg = emit_get_rgctx_method (cfg, context_used,
7702                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
7703                 } else {
7704                         if (context_used) {
7705                                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
7706                                                                                                    cmethod->klass, MONO_RGCTX_INFO_VTABLE);
7707                         } else {
7708                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
7709
7710                                 CHECK_TYPELOAD (cmethod->klass);
7711                                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
7712                         }
7713                 }
7714         }
7715
7716         /* Avoid virtual calls to ctors if possible */
7717         if (mono_class_is_marshalbyref (cmethod->klass))
7718                 callvirt_this_arg = sp [0];
7719
7720         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_ctor (cfg, cmethod, fsig, sp))) {
7721                 g_assert (MONO_TYPE_IS_VOID (fsig->ret));
7722                 CHECK_CFG_EXCEPTION;
7723         } else if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used && !vtable_arg &&
7724                            mono_method_check_inlining (cfg, cmethod) &&
7725                            !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE)) {
7726                 int costs;
7727
7728                 if ((costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, FALSE))) {
7729                         cfg->real_offset += 5;
7730
7731                         *inline_costs += costs - 5;
7732                 } else {
7733                         INLINE_FAILURE ("inline failure");
7734                         // FIXME-VT: Clean this up
7735                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))
7736                                 GSHAREDVT_FAILURE(*ip);
7737                         mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, callvirt_this_arg, NULL, NULL);
7738                 }
7739         } else if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
7740                 MonoInst *addr;
7741
7742                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE);
7743                 mono_emit_calli (cfg, fsig, sp, addr, NULL, vtable_arg);
7744         } else if (context_used &&
7745                            ((!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
7746                                  !mono_class_generic_sharing_enabled (cmethod->klass)) || cfg->gsharedvt)) {
7747                 MonoInst *cmethod_addr;
7748
7749                 /* Generic calls made out of gsharedvt methods cannot be patched, so use an indirect call */
7750
7751                 cmethod_addr = emit_get_rgctx_method (cfg, context_used,
7752                                                                                           cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
7753
7754                 mono_emit_calli (cfg, fsig, sp, cmethod_addr, NULL, vtable_arg);
7755         } else {
7756                 INLINE_FAILURE ("ctor call");
7757                 ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp,
7758                                                                                   callvirt_this_arg, NULL, vtable_arg);
7759         }
7760  exception_exit:
7761         return;
7762 }
7763
7764 static void
7765 emit_setret (MonoCompile *cfg, MonoInst *val)
7766 {
7767         MonoType *ret_type = mini_get_underlying_type (mono_method_signature (cfg->method)->ret);
7768         MonoInst *ins;
7769
7770         if (mini_type_to_stind (cfg, ret_type) == CEE_STOBJ) {
7771                 MonoInst *ret_addr;
7772
7773                 if (!cfg->vret_addr) {
7774                         EMIT_NEW_VARSTORE (cfg, ins, cfg->ret, ret_type, val);
7775                 } else {
7776                         EMIT_NEW_RETLOADA (cfg, ret_addr);
7777
7778                         EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STOREV_MEMBASE, ret_addr->dreg, 0, val->dreg);
7779                         ins->klass = mono_class_from_mono_type (ret_type);
7780                 }
7781         } else {
7782 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
7783                 if (COMPILE_SOFT_FLOAT (cfg) && !ret_type->byref && ret_type->type == MONO_TYPE_R4) {
7784                         MonoInst *iargs [1];
7785                         MonoInst *conv;
7786
7787                         iargs [0] = val;
7788                         conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
7789                         mono_arch_emit_setret (cfg, cfg->method, conv);
7790                 } else {
7791                         mono_arch_emit_setret (cfg, cfg->method, val);
7792                 }
7793 #else
7794                 mono_arch_emit_setret (cfg, cfg->method, val);
7795 #endif
7796         }
7797 }
7798
7799 static MonoMethodSignature*
7800 sig_to_rgctx_sig (MonoMethodSignature *sig)
7801 {
7802         // FIXME: memory allocation
7803         MonoMethodSignature *res;
7804         int i;
7805
7806         res = g_malloc (MONO_SIZEOF_METHOD_SIGNATURE + (sig->param_count + 1) * sizeof (MonoType*));
7807         memcpy (res, sig, MONO_SIZEOF_METHOD_SIGNATURE);
7808         res->param_count = sig->param_count + 1;
7809         for (i = 0; i < sig->param_count; ++i)
7810                 res->params [i] = sig->params [i];
7811         res->params [sig->param_count] = &mono_defaults.int_class->byval_arg;
7812         return res;
7813 }
7814
7815 /*
7816  * mono_method_to_ir:
7817  *
7818  *   Translate the .net IL into linear IR.
7819  */
7820 int
7821 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
7822                    MonoInst *return_var, MonoInst **inline_args, 
7823                    guint inline_offset, gboolean is_virtual_call)
7824 {
7825         MonoError error;
7826         MonoInst *ins, **sp, **stack_start;
7827         MonoBasicBlock *tblock = NULL, *init_localsbb = NULL;
7828         MonoSimpleBasicBlock *bb = NULL, *original_bb = NULL;
7829         MonoMethod *cmethod, *method_definition;
7830         MonoInst **arg_array;
7831         MonoMethodHeader *header;
7832         MonoImage *image;
7833         guint32 token, ins_flag;
7834         MonoClass *klass;
7835         MonoClass *constrained_class = NULL;
7836         unsigned char *ip, *end, *target, *err_pos;
7837         MonoMethodSignature *sig;
7838         MonoGenericContext *generic_context = NULL;
7839         MonoGenericContainer *generic_container = NULL;
7840         MonoType **param_types;
7841         int i, n, start_new_bblock, dreg;
7842         int num_calls = 0, inline_costs = 0;
7843         int breakpoint_id = 0;
7844         guint num_args;
7845         GSList *class_inits = NULL;
7846         gboolean dont_verify, dont_verify_stloc, readonly = FALSE;
7847         int context_used;
7848         gboolean init_locals, seq_points, skip_dead_blocks;
7849         gboolean sym_seq_points = FALSE;
7850         MonoDebugMethodInfo *minfo;
7851         MonoBitSet *seq_point_locs = NULL;
7852         MonoBitSet *seq_point_set_locs = NULL;
7853
7854         cfg->disable_inline = is_jit_optimizer_disabled (method);
7855
7856         /* serialization and xdomain stuff may need access to private fields and methods */
7857         dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
7858         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE;
7859         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH;
7860         dont_verify |= method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; /* bug #77896 */
7861         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP;
7862         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP_INVOKE;
7863
7864         /* still some type unsafety issues in marshal wrappers... (unknown is PtrToStructure) */
7865         dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE;
7866         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_UNKNOWN;
7867         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED;
7868         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_STELEMREF;
7869
7870         image = method->klass->image;
7871         header = mono_method_get_header (method);
7872         if (!header) {
7873                 MonoLoaderError *error;
7874
7875                 if ((error = mono_loader_get_last_error ())) {
7876                         mono_cfg_set_exception (cfg, error->exception_type);
7877                 } else {
7878                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
7879                         cfg->exception_message = g_strdup_printf ("Missing or incorrect header for method %s", cfg->method->name);
7880                 }
7881                 goto exception_exit;
7882         }
7883         generic_container = mono_method_get_generic_container (method);
7884         sig = mono_method_signature (method);
7885         num_args = sig->hasthis + sig->param_count;
7886         ip = (unsigned char*)header->code;
7887         cfg->cil_start = ip;
7888         end = ip + header->code_size;
7889         cfg->stat_cil_code_size += header->code_size;
7890
7891         seq_points = cfg->gen_seq_points && cfg->method == method;
7892
7893         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
7894                 /* We could hit a seq point before attaching to the JIT (#8338) */
7895                 seq_points = FALSE;
7896         }
7897
7898         if (cfg->gen_sdb_seq_points && cfg->method == method) {
7899                 minfo = mono_debug_lookup_method (method);
7900                 if (minfo) {
7901                         MonoSymSeqPoint *sps;
7902                         int i, n_il_offsets;
7903
7904                         mono_debug_get_seq_points (minfo, NULL, NULL, NULL, &sps, &n_il_offsets);
7905                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
7906                         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);
7907                         sym_seq_points = TRUE;
7908                         for (i = 0; i < n_il_offsets; ++i) {
7909                                 if (sps [i].il_offset < header->code_size)
7910                                         mono_bitset_set_fast (seq_point_locs, sps [i].il_offset);
7911                         }
7912                         g_free (sps);
7913                 } else if (!method->wrapper_type && !method->dynamic && mono_debug_image_has_debug_info (method->klass->image)) {
7914                         /* Methods without line number info like auto-generated property accessors */
7915                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
7916                         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);
7917                         sym_seq_points = TRUE;
7918                 }
7919         }
7920
7921         /* 
7922          * Methods without init_locals set could cause asserts in various passes
7923          * (#497220). To work around this, we emit dummy initialization opcodes
7924          * (OP_DUMMY_ICONST etc.) which generate no code. These are only supported
7925          * on some platforms.
7926          */
7927         if ((cfg->opt & MONO_OPT_UNSAFE) && cfg->backend->have_dummy_init)
7928                 init_locals = header->init_locals;
7929         else
7930                 init_locals = TRUE;
7931
7932         method_definition = method;
7933         while (method_definition->is_inflated) {
7934                 MonoMethodInflated *imethod = (MonoMethodInflated *) method_definition;
7935                 method_definition = imethod->declaring;
7936         }
7937
7938         /* SkipVerification is not allowed if core-clr is enabled */
7939         if (!dont_verify && mini_assembly_can_skip_verification (cfg->domain, method)) {
7940                 dont_verify = TRUE;
7941                 dont_verify_stloc = TRUE;
7942         }
7943
7944         if (sig->is_inflated)
7945                 generic_context = mono_method_get_context (method);
7946         else if (generic_container)
7947                 generic_context = &generic_container->context;
7948         cfg->generic_context = generic_context;
7949
7950         if (!cfg->gshared)
7951                 g_assert (!sig->has_type_parameters);
7952
7953         if (sig->generic_param_count && method->wrapper_type == MONO_WRAPPER_NONE) {
7954                 g_assert (method->is_inflated);
7955                 g_assert (mono_method_get_context (method)->method_inst);
7956         }
7957         if (method->is_inflated && mono_method_get_context (method)->method_inst)
7958                 g_assert (sig->generic_param_count);
7959
7960         if (cfg->method == method) {
7961                 cfg->real_offset = 0;
7962         } else {
7963                 cfg->real_offset = inline_offset;
7964         }
7965
7966         cfg->cil_offset_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoBasicBlock*) * header->code_size);
7967         cfg->cil_offset_to_bb_len = header->code_size;
7968
7969         cfg->current_method = method;
7970
7971         if (cfg->verbose_level > 2)
7972                 printf ("method to IR %s\n", mono_method_full_name (method, TRUE));
7973
7974         param_types = mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * num_args);
7975         if (sig->hasthis)
7976                 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
7977         for (n = 0; n < sig->param_count; ++n)
7978                 param_types [n + sig->hasthis] = sig->params [n];
7979         cfg->arg_types = param_types;
7980
7981         cfg->dont_inline = g_list_prepend (cfg->dont_inline, method);
7982         if (cfg->method == method) {
7983
7984                 if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
7985                         cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
7986
7987                 /* ENTRY BLOCK */
7988                 NEW_BBLOCK (cfg, start_bblock);
7989                 cfg->bb_entry = start_bblock;
7990                 start_bblock->cil_code = NULL;
7991                 start_bblock->cil_length = 0;
7992
7993                 /* EXIT BLOCK */
7994                 NEW_BBLOCK (cfg, end_bblock);
7995                 cfg->bb_exit = end_bblock;
7996                 end_bblock->cil_code = NULL;
7997                 end_bblock->cil_length = 0;
7998                 end_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
7999                 g_assert (cfg->num_bblocks == 2);
8000
8001                 arg_array = cfg->args;
8002
8003                 if (header->num_clauses) {
8004                         cfg->spvars = g_hash_table_new (NULL, NULL);
8005                         cfg->exvars = g_hash_table_new (NULL, NULL);
8006                 }
8007                 /* handle exception clauses */
8008                 for (i = 0; i < header->num_clauses; ++i) {
8009                         MonoBasicBlock *try_bb;
8010                         MonoExceptionClause *clause = &header->clauses [i];
8011                         GET_BBLOCK (cfg, try_bb, ip + clause->try_offset);
8012
8013                         try_bb->real_offset = clause->try_offset;
8014                         try_bb->try_start = TRUE;
8015                         try_bb->region = ((i + 1) << 8) | clause->flags;
8016                         GET_BBLOCK (cfg, tblock, ip + clause->handler_offset);
8017                         tblock->real_offset = clause->handler_offset;
8018                         tblock->flags |= BB_EXCEPTION_HANDLER;
8019
8020                         /*
8021                          * Linking the try block with the EH block hinders inlining as we won't be able to 
8022                          * merge the bblocks from inlining and produce an artificial hole for no good reason.
8023                          */
8024                         if (COMPILE_LLVM (cfg))
8025                                 link_bblock (cfg, try_bb, tblock);
8026
8027                         if (*(ip + clause->handler_offset) == CEE_POP)
8028                                 tblock->flags |= BB_EXCEPTION_DEAD_OBJ;
8029
8030                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
8031                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER ||
8032                             clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
8033                                 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
8034                                 MONO_ADD_INS (tblock, ins);
8035
8036                                 if (seq_points && clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY && clause->flags != MONO_EXCEPTION_CLAUSE_FILTER) {
8037                                         /* finally clauses already have a seq point */
8038                                         /* seq points for filter clauses are emitted below */
8039                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
8040                                         MONO_ADD_INS (tblock, ins);
8041                                 }
8042
8043                                 /* todo: is a fault block unsafe to optimize? */
8044                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
8045                                         tblock->flags |= BB_EXCEPTION_UNSAFE;
8046                         }
8047
8048                         /*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);
8049                           while (p < end) {
8050                           printf ("%s", mono_disasm_code_one (NULL, method, p, &p));
8051                           }*/
8052                         /* catch and filter blocks get the exception object on the stack */
8053                         if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
8054                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
8055
8056                                 /* mostly like handle_stack_args (), but just sets the input args */
8057                                 /* printf ("handling clause at IL_%04x\n", clause->handler_offset); */
8058                                 tblock->in_scount = 1;
8059                                 tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
8060                                 tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
8061
8062                                 cfg->cbb = tblock;
8063
8064 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
8065                                 /* The EH code passes in the exception in a register to both JITted and LLVM compiled code */
8066                                 if (!cfg->compile_llvm) {
8067                                         MONO_INST_NEW (cfg, ins, OP_GET_EX_OBJ);
8068                                         ins->dreg = tblock->in_stack [0]->dreg;
8069                                         MONO_ADD_INS (tblock, ins);
8070                                 }
8071 #else
8072                                 MonoInst *dummy_use;
8073
8074                                 /* 
8075                                  * Add a dummy use for the exvar so its liveness info will be
8076                                  * correct.
8077                                  */
8078                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, tblock->in_stack [0]);
8079 #endif
8080
8081                                 if (seq_points && clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
8082                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
8083                                         MONO_ADD_INS (tblock, ins);
8084                                 }
8085                                 
8086                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
8087                                         GET_BBLOCK (cfg, tblock, ip + clause->data.filter_offset);
8088                                         tblock->flags |= BB_EXCEPTION_HANDLER;
8089                                         tblock->real_offset = clause->data.filter_offset;
8090                                         tblock->in_scount = 1;
8091                                         tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
8092                                         /* The filter block shares the exvar with the handler block */
8093                                         tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
8094                                         MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
8095                                         MONO_ADD_INS (tblock, ins);
8096                                 }
8097                         }
8098
8099                         if (clause->flags != MONO_EXCEPTION_CLAUSE_FILTER &&
8100                                         clause->data.catch_class &&
8101                                         cfg->gshared &&
8102                                         mono_class_check_context_used (clause->data.catch_class)) {
8103                                 /*
8104                                  * In shared generic code with catch
8105                                  * clauses containing type variables
8106                                  * the exception handling code has to
8107                                  * be able to get to the rgctx.
8108                                  * Therefore we have to make sure that
8109                                  * the vtable/mrgctx argument (for
8110                                  * static or generic methods) or the
8111                                  * "this" argument (for non-static
8112                                  * methods) are live.
8113                                  */
8114                                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
8115                                                 mini_method_get_context (method)->method_inst ||
8116                                                 method->klass->valuetype) {
8117                                         mono_get_vtable_var (cfg);
8118                                 } else {
8119                                         MonoInst *dummy_use;
8120
8121                                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, arg_array [0]);
8122                                 }
8123                         }
8124                 }
8125         } else {
8126                 arg_array = (MonoInst **) alloca (sizeof (MonoInst *) * num_args);
8127                 cfg->cbb = start_bblock;
8128                 cfg->args = arg_array;
8129                 mono_save_args (cfg, sig, inline_args);
8130         }
8131
8132         /* FIRST CODE BLOCK */
8133         NEW_BBLOCK (cfg, tblock);
8134         tblock->cil_code = ip;
8135         cfg->cbb = tblock;
8136         cfg->ip = ip;
8137
8138         ADD_BBLOCK (cfg, tblock);
8139
8140         if (cfg->method == method) {
8141                 breakpoint_id = mono_debugger_method_has_breakpoint (method);
8142                 if (breakpoint_id) {
8143                         MONO_INST_NEW (cfg, ins, OP_BREAK);
8144                         MONO_ADD_INS (cfg->cbb, ins);
8145                 }
8146         }
8147
8148         /* we use a separate basic block for the initialization code */
8149         NEW_BBLOCK (cfg, init_localsbb);
8150         cfg->bb_init = init_localsbb;
8151         init_localsbb->real_offset = cfg->real_offset;
8152         start_bblock->next_bb = init_localsbb;
8153         init_localsbb->next_bb = cfg->cbb;
8154         link_bblock (cfg, start_bblock, init_localsbb);
8155         link_bblock (cfg, init_localsbb, cfg->cbb);
8156                 
8157         cfg->cbb = init_localsbb;
8158
8159         if (cfg->gsharedvt && cfg->method == method) {
8160                 MonoGSharedVtMethodInfo *info;
8161                 MonoInst *var, *locals_var;
8162                 int dreg;
8163
8164                 info = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoGSharedVtMethodInfo));
8165                 info->method = cfg->method;
8166                 info->count_entries = 16;
8167                 info->entries = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
8168                 cfg->gsharedvt_info = info;
8169
8170                 var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8171                 /* prevent it from being register allocated */
8172                 //var->flags |= MONO_INST_VOLATILE;
8173                 cfg->gsharedvt_info_var = var;
8174
8175                 ins = emit_get_rgctx_gsharedvt_method (cfg, mini_method_check_context_used (cfg, method), method, info);
8176                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, var->dreg, ins->dreg);
8177
8178                 /* Allocate locals */
8179                 locals_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8180                 /* prevent it from being register allocated */
8181                 //locals_var->flags |= MONO_INST_VOLATILE;
8182                 cfg->gsharedvt_locals_var = locals_var;
8183
8184                 dreg = alloc_ireg (cfg);
8185                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, dreg, var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, locals_size));
8186
8187                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
8188                 ins->dreg = locals_var->dreg;
8189                 ins->sreg1 = dreg;
8190                 MONO_ADD_INS (cfg->cbb, ins);
8191                 cfg->gsharedvt_locals_var_ins = ins;
8192                 
8193                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
8194                 /*
8195                 if (init_locals)
8196                         ins->flags |= MONO_INST_INIT;
8197                 */
8198         }
8199
8200         if (mono_security_core_clr_enabled ()) {
8201                 /* check if this is native code, e.g. an icall or a p/invoke */
8202                 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
8203                         MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
8204                         if (wrapped) {
8205                                 gboolean pinvk = (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL);
8206                                 gboolean icall = (wrapped->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL);
8207
8208                                 /* if this ia a native call then it can only be JITted from platform code */
8209                                 if ((icall || pinvk) && method->klass && method->klass->image) {
8210                                         if (!mono_security_core_clr_is_platform_image (method->klass->image)) {
8211                                                 MonoException *ex = icall ? mono_get_exception_security () : 
8212                                                         mono_get_exception_method_access ();
8213                                                 emit_throw_exception (cfg, ex);
8214                                         }
8215                                 }
8216                         }
8217                 }
8218         }
8219
8220         CHECK_CFG_EXCEPTION;
8221
8222         if (header->code_size == 0)
8223                 UNVERIFIED;
8224
8225         if (get_basic_blocks (cfg, header, cfg->real_offset, ip, end, &err_pos)) {
8226                 ip = err_pos;
8227                 UNVERIFIED;
8228         }
8229
8230         if (cfg->method == method)
8231                 mono_debug_init_method (cfg, cfg->cbb, breakpoint_id);
8232
8233         for (n = 0; n < header->num_locals; ++n) {
8234                 if (header->locals [n]->type == MONO_TYPE_VOID && !header->locals [n]->byref)
8235                         UNVERIFIED;
8236         }
8237         class_inits = NULL;
8238
8239         /* We force the vtable variable here for all shared methods
8240            for the possibility that they might show up in a stack
8241            trace where their exact instantiation is needed. */
8242         if (cfg->gshared && method == cfg->method) {
8243                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
8244                                 mini_method_get_context (method)->method_inst ||
8245                                 method->klass->valuetype) {
8246                         mono_get_vtable_var (cfg);
8247                 } else {
8248                         /* FIXME: Is there a better way to do this?
8249                            We need the variable live for the duration
8250                            of the whole method. */
8251                         cfg->args [0]->flags |= MONO_INST_VOLATILE;
8252                 }
8253         }
8254
8255         /* add a check for this != NULL to inlined methods */
8256         if (is_virtual_call) {
8257                 MonoInst *arg_ins;
8258
8259                 NEW_ARGLOAD (cfg, arg_ins, 0);
8260                 MONO_ADD_INS (cfg->cbb, arg_ins);
8261                 MONO_EMIT_NEW_CHECK_THIS (cfg, arg_ins->dreg);
8262         }
8263
8264         skip_dead_blocks = !dont_verify;
8265         if (skip_dead_blocks) {
8266                 original_bb = bb = mono_basic_block_split (method, &cfg->error);
8267                 CHECK_CFG_ERROR;
8268                 g_assert (bb);
8269         }
8270
8271         /* we use a spare stack slot in SWITCH and NEWOBJ and others */
8272         stack_start = sp = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
8273
8274         ins_flag = 0;
8275         start_new_bblock = 0;
8276         while (ip < end) {
8277                 if (cfg->method == method)
8278                         cfg->real_offset = ip - header->code;
8279                 else
8280                         cfg->real_offset = inline_offset;
8281                 cfg->ip = ip;
8282
8283                 context_used = 0;
8284
8285                 if (start_new_bblock) {
8286                         cfg->cbb->cil_length = ip - cfg->cbb->cil_code;
8287                         if (start_new_bblock == 2) {
8288                                 g_assert (ip == tblock->cil_code);
8289                         } else {
8290                                 GET_BBLOCK (cfg, tblock, ip);
8291                         }
8292                         cfg->cbb->next_bb = tblock;
8293                         cfg->cbb = tblock;
8294                         start_new_bblock = 0;
8295                         for (i = 0; i < cfg->cbb->in_scount; ++i) {
8296                                 if (cfg->verbose_level > 3)
8297                                         printf ("loading %d from temp %d\n", i, (int)cfg->cbb->in_stack [i]->inst_c0);
8298                                 EMIT_NEW_TEMPLOAD (cfg, ins, cfg->cbb->in_stack [i]->inst_c0);
8299                                 *sp++ = ins;
8300                         }
8301                         if (class_inits)
8302                                 g_slist_free (class_inits);
8303                         class_inits = NULL;
8304                 } else {
8305                         if ((tblock = cfg->cil_offset_to_bb [ip - cfg->cil_start]) && (tblock != cfg->cbb)) {
8306                                 link_bblock (cfg, cfg->cbb, tblock);
8307                                 if (sp != stack_start) {
8308                                         handle_stack_args (cfg, stack_start, sp - stack_start);
8309                                         sp = stack_start;
8310                                         CHECK_UNVERIFIABLE (cfg);
8311                                 }
8312                                 cfg->cbb->next_bb = tblock;
8313                                 cfg->cbb = tblock;
8314                                 for (i = 0; i < cfg->cbb->in_scount; ++i) {
8315                                         if (cfg->verbose_level > 3)
8316                                                 printf ("loading %d from temp %d\n", i, (int)cfg->cbb->in_stack [i]->inst_c0);
8317                                         EMIT_NEW_TEMPLOAD (cfg, ins, cfg->cbb->in_stack [i]->inst_c0);
8318                                         *sp++ = ins;
8319                                 }
8320                                 g_slist_free (class_inits);
8321                                 class_inits = NULL;
8322                         }
8323                 }
8324
8325                 if (skip_dead_blocks) {
8326                         int ip_offset = ip - header->code;
8327
8328                         if (ip_offset == bb->end)
8329                                 bb = bb->next;
8330
8331                         if (bb->dead) {
8332                                 int op_size = mono_opcode_size (ip, end);
8333                                 g_assert (op_size > 0); /*The BB formation pass must catch all bad ops*/
8334
8335                                 if (cfg->verbose_level > 3) printf ("SKIPPING DEAD OP at %x\n", ip_offset);
8336
8337                                 if (ip_offset + op_size == bb->end) {
8338                                         MONO_INST_NEW (cfg, ins, OP_NOP);
8339                                         MONO_ADD_INS (cfg->cbb, ins);
8340                                         start_new_bblock = 1;
8341                                 }
8342
8343                                 ip += op_size;
8344                                 continue;
8345                         }
8346                 }
8347                 /*
8348                  * Sequence points are points where the debugger can place a breakpoint.
8349                  * Currently, we generate these automatically at points where the IL
8350                  * stack is empty.
8351                  */
8352                 if (seq_points && ((!sym_seq_points && (sp == stack_start)) || (sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code)))) {
8353                         /*
8354                          * Make methods interruptable at the beginning, and at the targets of
8355                          * backward branches.
8356                          * Also, do this at the start of every bblock in methods with clauses too,
8357                          * to be able to handle instructions with inprecise control flow like
8358                          * throw/endfinally.
8359                          * Backward branches are handled at the end of method-to-ir ().
8360                          */
8361                         gboolean intr_loc = ip == header->code || (!cfg->cbb->last_ins && cfg->header->num_clauses);
8362                         gboolean sym_seq_point = sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code);
8363
8364                         /* Avoid sequence points on empty IL like .volatile */
8365                         // FIXME: Enable this
8366                         //if (!(cfg->cbb->last_ins && cfg->cbb->last_ins->opcode == OP_SEQ_POINT)) {
8367                         NEW_SEQ_POINT (cfg, ins, ip - header->code, intr_loc);
8368                         if ((sp != stack_start) && !sym_seq_point)
8369                                 ins->flags |= MONO_INST_NONEMPTY_STACK;
8370                         MONO_ADD_INS (cfg->cbb, ins);
8371
8372                         if (sym_seq_points)
8373                                 mono_bitset_set_fast (seq_point_set_locs, ip - header->code);
8374                 }
8375
8376                 cfg->cbb->real_offset = cfg->real_offset;
8377
8378                 if ((cfg->method == method) && cfg->coverage_info) {
8379                         guint32 cil_offset = ip - header->code;
8380                         cfg->coverage_info->data [cil_offset].cil_code = ip;
8381
8382                         /* TODO: Use an increment here */
8383 #if defined(TARGET_X86)
8384                         MONO_INST_NEW (cfg, ins, OP_STORE_MEM_IMM);
8385                         ins->inst_p0 = &(cfg->coverage_info->data [cil_offset].count);
8386                         ins->inst_imm = 1;
8387                         MONO_ADD_INS (cfg->cbb, ins);
8388 #else
8389                         EMIT_NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
8390                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, ins->dreg, 0, 1);
8391 #endif
8392                 }
8393
8394                 if (cfg->verbose_level > 3)
8395                         printf ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
8396
8397                 switch (*ip) {
8398                 case CEE_NOP:
8399                         if (seq_points && !sym_seq_points && sp != stack_start) {
8400                                 /*
8401                                  * The C# compiler uses these nops to notify the JIT that it should
8402                                  * insert seq points.
8403                                  */
8404                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, FALSE);
8405                                 MONO_ADD_INS (cfg->cbb, ins);
8406                         }
8407                         if (cfg->keep_cil_nops)
8408                                 MONO_INST_NEW (cfg, ins, OP_HARD_NOP);
8409                         else
8410                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8411                         ip++;
8412                         MONO_ADD_INS (cfg->cbb, ins);
8413                         break;
8414                 case CEE_BREAK:
8415                         if (should_insert_brekpoint (cfg->method)) {
8416                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
8417                         } else {
8418                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8419                         }
8420                         ip++;
8421                         MONO_ADD_INS (cfg->cbb, ins);
8422                         break;
8423                 case CEE_LDARG_0:
8424                 case CEE_LDARG_1:
8425                 case CEE_LDARG_2:
8426                 case CEE_LDARG_3:
8427                         CHECK_STACK_OVF (1);
8428                         n = (*ip)-CEE_LDARG_0;
8429                         CHECK_ARG (n);
8430                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8431                         ip++;
8432                         *sp++ = ins;
8433                         break;
8434                 case CEE_LDLOC_0:
8435                 case CEE_LDLOC_1:
8436                 case CEE_LDLOC_2:
8437                 case CEE_LDLOC_3:
8438                         CHECK_STACK_OVF (1);
8439                         n = (*ip)-CEE_LDLOC_0;
8440                         CHECK_LOCAL (n);
8441                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8442                         ip++;
8443                         *sp++ = ins;
8444                         break;
8445                 case CEE_STLOC_0:
8446                 case CEE_STLOC_1:
8447                 case CEE_STLOC_2:
8448                 case CEE_STLOC_3: {
8449                         CHECK_STACK (1);
8450                         n = (*ip)-CEE_STLOC_0;
8451                         CHECK_LOCAL (n);
8452                         --sp;
8453                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
8454                                 UNVERIFIED;
8455                         emit_stloc_ir (cfg, sp, header, n);
8456                         ++ip;
8457                         inline_costs += 1;
8458                         break;
8459                         }
8460                 case CEE_LDARG_S:
8461                         CHECK_OPSIZE (2);
8462                         CHECK_STACK_OVF (1);
8463                         n = ip [1];
8464                         CHECK_ARG (n);
8465                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8466                         *sp++ = ins;
8467                         ip += 2;
8468                         break;
8469                 case CEE_LDARGA_S:
8470                         CHECK_OPSIZE (2);
8471                         CHECK_STACK_OVF (1);
8472                         n = ip [1];
8473                         CHECK_ARG (n);
8474                         NEW_ARGLOADA (cfg, ins, n);
8475                         MONO_ADD_INS (cfg->cbb, ins);
8476                         *sp++ = ins;
8477                         ip += 2;
8478                         break;
8479                 case CEE_STARG_S:
8480                         CHECK_OPSIZE (2);
8481                         CHECK_STACK (1);
8482                         --sp;
8483                         n = ip [1];
8484                         CHECK_ARG (n);
8485                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [ip [1]], *sp))
8486                                 UNVERIFIED;
8487                         EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
8488                         ip += 2;
8489                         break;
8490                 case CEE_LDLOC_S:
8491                         CHECK_OPSIZE (2);
8492                         CHECK_STACK_OVF (1);
8493                         n = ip [1];
8494                         CHECK_LOCAL (n);
8495                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8496                         *sp++ = ins;
8497                         ip += 2;
8498                         break;
8499                 case CEE_LDLOCA_S: {
8500                         unsigned char *tmp_ip;
8501                         CHECK_OPSIZE (2);
8502                         CHECK_STACK_OVF (1);
8503                         CHECK_LOCAL (ip [1]);
8504
8505                         if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 1))) {
8506                                 ip = tmp_ip;
8507                                 inline_costs += 1;
8508                                 break;
8509                         }
8510
8511                         EMIT_NEW_LOCLOADA (cfg, ins, ip [1]);
8512                         *sp++ = ins;
8513                         ip += 2;
8514                         break;
8515                 }
8516                 case CEE_STLOC_S:
8517                         CHECK_OPSIZE (2);
8518                         CHECK_STACK (1);
8519                         --sp;
8520                         CHECK_LOCAL (ip [1]);
8521                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [ip [1]], *sp))
8522                                 UNVERIFIED;
8523                         emit_stloc_ir (cfg, sp, header, ip [1]);
8524                         ip += 2;
8525                         inline_costs += 1;
8526                         break;
8527                 case CEE_LDNULL:
8528                         CHECK_STACK_OVF (1);
8529                         EMIT_NEW_PCONST (cfg, ins, NULL);
8530                         ins->type = STACK_OBJ;
8531                         ++ip;
8532                         *sp++ = ins;
8533                         break;
8534                 case CEE_LDC_I4_M1:
8535                         CHECK_STACK_OVF (1);
8536                         EMIT_NEW_ICONST (cfg, ins, -1);
8537                         ++ip;
8538                         *sp++ = ins;
8539                         break;
8540                 case CEE_LDC_I4_0:
8541                 case CEE_LDC_I4_1:
8542                 case CEE_LDC_I4_2:
8543                 case CEE_LDC_I4_3:
8544                 case CEE_LDC_I4_4:
8545                 case CEE_LDC_I4_5:
8546                 case CEE_LDC_I4_6:
8547                 case CEE_LDC_I4_7:
8548                 case CEE_LDC_I4_8:
8549                         CHECK_STACK_OVF (1);
8550                         EMIT_NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
8551                         ++ip;
8552                         *sp++ = ins;
8553                         break;
8554                 case CEE_LDC_I4_S:
8555                         CHECK_OPSIZE (2);
8556                         CHECK_STACK_OVF (1);
8557                         ++ip;
8558                         EMIT_NEW_ICONST (cfg, ins, *((signed char*)ip));
8559                         ++ip;
8560                         *sp++ = ins;
8561                         break;
8562                 case CEE_LDC_I4:
8563                         CHECK_OPSIZE (5);
8564                         CHECK_STACK_OVF (1);
8565                         EMIT_NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
8566                         ip += 5;
8567                         *sp++ = ins;
8568                         break;
8569                 case CEE_LDC_I8:
8570                         CHECK_OPSIZE (9);
8571                         CHECK_STACK_OVF (1);
8572                         MONO_INST_NEW (cfg, ins, OP_I8CONST);
8573                         ins->type = STACK_I8;
8574                         ins->dreg = alloc_dreg (cfg, STACK_I8);
8575                         ++ip;
8576                         ins->inst_l = (gint64)read64 (ip);
8577                         MONO_ADD_INS (cfg->cbb, ins);
8578                         ip += 8;
8579                         *sp++ = ins;
8580                         break;
8581                 case CEE_LDC_R4: {
8582                         float *f;
8583                         gboolean use_aotconst = FALSE;
8584
8585 #ifdef TARGET_POWERPC
8586                         /* FIXME: Clean this up */
8587                         if (cfg->compile_aot)
8588                                 use_aotconst = TRUE;
8589 #endif
8590
8591                         /* FIXME: we should really allocate this only late in the compilation process */
8592                         f = mono_domain_alloc (cfg->domain, sizeof (float));
8593                         CHECK_OPSIZE (5);
8594                         CHECK_STACK_OVF (1);
8595
8596                         if (use_aotconst) {
8597                                 MonoInst *cons;
8598                                 int dreg;
8599
8600                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R4, f);
8601
8602                                 dreg = alloc_freg (cfg);
8603                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR4_MEMBASE, dreg, cons->dreg, 0);
8604                                 ins->type = cfg->r4_stack_type;
8605                         } else {
8606                                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
8607                                 ins->type = cfg->r4_stack_type;
8608                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8609                                 ins->inst_p0 = f;
8610                                 MONO_ADD_INS (cfg->cbb, ins);
8611                         }
8612                         ++ip;
8613                         readr4 (ip, f);
8614                         ip += 4;
8615                         *sp++ = ins;                    
8616                         break;
8617                 }
8618                 case CEE_LDC_R8: {
8619                         double *d;
8620                         gboolean use_aotconst = FALSE;
8621
8622 #ifdef TARGET_POWERPC
8623                         /* FIXME: Clean this up */
8624                         if (cfg->compile_aot)
8625                                 use_aotconst = TRUE;
8626 #endif
8627
8628                         /* FIXME: we should really allocate this only late in the compilation process */
8629                         d = mono_domain_alloc (cfg->domain, sizeof (double));
8630                         CHECK_OPSIZE (9);
8631                         CHECK_STACK_OVF (1);
8632
8633                         if (use_aotconst) {
8634                                 MonoInst *cons;
8635                                 int dreg;
8636
8637                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R8, d);
8638
8639                                 dreg = alloc_freg (cfg);
8640                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR8_MEMBASE, dreg, cons->dreg, 0);
8641                                 ins->type = STACK_R8;
8642                         } else {
8643                                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
8644                                 ins->type = STACK_R8;
8645                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8646                                 ins->inst_p0 = d;
8647                                 MONO_ADD_INS (cfg->cbb, ins);
8648                         }
8649                         ++ip;
8650                         readr8 (ip, d);
8651                         ip += 8;
8652                         *sp++ = ins;
8653                         break;
8654                 }
8655                 case CEE_DUP: {
8656                         MonoInst *temp, *store;
8657                         CHECK_STACK (1);
8658                         CHECK_STACK_OVF (1);
8659                         sp--;
8660                         ins = *sp;
8661
8662                         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
8663                         EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
8664
8665                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8666                         *sp++ = ins;
8667
8668                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8669                         *sp++ = ins;
8670
8671                         ++ip;
8672                         inline_costs += 2;
8673                         break;
8674                 }
8675                 case CEE_POP:
8676                         CHECK_STACK (1);
8677                         ip++;
8678                         --sp;
8679
8680 #ifdef TARGET_X86
8681                         if (sp [0]->type == STACK_R8)
8682                                 /* we need to pop the value from the x86 FP stack */
8683                                 MONO_EMIT_NEW_UNALU (cfg, OP_X86_FPOP, -1, sp [0]->dreg);
8684 #endif
8685                         break;
8686                 case CEE_JMP: {
8687                         MonoCallInst *call;
8688                         MonoMethodSignature *fsig;
8689                         int i, n;
8690
8691                         INLINE_FAILURE ("jmp");
8692                         GSHAREDVT_FAILURE (*ip);
8693
8694                         CHECK_OPSIZE (5);
8695                         if (stack_start != sp)
8696                                 UNVERIFIED;
8697                         token = read32 (ip + 1);
8698                         /* FIXME: check the signature matches */
8699                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
8700
8701                         if (!cmethod || mono_loader_get_last_error ())
8702                                 LOAD_ERROR;
8703  
8704                         if (cfg->gshared && mono_method_check_context_used (cmethod))
8705                                 GENERIC_SHARING_FAILURE (CEE_JMP);
8706
8707                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
8708
8709                         fsig = mono_method_signature (cmethod);
8710                         n = fsig->param_count + fsig->hasthis;
8711                         if (cfg->llvm_only) {
8712                                 MonoInst **args;
8713
8714                                 args = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
8715                                 for (i = 0; i < n; ++i)
8716                                         EMIT_NEW_ARGLOAD (cfg, args [i], i);
8717                                 ins = mono_emit_method_call_full (cfg, cmethod, fsig, TRUE, args, NULL, NULL, NULL);
8718                                 /*
8719                                  * The code in mono-basic-block.c treats the rest of the code as dead, but we
8720                                  * have to emit a normal return since llvm expects it.
8721                                  */
8722                                 if (cfg->ret)
8723                                         emit_setret (cfg, ins);
8724                                 MONO_INST_NEW (cfg, ins, OP_BR);
8725                                 ins->inst_target_bb = end_bblock;
8726                                 MONO_ADD_INS (cfg->cbb, ins);
8727                                 link_bblock (cfg, cfg->cbb, end_bblock);
8728                                 ip += 5;
8729                                 break;
8730                         } else if (cfg->backend->have_op_tail_call) {
8731                                 /* Handle tail calls similarly to calls */
8732                                 DISABLE_AOT (cfg);
8733
8734                                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
8735                                 call->method = cmethod;
8736                                 call->tail_call = TRUE;
8737                                 call->signature = mono_method_signature (cmethod);
8738                                 call->args = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
8739                                 call->inst.inst_p0 = cmethod;
8740                                 for (i = 0; i < n; ++i)
8741                                         EMIT_NEW_ARGLOAD (cfg, call->args [i], i);
8742
8743                                 mono_arch_emit_call (cfg, call);
8744                                 cfg->param_area = MAX(cfg->param_area, call->stack_usage);
8745                                 MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
8746                         } else {
8747                                 for (i = 0; i < num_args; ++i)
8748                                         /* Prevent arguments from being optimized away */
8749                                         arg_array [i]->flags |= MONO_INST_VOLATILE;
8750
8751                                 MONO_INST_NEW_CALL (cfg, call, OP_JMP);
8752                                 ins = (MonoInst*)call;
8753                                 ins->inst_p0 = cmethod;
8754                                 MONO_ADD_INS (cfg->cbb, ins);
8755                         }
8756
8757                         ip += 5;
8758                         start_new_bblock = 1;
8759                         break;
8760                 }
8761                 case CEE_CALLI: {
8762                         MonoInst *addr;
8763                         MonoMethodSignature *fsig;
8764
8765                         CHECK_OPSIZE (5);
8766                         token = read32 (ip + 1);
8767
8768                         ins = NULL;
8769
8770                         //GSHAREDVT_FAILURE (*ip);
8771                         cmethod = NULL;
8772                         CHECK_STACK (1);
8773                         --sp;
8774                         addr = *sp;
8775                         fsig = mini_get_signature (method, token, generic_context);
8776
8777                         if (method->dynamic && fsig->pinvoke) {
8778                                 MonoInst *args [3];
8779
8780                                 /*
8781                                  * This is a call through a function pointer using a pinvoke
8782                                  * signature. Have to create a wrapper and call that instead.
8783                                  * FIXME: This is very slow, need to create a wrapper at JIT time
8784                                  * instead based on the signature.
8785                                  */
8786                                 EMIT_NEW_IMAGECONST (cfg, args [0], method->klass->image);
8787                                 EMIT_NEW_PCONST (cfg, args [1], fsig);
8788                                 args [2] = addr;
8789                                 addr = mono_emit_jit_icall (cfg, mono_get_native_calli_wrapper, args);
8790                         }
8791
8792                         n = fsig->param_count + fsig->hasthis;
8793
8794                         CHECK_STACK (n);
8795
8796                         //g_assert (!virtual || fsig->hasthis);
8797
8798                         sp -= n;
8799
8800                         inline_costs += 10 * num_calls++;
8801
8802                         /*
8803                          * Making generic calls out of gsharedvt methods.
8804                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
8805                          * patching gshared method addresses into a gsharedvt method.
8806                          */
8807                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
8808                                 /*
8809                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
8810                                  */
8811                                 MonoInst *callee = addr;
8812
8813                                 if (method->wrapper_type != MONO_WRAPPER_DELEGATE_INVOKE)
8814                                         /* Not tested */
8815                                         GSHAREDVT_FAILURE (*ip);
8816
8817                                 addr = emit_get_rgctx_sig (cfg, context_used,
8818                                                                                           fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
8819                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
8820                                 goto calli_end;
8821                         }
8822
8823                         /* Prevent inlining of methods with indirect calls */
8824                         INLINE_FAILURE ("indirect call");
8825
8826                         if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST || addr->opcode == OP_GOT_ENTRY) {
8827                                 int info_type;
8828                                 gpointer info_data;
8829
8830                                 /*
8831                                  * Instead of emitting an indirect call, emit a direct call
8832                                  * with the contents of the aotconst as the patch info.
8833                                  */
8834                                 if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST) {
8835                                         info_type = addr->inst_c1;
8836                                         info_data = addr->inst_p0;
8837                                 } else {
8838                                         info_type = addr->inst_right->inst_c1;
8839                                         info_data = addr->inst_right->inst_left;
8840                                 }
8841
8842                                 if (info_type == MONO_PATCH_INFO_ICALL_ADDR || info_type == MONO_PATCH_INFO_JIT_ICALL_ADDR) {
8843                                         ins = (MonoInst*)mono_emit_abs_call (cfg, info_type, info_data, fsig, sp);
8844                                         NULLIFY_INS (addr);
8845                                         goto calli_end;
8846                                 }
8847                         }
8848                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8849
8850                         calli_end:
8851
8852                         /* End of call, INS should contain the result of the call, if any */
8853
8854                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8855                                 g_assert (ins);
8856                                 *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
8857                         }
8858
8859                         CHECK_CFG_EXCEPTION;
8860
8861                         ip += 5;
8862                         ins_flag = 0;
8863                         constrained_class = NULL;
8864                         break;
8865                 }
8866                 case CEE_CALL:
8867                 case CEE_CALLVIRT: {
8868                         MonoInst *addr = NULL;
8869                         MonoMethodSignature *fsig = NULL;
8870                         int array_rank = 0;
8871                         int virtual = *ip == CEE_CALLVIRT;
8872                         gboolean pass_imt_from_rgctx = FALSE;
8873                         MonoInst *imt_arg = NULL;
8874                         MonoInst *keep_this_alive = NULL;
8875                         gboolean pass_vtable = FALSE;
8876                         gboolean pass_mrgctx = FALSE;
8877                         MonoInst *vtable_arg = NULL;
8878                         gboolean check_this = FALSE;
8879                         gboolean supported_tail_call = FALSE;
8880                         gboolean tail_call = FALSE;
8881                         gboolean need_seq_point = FALSE;
8882                         guint32 call_opcode = *ip;
8883                         gboolean emit_widen = TRUE;
8884                         gboolean push_res = TRUE;
8885                         gboolean skip_ret = FALSE;
8886                         gboolean delegate_invoke = FALSE;
8887                         gboolean direct_icall = FALSE;
8888                         gboolean constrained_partial_call = FALSE;
8889                         MonoMethod *cil_method;
8890
8891                         CHECK_OPSIZE (5);
8892                         token = read32 (ip + 1);
8893
8894                         ins = NULL;
8895
8896                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
8897                         cil_method = cmethod;
8898                                 
8899                         if (constrained_class) {
8900                                 if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->gshared) {
8901                                         if (!mini_is_gsharedvt_klass (constrained_class)) {
8902                                                 g_assert (!cmethod->klass->valuetype);
8903                                                 if (!mini_type_is_reference (&constrained_class->byval_arg))
8904                                                         constrained_partial_call = TRUE;
8905                                         }
8906                                 }
8907
8908                                 if (method->wrapper_type != MONO_WRAPPER_NONE) {
8909                                         if (cfg->verbose_level > 2)
8910                                                 printf ("DM Constrained call to %s\n", mono_type_get_full_name (constrained_class));
8911                                         if (!((constrained_class->byval_arg.type == MONO_TYPE_VAR ||
8912                                                    constrained_class->byval_arg.type == MONO_TYPE_MVAR) &&
8913                                                   cfg->gshared)) {
8914                                                 cmethod = mono_get_method_constrained_with_method (image, cil_method, constrained_class, generic_context, &cfg->error);
8915                                                 CHECK_CFG_ERROR;
8916                                         }
8917                                 } else {
8918                                         if (cfg->verbose_level > 2)
8919                                                 printf ("Constrained call to %s\n", mono_type_get_full_name (constrained_class));
8920
8921                                         if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->gshared) {
8922                                                 /* 
8923                                                  * This is needed since get_method_constrained can't find 
8924                                                  * the method in klass representing a type var.
8925                                                  * The type var is guaranteed to be a reference type in this
8926                                                  * case.
8927                                                  */
8928                                                 if (!mini_is_gsharedvt_klass (constrained_class))
8929                                                         g_assert (!cmethod->klass->valuetype);
8930                                         } else {
8931                                                 cmethod = mono_get_method_constrained_checked (image, token, constrained_class, generic_context, &cil_method, &cfg->error);
8932                                                 CHECK_CFG_ERROR;
8933                                         }
8934                                 }
8935                         }
8936                                         
8937                         if (!cmethod || mono_loader_get_last_error ())
8938                                 LOAD_ERROR;
8939                         if (!dont_verify && !cfg->skip_visibility) {
8940                                 MonoMethod *target_method = cil_method;
8941                                 if (method->is_inflated) {
8942                                         target_method = mini_get_method_allow_open (method, token, NULL, &(mono_method_get_generic_container (method_definition)->context));
8943                                 }
8944                                 if (!mono_method_can_access_method (method_definition, target_method) &&
8945                                         !mono_method_can_access_method (method, cil_method))
8946                                         METHOD_ACCESS_FAILURE (method, cil_method);
8947                         }
8948
8949                         if (mono_security_core_clr_enabled ())
8950                                 ensure_method_is_allowed_to_call_method (cfg, method, cil_method);
8951
8952                         if (!virtual && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
8953                                 /* MS.NET seems to silently convert this to a callvirt */
8954                                 virtual = 1;
8955
8956                         {
8957                                 /*
8958                                  * MS.NET accepts non virtual calls to virtual final methods of transparent proxy classes and
8959                                  * converts to a callvirt.
8960                                  *
8961                                  * tests/bug-515884.il is an example of this behavior
8962                                  */
8963                                 const int test_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_STATIC;
8964                                 const int expected_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL;
8965                                 if (!virtual && mono_class_is_marshalbyref (cmethod->klass) && (cmethod->flags & test_flags) == expected_flags && cfg->method->wrapper_type == MONO_WRAPPER_NONE)
8966                                         virtual = 1;
8967                         }
8968
8969                         if (!cmethod->klass->inited)
8970                                 if (!mono_class_init (cmethod->klass))
8971                                         TYPE_LOAD_ERROR (cmethod->klass);
8972
8973                         fsig = mono_method_signature (cmethod);
8974                         if (!fsig)
8975                                 LOAD_ERROR;
8976                         if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
8977                                 mini_class_is_system_array (cmethod->klass)) {
8978                                 array_rank = cmethod->klass->rank;
8979                         } else if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && icall_is_direct_callable (cfg, cmethod)) {
8980                                 direct_icall = TRUE;
8981                         } else if (fsig->pinvoke) {
8982                                 MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
8983                                 fsig = mono_method_signature (wrapper);
8984                         } else if (constrained_class) {
8985                         } else {
8986                                 fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
8987                                 CHECK_CFG_ERROR;
8988                         }
8989
8990                         /* See code below */
8991                         if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
8992                                 MonoBasicBlock *tbb;
8993
8994                                 GET_BBLOCK (cfg, tbb, ip + 5);
8995                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
8996                                         /*
8997                                          * We want to extend the try block to cover the call, but we can't do it if the
8998                                          * call is made directly since its followed by an exception check.
8999                                          */
9000                                         direct_icall = FALSE;
9001                                 }
9002                         }
9003
9004                         mono_save_token_info (cfg, image, token, cil_method);
9005
9006                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip + 5 - header->code)))
9007                                 need_seq_point = TRUE;
9008
9009                         /* Don't support calls made using type arguments for now */
9010                         /*
9011                           if (cfg->gsharedvt) {
9012                           if (mini_is_gsharedvt_signature (fsig))
9013                           GSHAREDVT_FAILURE (*ip);
9014                           }
9015                         */
9016
9017                         if (cmethod->string_ctor && method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE)
9018                                 g_assert_not_reached ();
9019
9020                         n = fsig->param_count + fsig->hasthis;
9021
9022                         if (!cfg->gshared && cmethod->klass->generic_container)
9023                                 UNVERIFIED;
9024
9025                         if (!cfg->gshared)
9026                                 g_assert (!mono_method_check_context_used (cmethod));
9027
9028                         CHECK_STACK (n);
9029
9030                         //g_assert (!virtual || fsig->hasthis);
9031
9032                         sp -= n;
9033
9034                         if (constrained_class) {
9035                                 if (mini_is_gsharedvt_klass (constrained_class)) {
9036                                         if ((cmethod->klass != mono_defaults.object_class) && constrained_class->valuetype && cmethod->klass->valuetype) {
9037                                                 /* The 'Own method' case below */
9038                                         } else if (cmethod->klass->image != mono_defaults.corlib && !(cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !cmethod->klass->valuetype) {
9039                                                 /* 'The type parameter is instantiated as a reference type' case below. */
9040                                         } else {
9041                                                 ins = handle_constrained_gsharedvt_call (cfg, cmethod, fsig, sp, constrained_class, &emit_widen);
9042                                                 CHECK_CFG_EXCEPTION;
9043                                                 g_assert (ins);
9044                                                 goto call_end;
9045                                         }
9046                                 }
9047
9048                                 /*
9049                                  * We have the `constrained.' prefix opcode.
9050                                  */
9051                                 if (constrained_partial_call) {
9052                                         gboolean need_box = TRUE;
9053
9054                                         /*
9055                                          * The receiver is a valuetype, but the exact type is not known at compile time. This means the
9056                                          * called method is not known at compile time either. The called method could end up being
9057                                          * one of the methods on the parent classes (object/valuetype/enum), in which case we need
9058                                          * to box the receiver.
9059                                          * A simple solution would be to box always and make a normal virtual call, but that would
9060                                          * be bad performance wise.
9061                                          */
9062                                         if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE && cmethod->klass->generic_class) {
9063                                                 /*
9064                                                  * The parent classes implement no generic interfaces, so the called method will be a vtype method, so no boxing neccessary.
9065                                                  */
9066                                                 need_box = FALSE;
9067                                         }
9068
9069                                         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)) {
9070                                                 /* The called method is not virtual, i.e. Object:GetType (), the receiver is a vtype, has to box */
9071                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9072                                                 ins->klass = constrained_class;
9073                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9074                                                 CHECK_CFG_EXCEPTION;
9075                                         } else if (need_box) {
9076                                                 MonoInst *box_type;
9077                                                 MonoBasicBlock *is_ref_bb, *end_bb;
9078                                                 MonoInst *nonbox_call;
9079
9080                                                 /*
9081                                                  * Determine at runtime whenever the called method is defined on object/valuetype/enum, and emit a boxing call
9082                                                  * if needed.
9083                                                  * FIXME: It is possible to inline the called method in a lot of cases, i.e. for T_INT,
9084                                                  * the no-box case goes to a method in Int32, while the box case goes to a method in Enum.
9085                                                  */
9086                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
9087
9088                                                 NEW_BBLOCK (cfg, is_ref_bb);
9089                                                 NEW_BBLOCK (cfg, end_bb);
9090
9091                                                 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);
9092                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, box_type->dreg, 1);
9093                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
9094
9095                                                 /* Non-ref case */
9096                                                 nonbox_call = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9097
9098                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
9099
9100                                                 /* Ref case */
9101                                                 MONO_START_BB (cfg, is_ref_bb);
9102                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9103                                                 ins->klass = constrained_class;
9104                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9105                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9106
9107                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
9108
9109                                                 MONO_START_BB (cfg, end_bb);
9110                                                 cfg->cbb = end_bb;
9111
9112                                                 nonbox_call->dreg = ins->dreg;
9113                                                 goto call_end;
9114                                         } else {
9115                                                 g_assert (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE);
9116                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
9117                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9118                                                 goto call_end;
9119                                         }
9120                                 } else if (constrained_class->valuetype && (cmethod->klass == mono_defaults.object_class || cmethod->klass == mono_defaults.enum_class->parent || cmethod->klass == mono_defaults.enum_class)) {
9121                                         /*
9122                                          * The type parameter is instantiated as a valuetype,
9123                                          * but that type doesn't override the method we're
9124                                          * calling, so we need to box `this'.
9125                                          */
9126                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9127                                         ins->klass = constrained_class;
9128                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9129                                         CHECK_CFG_EXCEPTION;
9130                                 } else if (!constrained_class->valuetype) {
9131                                         int dreg = alloc_ireg_ref (cfg);
9132
9133                                         /*
9134                                          * The type parameter is instantiated as a reference
9135                                          * type.  We have a managed pointer on the stack, so
9136                                          * we need to dereference it here.
9137                                          */
9138                                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, sp [0]->dreg, 0);
9139                                         ins->type = STACK_OBJ;
9140                                         sp [0] = ins;
9141                                 } else {
9142                                         if (cmethod->klass->valuetype) {
9143                                                 /* Own method */
9144                                         } else {
9145                                                 /* Interface method */
9146                                                 int ioffset, slot;
9147
9148                                                 mono_class_setup_vtable (constrained_class);
9149                                                 CHECK_TYPELOAD (constrained_class);
9150                                                 ioffset = mono_class_interface_offset (constrained_class, cmethod->klass);
9151                                                 if (ioffset == -1)
9152                                                         TYPE_LOAD_ERROR (constrained_class);
9153                                                 slot = mono_method_get_vtable_slot (cmethod);
9154                                                 if (slot == -1)
9155                                                         TYPE_LOAD_ERROR (cmethod->klass);
9156                                                 cmethod = constrained_class->vtable [ioffset + slot];
9157
9158                                                 if (cmethod->klass == mono_defaults.enum_class) {
9159                                                         /* Enum implements some interfaces, so treat this as the first case */
9160                                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9161                                                         ins->klass = constrained_class;
9162                                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9163                                                         CHECK_CFG_EXCEPTION;
9164                                                 }
9165                                         }
9166                                         virtual = 0;
9167                                 }
9168                                 constrained_class = NULL;
9169                         }
9170
9171                         if (check_call_signature (cfg, fsig, sp))
9172                                 UNVERIFIED;
9173
9174                         if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (cmethod->name, "Invoke"))
9175                                 delegate_invoke = TRUE;
9176
9177                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_sharable_method (cfg, cmethod, fsig, sp))) {
9178                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9179                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
9180                                         emit_widen = FALSE;
9181                                 }
9182
9183                                 goto call_end;
9184                         }
9185
9186                         /* 
9187                          * If the callee is a shared method, then its static cctor
9188                          * might not get called after the call was patched.
9189                          */
9190                         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)) {
9191                                 emit_class_init (cfg, cmethod->klass);
9192                                 CHECK_TYPELOAD (cmethod->klass);
9193                         }
9194
9195                         check_method_sharing (cfg, cmethod, &pass_vtable, &pass_mrgctx);
9196
9197                         if (cfg->gshared) {
9198                                 MonoGenericContext *cmethod_context = mono_method_get_context (cmethod);
9199
9200                                 context_used = mini_method_check_context_used (cfg, cmethod);
9201
9202                                 if (context_used && (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
9203                                         /* Generic method interface
9204                                            calls are resolved via a
9205                                            helper function and don't
9206                                            need an imt. */
9207                                         if (!cmethod_context || !cmethod_context->method_inst)
9208                                                 pass_imt_from_rgctx = TRUE;
9209                                 }
9210
9211                                 /*
9212                                  * If a shared method calls another
9213                                  * shared method then the caller must
9214                                  * have a generic sharing context
9215                                  * because the magic trampoline
9216                                  * requires it.  FIXME: We shouldn't
9217                                  * have to force the vtable/mrgctx
9218                                  * variable here.  Instead there
9219                                  * should be a flag in the cfg to
9220                                  * request a generic sharing context.
9221                                  */
9222                                 if (context_used &&
9223                                                 ((method->flags & METHOD_ATTRIBUTE_STATIC) || method->klass->valuetype))
9224                                         mono_get_vtable_var (cfg);
9225                         }
9226
9227                         if (pass_vtable) {
9228                                 if (context_used) {
9229                                         vtable_arg = emit_get_rgctx_klass (cfg, context_used, cmethod->klass, MONO_RGCTX_INFO_VTABLE);
9230                                 } else {
9231                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
9232
9233                                         CHECK_TYPELOAD (cmethod->klass);
9234                                         EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
9235                                 }
9236                         }
9237
9238                         if (pass_mrgctx) {
9239                                 g_assert (!vtable_arg);
9240
9241                                 if (!cfg->compile_aot) {
9242                                         /* 
9243                                          * emit_get_rgctx_method () calls mono_class_vtable () so check 
9244                                          * for type load errors before.
9245                                          */
9246                                         mono_class_setup_vtable (cmethod->klass);
9247                                         CHECK_TYPELOAD (cmethod->klass);
9248                                 }
9249
9250                                 vtable_arg = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
9251
9252                                 /* !marshalbyref is needed to properly handle generic methods + remoting */
9253                                 if ((!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
9254                                          MONO_METHOD_IS_FINAL (cmethod)) &&
9255                                         !mono_class_is_marshalbyref (cmethod->klass)) {
9256                                         if (virtual)
9257                                                 check_this = TRUE;
9258                                         virtual = 0;
9259                                 }
9260                         }
9261
9262                         if (pass_imt_from_rgctx) {
9263                                 g_assert (!pass_vtable);
9264
9265                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9266                                         cmethod, MONO_RGCTX_INFO_METHOD);
9267                         }
9268
9269                         if (check_this)
9270                                 MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9271
9272                         /* Calling virtual generic methods */
9273                         if (virtual && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) && 
9274                             !(MONO_METHOD_IS_FINAL (cmethod) && 
9275                               cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) &&
9276                             fsig->generic_param_count && 
9277                                 !(cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) &&
9278                                 !cfg->llvm_only) {
9279                                 MonoInst *this_temp, *this_arg_temp, *store;
9280                                 MonoInst *iargs [4];
9281
9282                                 g_assert (fsig->is_inflated);
9283
9284                                 /* Prevent inlining of methods that contain indirect calls */
9285                                 INLINE_FAILURE ("virtual generic call");
9286
9287                                 if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))
9288                                         GSHAREDVT_FAILURE (*ip);
9289
9290                                 if (cfg->backend->have_generalized_imt_thunk && cfg->backend->gshared_supported && cmethod->wrapper_type == MONO_WRAPPER_NONE) {
9291                                         g_assert (!imt_arg);
9292                                         if (!context_used)
9293                                                 g_assert (cmethod->is_inflated);
9294                                         imt_arg = emit_get_rgctx_method (cfg, context_used,
9295                                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
9296                                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, sp [0], imt_arg, NULL);
9297                                 } else {
9298                                         this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
9299                                         NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
9300                                         MONO_ADD_INS (cfg->cbb, store);
9301
9302                                         /* FIXME: This should be a managed pointer */
9303                                         this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
9304
9305                                         EMIT_NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
9306                                         iargs [1] = emit_get_rgctx_method (cfg, context_used,
9307                                                                                                            cmethod, MONO_RGCTX_INFO_METHOD);
9308                                         EMIT_NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
9309                                         addr = mono_emit_jit_icall (cfg,
9310                                                                                                 mono_helper_compile_generic_method, iargs);
9311
9312                                         EMIT_NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
9313
9314                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9315                                 }
9316
9317                                 goto call_end;
9318                         }
9319
9320                         /*
9321                          * Implement a workaround for the inherent races involved in locking:
9322                          * Monitor.Enter ()
9323                          * try {
9324                          * } finally {
9325                          *    Monitor.Exit ()
9326                          * }
9327                          * If a thread abort happens between the call to Monitor.Enter () and the start of the
9328                          * try block, the Exit () won't be executed, see:
9329                          * http://www.bluebytesoftware.com/blog/2007/01/30/MonitorEnterThreadAbortsAndOrphanedLocks.aspx
9330                          * To work around this, we extend such try blocks to include the last x bytes
9331                          * of the Monitor.Enter () call.
9332                          */
9333                         if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
9334                                 MonoBasicBlock *tbb;
9335
9336                                 GET_BBLOCK (cfg, tbb, ip + 5);
9337                                 /* 
9338                                  * Only extend try blocks with a finally, to avoid catching exceptions thrown
9339                                  * from Monitor.Enter like ArgumentNullException.
9340                                  */
9341                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
9342                                         /* Mark this bblock as needing to be extended */
9343                                         tbb->extend_try_block = TRUE;
9344                                 }
9345                         }
9346
9347                         /* Conversion to a JIT intrinsic */
9348                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_method (cfg, cmethod, fsig, sp))) {
9349                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9350                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
9351                                         emit_widen = FALSE;
9352                                 }
9353                                 goto call_end;
9354                         }
9355
9356                         /* Inlining */
9357                         if ((cfg->opt & MONO_OPT_INLINE) &&
9358                                 (!virtual || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || MONO_METHOD_IS_FINAL (cmethod)) &&
9359                             mono_method_check_inlining (cfg, cmethod)) {
9360                                 int costs;
9361                                 gboolean always = FALSE;
9362
9363                                 if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
9364                                         (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
9365                                         /* Prevent inlining of methods that call wrappers */
9366                                         INLINE_FAILURE ("wrapper call");
9367                                         cmethod = mono_marshal_get_native_wrapper (cmethod, TRUE, FALSE);
9368                                         always = TRUE;
9369                                 }
9370
9371                                 costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, always);
9372                                 if (costs) {
9373                                         cfg->real_offset += 5;
9374
9375                                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9376                                                 /* *sp is already set by inline_method */
9377                                                 sp++;
9378                                                 push_res = FALSE;
9379                                         }
9380
9381                                         inline_costs += costs;
9382
9383                                         goto call_end;
9384                                 }
9385                         }
9386
9387                         /* Tail recursion elimination */
9388                         if ((cfg->opt & MONO_OPT_TAILC) && call_opcode == CEE_CALL && cmethod == method && ip [5] == CEE_RET && !vtable_arg) {
9389                                 gboolean has_vtargs = FALSE;
9390                                 int i;
9391
9392                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9393                                 INLINE_FAILURE ("tail call");
9394
9395                                 /* keep it simple */
9396                                 for (i =  fsig->param_count - 1; i >= 0; i--) {
9397                                         if (MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->params [i])) 
9398                                                 has_vtargs = TRUE;
9399                                 }
9400
9401                                 if (!has_vtargs) {
9402                                         for (i = 0; i < n; ++i)
9403                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9404                                         MONO_INST_NEW (cfg, ins, OP_BR);
9405                                         MONO_ADD_INS (cfg->cbb, ins);
9406                                         tblock = start_bblock->out_bb [0];
9407                                         link_bblock (cfg, cfg->cbb, tblock);
9408                                         ins->inst_target_bb = tblock;
9409                                         start_new_bblock = 1;
9410
9411                                         /* skip the CEE_RET, too */
9412                                         if (ip_in_bb (cfg, cfg->cbb, ip + 5))
9413                                                 skip_ret = TRUE;
9414                                         push_res = FALSE;
9415                                         goto call_end;
9416                                 }
9417                         }
9418
9419                         inline_costs += 10 * num_calls++;
9420
9421                         /*
9422                          * Making generic calls out of gsharedvt methods.
9423                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
9424                          * patching gshared method addresses into a gsharedvt method.
9425                          */
9426                         if (cfg->gsharedvt && (mini_is_gsharedvt_signature (fsig) || cmethod->is_inflated || cmethod->klass->generic_class) &&
9427                                 !(cmethod->klass->rank && cmethod->klass->byval_arg.type != MONO_TYPE_SZARRAY)) {
9428                                 MonoRgctxInfoType info_type;
9429
9430                                 if (virtual) {
9431                                         //if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
9432                                                 //GSHAREDVT_FAILURE (*ip);
9433                                         // disable for possible remoting calls
9434                                         if (fsig->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class))
9435                                                 GSHAREDVT_FAILURE (*ip);
9436                                         if (fsig->generic_param_count) {
9437                                                 /* virtual generic call */
9438                                                 g_assert (!imt_arg);
9439                                                 /* Same as the virtual generic case above */
9440                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9441                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9442                                                 /* This is not needed, as the trampoline code will pass one, and it might be passed in the same reg as the imt arg */
9443                                                 vtable_arg = NULL;
9444                                         } else if ((cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !imt_arg) {
9445                                                 /* This can happen when we call a fully instantiated iface method */
9446                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9447                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9448                                                 vtable_arg = NULL;
9449                                         }
9450                                 }
9451
9452                                 if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (cmethod->name, "Invoke")))
9453                                         keep_this_alive = sp [0];
9454
9455                                 if (virtual && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))
9456                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
9457                                 else
9458                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE;
9459                                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, info_type);
9460
9461                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9462                                 goto call_end;
9463                         }
9464
9465                         /* Generic sharing */
9466
9467                         /*
9468                          * Use this if the callee is gsharedvt sharable too, since
9469                          * at runtime we might find an instantiation so the call cannot
9470                          * be patched (the 'no_patch' code path in mini-trampolines.c).
9471                          */
9472                         if (context_used && !imt_arg && !array_rank && !delegate_invoke &&
9473                                 (!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
9474                                  !mono_class_generic_sharing_enabled (cmethod->klass)) &&
9475                                 (!virtual || MONO_METHOD_IS_FINAL (cmethod) ||
9476                                  !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))) {
9477                                 INLINE_FAILURE ("gshared");
9478
9479                                 g_assert (cfg->gshared && cmethod);
9480                                 g_assert (!addr);
9481
9482                                 /*
9483                                  * We are compiling a call to a
9484                                  * generic method from shared code,
9485                                  * which means that we have to look up
9486                                  * the method in the rgctx and do an
9487                                  * indirect call.
9488                                  */
9489                                 if (fsig->hasthis)
9490                                         MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9491
9492                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
9493                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9494                                 goto call_end;
9495                         }
9496
9497                         /* Direct calls to icalls */
9498                         if (direct_icall) {
9499                                 MonoMethod *wrapper;
9500                                 int costs;
9501
9502                                 /* Inline the wrapper */
9503                                 wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
9504
9505                                 costs = inline_method (cfg, wrapper, fsig, sp, ip, cfg->real_offset, TRUE);
9506                                 g_assert (costs > 0);
9507                                 cfg->real_offset += 5;
9508
9509                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9510                                         /* *sp is already set by inline_method */
9511                                         sp++;
9512                                         push_res = FALSE;
9513                                 }
9514
9515                                 inline_costs += costs;
9516
9517                                 goto call_end;
9518                         }
9519                                         
9520                         /* Array methods */
9521                         if (array_rank) {
9522                                 MonoInst *addr;
9523
9524                                 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ 
9525                                         MonoInst *val = sp [fsig->param_count];
9526
9527                                         if (val->type == STACK_OBJ) {
9528                                                 MonoInst *iargs [2];
9529
9530                                                 iargs [0] = sp [0];
9531                                                 iargs [1] = val;
9532                                                 
9533                                                 mono_emit_jit_icall (cfg, mono_helper_stelem_ref_check, iargs);
9534                                         }
9535                                         
9536                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, TRUE);
9537                                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, fsig->params [fsig->param_count - 1], addr->dreg, 0, val->dreg);
9538                                         if (cfg->gen_write_barriers && val->type == STACK_OBJ && !(val->opcode == OP_PCONST && val->inst_c0 == 0))
9539                                                 emit_write_barrier (cfg, addr, val);
9540                                         if (cfg->gen_write_barriers && mini_is_gsharedvt_klass (cmethod->klass))
9541                                                 GSHAREDVT_FAILURE (*ip);
9542                                 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
9543                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9544
9545                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, addr->dreg, 0);
9546                                 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
9547                                         if (!cmethod->klass->element_class->valuetype && !readonly)
9548                                                 mini_emit_check_array_type (cfg, sp [0], cmethod->klass);
9549                                         CHECK_TYPELOAD (cmethod->klass);
9550                                         
9551                                         readonly = FALSE;
9552                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9553                                         ins = addr;
9554                                 } else {
9555                                         g_assert_not_reached ();
9556                                 }
9557
9558                                 emit_widen = FALSE;
9559                                 goto call_end;
9560                         }
9561
9562                         ins = mini_redirect_call (cfg, cmethod, fsig, sp, virtual ? sp [0] : NULL);
9563                         if (ins)
9564                                 goto call_end;
9565
9566                         /* Tail prefix / tail call optimization */
9567
9568                         /* FIXME: Enabling TAILC breaks some inlining/stack trace/etc tests */
9569                         /* FIXME: runtime generic context pointer for jumps? */
9570                         /* FIXME: handle this for generic sharing eventually */
9571                         if ((ins_flag & MONO_INST_TAILCALL) &&
9572                                 !vtable_arg && !cfg->gshared && is_supported_tail_call (cfg, method, cmethod, fsig, call_opcode))
9573                                 supported_tail_call = TRUE;
9574
9575                         if (supported_tail_call) {
9576                                 MonoCallInst *call;
9577
9578                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9579                                 INLINE_FAILURE ("tail call");
9580
9581                                 //printf ("HIT: %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
9582
9583                                 if (cfg->backend->have_op_tail_call) {
9584                                         /* Handle tail calls similarly to normal calls */
9585                                         tail_call = TRUE;
9586                                 } else {
9587                                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
9588
9589                                         MONO_INST_NEW_CALL (cfg, call, OP_JMP);
9590                                         call->tail_call = TRUE;
9591                                         call->method = cmethod;
9592                                         call->signature = mono_method_signature (cmethod);
9593
9594                                         /*
9595                                          * We implement tail calls by storing the actual arguments into the 
9596                                          * argument variables, then emitting a CEE_JMP.
9597                                          */
9598                                         for (i = 0; i < n; ++i) {
9599                                                 /* Prevent argument from being register allocated */
9600                                                 arg_array [i]->flags |= MONO_INST_VOLATILE;
9601                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9602                                         }
9603                                         ins = (MonoInst*)call;
9604                                         ins->inst_p0 = cmethod;
9605                                         ins->inst_p1 = arg_array [0];
9606                                         MONO_ADD_INS (cfg->cbb, ins);
9607                                         link_bblock (cfg, cfg->cbb, end_bblock);
9608                                         start_new_bblock = 1;
9609
9610                                         // FIXME: Eliminate unreachable epilogs
9611
9612                                         /*
9613                                          * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9614                                          * only reachable from this call.
9615                                          */
9616                                         GET_BBLOCK (cfg, tblock, ip + 5);
9617                                         if (tblock == cfg->cbb || tblock->in_count == 0)
9618                                                 skip_ret = TRUE;
9619                                         push_res = FALSE;
9620
9621                                         goto call_end;
9622                                 }
9623                         }
9624
9625                         /* 
9626                          * Synchronized wrappers.
9627                          * Its hard to determine where to replace a method with its synchronized
9628                          * wrapper without causing an infinite recursion. The current solution is
9629                          * to add the synchronized wrapper in the trampolines, and to
9630                          * change the called method to a dummy wrapper, and resolve that wrapper
9631                          * to the real method in mono_jit_compile_method ().
9632                          */
9633                         if (cfg->method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
9634                                 MonoMethod *orig = mono_marshal_method_from_wrapper (cfg->method);
9635                                 if (cmethod == orig || (cmethod->is_inflated && mono_method_get_declaring_generic_method (cmethod) == orig))
9636                                         cmethod = mono_marshal_get_synchronized_inner_wrapper (cmethod);
9637                         }
9638
9639                         /*
9640                          * Interface calls in llvm-only mode are complicated becase the callee might need an rgctx arg,
9641                          * (i.e. its a vtype method), and there is no way to for the caller to know this at compile time.
9642                          * So we make resolve_iface_call return the rgctx, and do two calls with different signatures
9643                          * based on whenever there is an rgctx or not.
9644                          */
9645                         if (cfg->llvm_only && virtual && cmethod && (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
9646                                 MonoInst *args_buf [16], *icall_args [16];
9647                                 MonoInst **args;
9648                                 MonoBasicBlock *rgctx_bb, *end_bb;
9649                                 MonoInst *call1, *call2, *call_target;
9650                                 MonoMethodSignature *rgctx_sig;
9651                                 int rgctx_reg, tmp_reg;
9652
9653                                 MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
9654
9655                                 NEW_BBLOCK (cfg, rgctx_bb);
9656                                 NEW_BBLOCK (cfg, end_bb);
9657
9658                                 // FIXME: Optimize this
9659
9660                                 guint32 imt_slot = mono_method_get_imt_slot (cmethod);
9661
9662                                 icall_args [0] = sp [0];
9663                                 EMIT_NEW_ICONST (cfg, icall_args [1], imt_slot);
9664                                 if (imt_arg) {
9665                                         icall_args [2] = imt_arg;
9666                                 } else {
9667                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_METHODCONST, cmethod);
9668                                         icall_args [2] = ins;
9669                                 }
9670
9671                                 rgctx_reg = alloc_preg (cfg);
9672                                 MONO_EMIT_NEW_PCONST (cfg, rgctx_reg, NULL);
9673                                 EMIT_NEW_VARLOADA_VREG (cfg, icall_args [3], rgctx_reg, &mono_defaults.int_class->byval_arg);
9674                                 //EMIT_NEW_PCONST (cfg, icall_args [3], NULL);
9675
9676                                 call_target = mono_emit_jit_icall (cfg, mono_resolve_iface_call, icall_args);
9677
9678                                 // FIXME: Only do this if needed (generic calls)
9679
9680                                 // Check whenever to pass an rgctx
9681                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rgctx_reg, 0);
9682                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, rgctx_bb);
9683                                 /* Non rgctx case */
9684                                 call1 = mono_emit_calli (cfg, fsig, sp, call_target, NULL, vtable_arg);
9685                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
9686                                 /* Rgctx case */
9687                                 MONO_START_BB (cfg, rgctx_bb);
9688                                 /* Make a call with an rgctx */
9689                                 if (fsig->param_count + 2 < 16)
9690                                         args = args_buf;
9691                                 else
9692                                         args = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (fsig->param_count + 2));
9693                                 args [0] = sp [0];
9694                                 for (i = 0; i < fsig->param_count; ++i)
9695                                         args [i + 1] = sp [i + 1];
9696                                 tmp_reg = alloc_preg (cfg);
9697                                 EMIT_NEW_UNALU (cfg, args [fsig->param_count + 1], OP_MOVE, tmp_reg, rgctx_reg);
9698                                 rgctx_sig = sig_to_rgctx_sig (fsig);
9699                                 call2 = mono_emit_calli (cfg, rgctx_sig, args, call_target, NULL, NULL);
9700                                 call2->dreg = call1->dreg;
9701                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
9702                                 /* End */
9703                                 MONO_START_BB (cfg, end_bb);
9704                                 ins = call1;
9705                                 goto call_end;
9706                         }
9707
9708                         /* Common call */
9709                         INLINE_FAILURE ("call");
9710                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, tail_call, sp, virtual ? sp [0] : NULL,
9711                                                                                           imt_arg, vtable_arg);
9712
9713                         if (tail_call && !cfg->llvm_only) {
9714                                 link_bblock (cfg, cfg->cbb, end_bblock);
9715                                 start_new_bblock = 1;
9716
9717                                 // FIXME: Eliminate unreachable epilogs
9718
9719                                 /*
9720                                  * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9721                                  * only reachable from this call.
9722                                  */
9723                                 GET_BBLOCK (cfg, tblock, ip + 5);
9724                                 if (tblock == cfg->cbb || tblock->in_count == 0)
9725                                         skip_ret = TRUE;
9726                                 push_res = FALSE;
9727                         }
9728
9729                         call_end:
9730
9731                         /* End of call, INS should contain the result of the call, if any */
9732
9733                         if (push_res && !MONO_TYPE_IS_VOID (fsig->ret)) {
9734                                 g_assert (ins);
9735                                 if (emit_widen)
9736                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
9737                                 else
9738                                         *sp++ = ins;
9739                         }
9740
9741                         if (keep_this_alive) {
9742                                 MonoInst *dummy_use;
9743
9744                                 /* See mono_emit_method_call_full () */
9745                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, keep_this_alive);
9746                         }
9747
9748                         CHECK_CFG_EXCEPTION;
9749
9750                         ip += 5;
9751                         if (skip_ret) {
9752                                 g_assert (*ip == CEE_RET);
9753                                 ip += 1;
9754                         }
9755                         ins_flag = 0;
9756                         constrained_class = NULL;
9757                         if (need_seq_point)
9758                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
9759                         break;
9760                 }
9761                 case CEE_RET:
9762                         if (cfg->method != method) {
9763                                 /* return from inlined method */
9764                                 /* 
9765                                  * If in_count == 0, that means the ret is unreachable due to
9766                                  * being preceeded by a throw. In that case, inline_method () will
9767                                  * handle setting the return value 
9768                                  * (test case: test_0_inline_throw ()).
9769                                  */
9770                                 if (return_var && cfg->cbb->in_count) {
9771                                         MonoType *ret_type = mono_method_signature (method)->ret;
9772
9773                                         MonoInst *store;
9774                                         CHECK_STACK (1);
9775                                         --sp;
9776
9777                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
9778                                                 UNVERIFIED;
9779
9780                                         //g_assert (returnvar != -1);
9781                                         EMIT_NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
9782                                         cfg->ret_var_set = TRUE;
9783                                 } 
9784                         } else {
9785                                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
9786
9787                                 if (cfg->lmf_var && cfg->cbb->in_count && !cfg->llvm_only)
9788                                         emit_pop_lmf (cfg);
9789
9790                                 if (cfg->ret) {
9791                                         MonoType *ret_type = mini_get_underlying_type (mono_method_signature (method)->ret);
9792
9793                                         if (seq_points && !sym_seq_points) {
9794                                                 /* 
9795                                                  * Place a seq point here too even through the IL stack is not
9796                                                  * empty, so a step over on
9797                                                  * call <FOO>
9798                                                  * ret
9799                                                  * will work correctly.
9800                                                  */
9801                                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, TRUE);
9802                                                 MONO_ADD_INS (cfg->cbb, ins);
9803                                         }
9804
9805                                         g_assert (!return_var);
9806                                         CHECK_STACK (1);
9807                                         --sp;
9808
9809                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
9810                                                 UNVERIFIED;
9811
9812                                         emit_setret (cfg, *sp);
9813                                 }
9814                         }
9815                         if (sp != stack_start)
9816                                 UNVERIFIED;
9817                         MONO_INST_NEW (cfg, ins, OP_BR);
9818                         ip++;
9819                         ins->inst_target_bb = end_bblock;
9820                         MONO_ADD_INS (cfg->cbb, ins);
9821                         link_bblock (cfg, cfg->cbb, end_bblock);
9822                         start_new_bblock = 1;
9823                         break;
9824                 case CEE_BR_S:
9825                         CHECK_OPSIZE (2);
9826                         MONO_INST_NEW (cfg, ins, OP_BR);
9827                         ip++;
9828                         target = ip + 1 + (signed char)(*ip);
9829                         ++ip;
9830                         GET_BBLOCK (cfg, tblock, target);
9831                         link_bblock (cfg, cfg->cbb, tblock);
9832                         ins->inst_target_bb = tblock;
9833                         if (sp != stack_start) {
9834                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9835                                 sp = stack_start;
9836                                 CHECK_UNVERIFIABLE (cfg);
9837                         }
9838                         MONO_ADD_INS (cfg->cbb, ins);
9839                         start_new_bblock = 1;
9840                         inline_costs += BRANCH_COST;
9841                         break;
9842                 case CEE_BEQ_S:
9843                 case CEE_BGE_S:
9844                 case CEE_BGT_S:
9845                 case CEE_BLE_S:
9846                 case CEE_BLT_S:
9847                 case CEE_BNE_UN_S:
9848                 case CEE_BGE_UN_S:
9849                 case CEE_BGT_UN_S:
9850                 case CEE_BLE_UN_S:
9851                 case CEE_BLT_UN_S:
9852                         CHECK_OPSIZE (2);
9853                         CHECK_STACK (2);
9854                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
9855                         ip++;
9856                         target = ip + 1 + *(signed char*)ip;
9857                         ip++;
9858
9859                         ADD_BINCOND (NULL);
9860
9861                         sp = stack_start;
9862                         inline_costs += BRANCH_COST;
9863                         break;
9864                 case CEE_BR:
9865                         CHECK_OPSIZE (5);
9866                         MONO_INST_NEW (cfg, ins, OP_BR);
9867                         ip++;
9868
9869                         target = ip + 4 + (gint32)read32(ip);
9870                         ip += 4;
9871                         GET_BBLOCK (cfg, tblock, target);
9872                         link_bblock (cfg, cfg->cbb, tblock);
9873                         ins->inst_target_bb = tblock;
9874                         if (sp != stack_start) {
9875                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9876                                 sp = stack_start;
9877                                 CHECK_UNVERIFIABLE (cfg);
9878                         }
9879
9880                         MONO_ADD_INS (cfg->cbb, ins);
9881
9882                         start_new_bblock = 1;
9883                         inline_costs += BRANCH_COST;
9884                         break;
9885                 case CEE_BRFALSE_S:
9886                 case CEE_BRTRUE_S:
9887                 case CEE_BRFALSE:
9888                 case CEE_BRTRUE: {
9889                         MonoInst *cmp;
9890                         gboolean is_short = ((*ip) == CEE_BRFALSE_S) || ((*ip) == CEE_BRTRUE_S);
9891                         gboolean is_true = ((*ip) == CEE_BRTRUE_S) || ((*ip) == CEE_BRTRUE);
9892                         guint32 opsize = is_short ? 1 : 4;
9893
9894                         CHECK_OPSIZE (opsize);
9895                         CHECK_STACK (1);
9896                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
9897                                 UNVERIFIED;
9898                         ip ++;
9899                         target = ip + opsize + (is_short ? *(signed char*)ip : (gint32)read32(ip));
9900                         ip += opsize;
9901
9902                         sp--;
9903
9904                         GET_BBLOCK (cfg, tblock, target);
9905                         link_bblock (cfg, cfg->cbb, tblock);
9906                         GET_BBLOCK (cfg, tblock, ip);
9907                         link_bblock (cfg, cfg->cbb, tblock);
9908
9909                         if (sp != stack_start) {
9910                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9911                                 CHECK_UNVERIFIABLE (cfg);
9912                         }
9913
9914                         MONO_INST_NEW(cfg, cmp, OP_ICOMPARE_IMM);
9915                         cmp->sreg1 = sp [0]->dreg;
9916                         type_from_op (cfg, cmp, sp [0], NULL);
9917                         CHECK_TYPE (cmp);
9918
9919 #if SIZEOF_REGISTER == 4
9920                         if (cmp->opcode == OP_LCOMPARE_IMM) {
9921                                 /* Convert it to OP_LCOMPARE */
9922                                 MONO_INST_NEW (cfg, ins, OP_I8CONST);
9923                                 ins->type = STACK_I8;
9924                                 ins->dreg = alloc_dreg (cfg, STACK_I8);
9925                                 ins->inst_l = 0;
9926                                 MONO_ADD_INS (cfg->cbb, ins);
9927                                 cmp->opcode = OP_LCOMPARE;
9928                                 cmp->sreg2 = ins->dreg;
9929                         }
9930 #endif
9931                         MONO_ADD_INS (cfg->cbb, cmp);
9932
9933                         MONO_INST_NEW (cfg, ins, is_true ? CEE_BNE_UN : CEE_BEQ);
9934                         type_from_op (cfg, ins, sp [0], NULL);
9935                         MONO_ADD_INS (cfg->cbb, ins);
9936                         ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);
9937                         GET_BBLOCK (cfg, tblock, target);
9938                         ins->inst_true_bb = tblock;
9939                         GET_BBLOCK (cfg, tblock, ip);
9940                         ins->inst_false_bb = tblock;
9941                         start_new_bblock = 2;
9942
9943                         sp = stack_start;
9944                         inline_costs += BRANCH_COST;
9945                         break;
9946                 }
9947                 case CEE_BEQ:
9948                 case CEE_BGE:
9949                 case CEE_BGT:
9950                 case CEE_BLE:
9951                 case CEE_BLT:
9952                 case CEE_BNE_UN:
9953                 case CEE_BGE_UN:
9954                 case CEE_BGT_UN:
9955                 case CEE_BLE_UN:
9956                 case CEE_BLT_UN:
9957                         CHECK_OPSIZE (5);
9958                         CHECK_STACK (2);
9959                         MONO_INST_NEW (cfg, ins, *ip);
9960                         ip++;
9961                         target = ip + 4 + (gint32)read32(ip);
9962                         ip += 4;
9963
9964                         ADD_BINCOND (NULL);
9965
9966                         sp = stack_start;
9967                         inline_costs += BRANCH_COST;
9968                         break;
9969                 case CEE_SWITCH: {
9970                         MonoInst *src1;
9971                         MonoBasicBlock **targets;
9972                         MonoBasicBlock *default_bblock;
9973                         MonoJumpInfoBBTable *table;
9974                         int offset_reg = alloc_preg (cfg);
9975                         int target_reg = alloc_preg (cfg);
9976                         int table_reg = alloc_preg (cfg);
9977                         int sum_reg = alloc_preg (cfg);
9978                         gboolean use_op_switch;
9979
9980                         CHECK_OPSIZE (5);
9981                         CHECK_STACK (1);
9982                         n = read32 (ip + 1);
9983                         --sp;
9984                         src1 = sp [0];
9985                         if ((src1->type != STACK_I4) && (src1->type != STACK_PTR)) 
9986                                 UNVERIFIED;
9987
9988                         ip += 5;
9989                         CHECK_OPSIZE (n * sizeof (guint32));
9990                         target = ip + n * sizeof (guint32);
9991
9992                         GET_BBLOCK (cfg, default_bblock, target);
9993                         default_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
9994
9995                         targets = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * n);
9996                         for (i = 0; i < n; ++i) {
9997                                 GET_BBLOCK (cfg, tblock, target + (gint32)read32(ip));
9998                                 targets [i] = tblock;
9999                                 targets [i]->flags |= BB_INDIRECT_JUMP_TARGET;
10000                                 ip += 4;
10001                         }
10002
10003                         if (sp != stack_start) {
10004                                 /* 
10005                                  * Link the current bb with the targets as well, so handle_stack_args
10006                                  * will set their in_stack correctly.
10007                                  */
10008                                 link_bblock (cfg, cfg->cbb, default_bblock);
10009                                 for (i = 0; i < n; ++i)
10010                                         link_bblock (cfg, cfg->cbb, targets [i]);
10011
10012                                 handle_stack_args (cfg, stack_start, sp - stack_start);
10013                                 sp = stack_start;
10014                                 CHECK_UNVERIFIABLE (cfg);
10015
10016                                 /* Undo the links */
10017                                 mono_unlink_bblock (cfg, cfg->cbb, default_bblock);
10018                                 for (i = 0; i < n; ++i)
10019                                         mono_unlink_bblock (cfg, cfg->cbb, targets [i]);
10020                         }
10021
10022                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, src1->dreg, n);
10023                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBGE_UN, default_bblock);
10024
10025                         for (i = 0; i < n; ++i)
10026                                 link_bblock (cfg, cfg->cbb, targets [i]);
10027
10028                         table = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
10029                         table->table = targets;
10030                         table->table_size = n;
10031
10032                         use_op_switch = FALSE;
10033 #ifdef TARGET_ARM
10034                         /* ARM implements SWITCH statements differently */
10035                         /* FIXME: Make it use the generic implementation */
10036                         if (!cfg->compile_aot)
10037                                 use_op_switch = TRUE;
10038 #endif
10039
10040                         if (COMPILE_LLVM (cfg))
10041                                 use_op_switch = TRUE;
10042
10043                         cfg->cbb->has_jump_table = 1;
10044
10045                         if (use_op_switch) {
10046                                 MONO_INST_NEW (cfg, ins, OP_SWITCH);
10047                                 ins->sreg1 = src1->dreg;
10048                                 ins->inst_p0 = table;
10049                                 ins->inst_many_bb = targets;
10050                                 ins->klass = GUINT_TO_POINTER (n);
10051                                 MONO_ADD_INS (cfg->cbb, ins);
10052                         } else {
10053                                 if (sizeof (gpointer) == 8)
10054                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 3);
10055                                 else
10056                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 2);
10057
10058 #if SIZEOF_REGISTER == 8
10059                                 /* The upper word might not be zero, and we add it to a 64 bit address later */
10060                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, offset_reg, offset_reg);
10061 #endif
10062
10063                                 if (cfg->compile_aot) {
10064                                         MONO_EMIT_NEW_AOTCONST (cfg, table_reg, table, MONO_PATCH_INFO_SWITCH);
10065                                 } else {
10066                                         MONO_INST_NEW (cfg, ins, OP_JUMP_TABLE);
10067                                         ins->inst_c1 = MONO_PATCH_INFO_SWITCH;
10068                                         ins->inst_p0 = table;
10069                                         ins->dreg = table_reg;
10070                                         MONO_ADD_INS (cfg->cbb, ins);
10071                                 }
10072
10073                                 /* FIXME: Use load_memindex */
10074                                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, table_reg, offset_reg);
10075                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, target_reg, sum_reg, 0);
10076                                 MONO_EMIT_NEW_UNALU (cfg, OP_BR_REG, -1, target_reg);
10077                         }
10078                         start_new_bblock = 1;
10079                         inline_costs += (BRANCH_COST * 2);
10080                         break;
10081                 }
10082                 case CEE_LDIND_I1:
10083                 case CEE_LDIND_U1:
10084                 case CEE_LDIND_I2:
10085                 case CEE_LDIND_U2:
10086                 case CEE_LDIND_I4:
10087                 case CEE_LDIND_U4:
10088                 case CEE_LDIND_I8:
10089                 case CEE_LDIND_I:
10090                 case CEE_LDIND_R4:
10091                 case CEE_LDIND_R8:
10092                 case CEE_LDIND_REF:
10093                         CHECK_STACK (1);
10094                         --sp;
10095
10096                         switch (*ip) {
10097                         case CEE_LDIND_R4:
10098                         case CEE_LDIND_R8:
10099                                 dreg = alloc_freg (cfg);
10100                                 break;
10101                         case CEE_LDIND_I8:
10102                                 dreg = alloc_lreg (cfg);
10103                                 break;
10104                         case CEE_LDIND_REF:
10105                                 dreg = alloc_ireg_ref (cfg);
10106                                 break;
10107                         default:
10108                                 dreg = alloc_preg (cfg);
10109                         }
10110
10111                         NEW_LOAD_MEMBASE (cfg, ins, ldind_to_load_membase (*ip), dreg, sp [0]->dreg, 0);
10112                         ins->type = ldind_type [*ip - CEE_LDIND_I1];
10113                         if (*ip == CEE_LDIND_R4)
10114                                 ins->type = cfg->r4_stack_type;
10115                         ins->flags |= ins_flag;
10116                         MONO_ADD_INS (cfg->cbb, ins);
10117                         *sp++ = ins;
10118                         if (ins_flag & MONO_INST_VOLATILE) {
10119                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10120                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10121                         }
10122                         ins_flag = 0;
10123                         ++ip;
10124                         break;
10125                 case CEE_STIND_REF:
10126                 case CEE_STIND_I1:
10127                 case CEE_STIND_I2:
10128                 case CEE_STIND_I4:
10129                 case CEE_STIND_I8:
10130                 case CEE_STIND_R4:
10131                 case CEE_STIND_R8:
10132                 case CEE_STIND_I:
10133                         CHECK_STACK (2);
10134                         sp -= 2;
10135
10136                         if (ins_flag & MONO_INST_VOLATILE) {
10137                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
10138                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
10139                         }
10140
10141                         NEW_STORE_MEMBASE (cfg, ins, stind_to_store_membase (*ip), sp [0]->dreg, 0, sp [1]->dreg);
10142                         ins->flags |= ins_flag;
10143                         ins_flag = 0;
10144
10145                         MONO_ADD_INS (cfg->cbb, ins);
10146
10147                         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)))
10148                                 emit_write_barrier (cfg, sp [0], sp [1]);
10149
10150                         inline_costs += 1;
10151                         ++ip;
10152                         break;
10153
10154                 case CEE_MUL:
10155                         CHECK_STACK (2);
10156
10157                         MONO_INST_NEW (cfg, ins, (*ip));
10158                         sp -= 2;
10159                         ins->sreg1 = sp [0]->dreg;
10160                         ins->sreg2 = sp [1]->dreg;
10161                         type_from_op (cfg, ins, sp [0], sp [1]);
10162                         CHECK_TYPE (ins);
10163                         ins->dreg = alloc_dreg ((cfg), (ins)->type);
10164
10165                         /* Use the immediate opcodes if possible */
10166                         if ((sp [1]->opcode == OP_ICONST) && mono_arch_is_inst_imm (sp [1]->inst_c0)) {
10167                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
10168                                 if (imm_opcode != -1) {
10169                                         ins->opcode = imm_opcode;
10170                                         ins->inst_p1 = (gpointer)(gssize)(sp [1]->inst_c0);
10171                                         ins->sreg2 = -1;
10172
10173                                         NULLIFY_INS (sp [1]);
10174                                 }
10175                         }
10176
10177                         MONO_ADD_INS ((cfg)->cbb, (ins));
10178
10179                         *sp++ = mono_decompose_opcode (cfg, ins);
10180                         ip++;
10181                         break;
10182                 case CEE_ADD:
10183                 case CEE_SUB:
10184                 case CEE_DIV:
10185                 case CEE_DIV_UN:
10186                 case CEE_REM:
10187                 case CEE_REM_UN:
10188                 case CEE_AND:
10189                 case CEE_OR:
10190                 case CEE_XOR:
10191                 case CEE_SHL:
10192                 case CEE_SHR:
10193                 case CEE_SHR_UN:
10194                         CHECK_STACK (2);
10195
10196                         MONO_INST_NEW (cfg, ins, (*ip));
10197                         sp -= 2;
10198                         ins->sreg1 = sp [0]->dreg;
10199                         ins->sreg2 = sp [1]->dreg;
10200                         type_from_op (cfg, ins, sp [0], sp [1]);
10201                         CHECK_TYPE (ins);
10202                         add_widen_op (cfg, ins, &sp [0], &sp [1]);
10203                         ins->dreg = alloc_dreg ((cfg), (ins)->type);
10204
10205                         /* FIXME: Pass opcode to is_inst_imm */
10206
10207                         /* Use the immediate opcodes if possible */
10208                         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)) {
10209                                 int imm_opcode;
10210
10211                                 imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
10212 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
10213                                 /* Keep emulated opcodes which are optimized away later */
10214                                 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) {
10215                                         imm_opcode = mono_op_to_op_imm (ins->opcode);
10216                                 }
10217 #endif
10218                                 if (imm_opcode != -1) {
10219                                         ins->opcode = imm_opcode;
10220                                         if (sp [1]->opcode == OP_I8CONST) {
10221 #if SIZEOF_REGISTER == 8
10222                                                 ins->inst_imm = sp [1]->inst_l;
10223 #else
10224                                                 ins->inst_ls_word = sp [1]->inst_ls_word;
10225                                                 ins->inst_ms_word = sp [1]->inst_ms_word;
10226 #endif
10227                                         }
10228                                         else
10229                                                 ins->inst_imm = (gssize)(sp [1]->inst_c0);
10230                                         ins->sreg2 = -1;
10231
10232                                         /* Might be followed by an instruction added by add_widen_op */
10233                                         if (sp [1]->next == NULL)
10234                                                 NULLIFY_INS (sp [1]);
10235                                 }
10236                         }
10237                         MONO_ADD_INS ((cfg)->cbb, (ins));
10238
10239                         *sp++ = mono_decompose_opcode (cfg, ins);
10240                         ip++;
10241                         break;
10242                 case CEE_NEG:
10243                 case CEE_NOT:
10244                 case CEE_CONV_I1:
10245                 case CEE_CONV_I2:
10246                 case CEE_CONV_I4:
10247                 case CEE_CONV_R4:
10248                 case CEE_CONV_R8:
10249                 case CEE_CONV_U4:
10250                 case CEE_CONV_I8:
10251                 case CEE_CONV_U8:
10252                 case CEE_CONV_OVF_I8:
10253                 case CEE_CONV_OVF_U8:
10254                 case CEE_CONV_R_UN:
10255                         CHECK_STACK (1);
10256
10257                         /* Special case this earlier so we have long constants in the IR */
10258                         if ((((*ip) == CEE_CONV_I8) || ((*ip) == CEE_CONV_U8)) && (sp [-1]->opcode == OP_ICONST)) {
10259                                 int data = sp [-1]->inst_c0;
10260                                 sp [-1]->opcode = OP_I8CONST;
10261                                 sp [-1]->type = STACK_I8;
10262 #if SIZEOF_REGISTER == 8
10263                                 if ((*ip) == CEE_CONV_U8)
10264                                         sp [-1]->inst_c0 = (guint32)data;
10265                                 else
10266                                         sp [-1]->inst_c0 = data;
10267 #else
10268                                 sp [-1]->inst_ls_word = data;
10269                                 if ((*ip) == CEE_CONV_U8)
10270                                         sp [-1]->inst_ms_word = 0;
10271                                 else
10272                                         sp [-1]->inst_ms_word = (data < 0) ? -1 : 0;
10273 #endif
10274                                 sp [-1]->dreg = alloc_dreg (cfg, STACK_I8);
10275                         }
10276                         else {
10277                                 ADD_UNOP (*ip);
10278                         }
10279                         ip++;
10280                         break;
10281                 case CEE_CONV_OVF_I4:
10282                 case CEE_CONV_OVF_I1:
10283                 case CEE_CONV_OVF_I2:
10284                 case CEE_CONV_OVF_I:
10285                 case CEE_CONV_OVF_U:
10286                         CHECK_STACK (1);
10287
10288                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
10289                                 ADD_UNOP (CEE_CONV_OVF_I8);
10290                                 ADD_UNOP (*ip);
10291                         } else {
10292                                 ADD_UNOP (*ip);
10293                         }
10294                         ip++;
10295                         break;
10296                 case CEE_CONV_OVF_U1:
10297                 case CEE_CONV_OVF_U2:
10298                 case CEE_CONV_OVF_U4:
10299                         CHECK_STACK (1);
10300
10301                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
10302                                 ADD_UNOP (CEE_CONV_OVF_U8);
10303                                 ADD_UNOP (*ip);
10304                         } else {
10305                                 ADD_UNOP (*ip);
10306                         }
10307                         ip++;
10308                         break;
10309                 case CEE_CONV_OVF_I1_UN:
10310                 case CEE_CONV_OVF_I2_UN:
10311                 case CEE_CONV_OVF_I4_UN:
10312                 case CEE_CONV_OVF_I8_UN:
10313                 case CEE_CONV_OVF_U1_UN:
10314                 case CEE_CONV_OVF_U2_UN:
10315                 case CEE_CONV_OVF_U4_UN:
10316                 case CEE_CONV_OVF_U8_UN:
10317                 case CEE_CONV_OVF_I_UN:
10318                 case CEE_CONV_OVF_U_UN:
10319                 case CEE_CONV_U2:
10320                 case CEE_CONV_U1:
10321                 case CEE_CONV_I:
10322                 case CEE_CONV_U:
10323                         CHECK_STACK (1);
10324                         ADD_UNOP (*ip);
10325                         CHECK_CFG_EXCEPTION;
10326                         ip++;
10327                         break;
10328                 case CEE_ADD_OVF:
10329                 case CEE_ADD_OVF_UN:
10330                 case CEE_MUL_OVF:
10331                 case CEE_MUL_OVF_UN:
10332                 case CEE_SUB_OVF:
10333                 case CEE_SUB_OVF_UN:
10334                         CHECK_STACK (2);
10335                         ADD_BINOP (*ip);
10336                         ip++;
10337                         break;
10338                 case CEE_CPOBJ:
10339                         GSHAREDVT_FAILURE (*ip);
10340                         CHECK_OPSIZE (5);
10341                         CHECK_STACK (2);
10342                         token = read32 (ip + 1);
10343                         klass = mini_get_class (method, token, generic_context);
10344                         CHECK_TYPELOAD (klass);
10345                         sp -= 2;
10346                         if (generic_class_is_reference_type (cfg, klass)) {
10347                                 MonoInst *store, *load;
10348                                 int dreg = alloc_ireg_ref (cfg);
10349
10350                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, dreg, sp [1]->dreg, 0);
10351                                 load->flags |= ins_flag;
10352                                 MONO_ADD_INS (cfg->cbb, load);
10353
10354                                 NEW_STORE_MEMBASE (cfg, store, OP_STORE_MEMBASE_REG, sp [0]->dreg, 0, dreg);
10355                                 store->flags |= ins_flag;
10356                                 MONO_ADD_INS (cfg->cbb, store);
10357
10358                                 if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER)
10359                                         emit_write_barrier (cfg, sp [0], sp [1]);
10360                         } else {
10361                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
10362                         }
10363                         ins_flag = 0;
10364                         ip += 5;
10365                         break;
10366                 case CEE_LDOBJ: {
10367                         int loc_index = -1;
10368                         int stloc_len = 0;
10369
10370                         CHECK_OPSIZE (5);
10371                         CHECK_STACK (1);
10372                         --sp;
10373                         token = read32 (ip + 1);
10374                         klass = mini_get_class (method, token, generic_context);
10375                         CHECK_TYPELOAD (klass);
10376
10377                         /* Optimize the common ldobj+stloc combination */
10378                         switch (ip [5]) {
10379                         case CEE_STLOC_S:
10380                                 loc_index = ip [6];
10381                                 stloc_len = 2;
10382                                 break;
10383                         case CEE_STLOC_0:
10384                         case CEE_STLOC_1:
10385                         case CEE_STLOC_2:
10386                         case CEE_STLOC_3:
10387                                 loc_index = ip [5] - CEE_STLOC_0;
10388                                 stloc_len = 1;
10389                                 break;
10390                         default:
10391                                 break;
10392                         }
10393
10394                         if ((loc_index != -1) && ip_in_bb (cfg, cfg->cbb, ip + 5)) {
10395                                 CHECK_LOCAL (loc_index);
10396
10397                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10398                                 ins->dreg = cfg->locals [loc_index]->dreg;
10399                                 ins->flags |= ins_flag;
10400                                 ip += 5;
10401                                 ip += stloc_len;
10402                                 if (ins_flag & MONO_INST_VOLATILE) {
10403                                         /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10404                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10405                                 }
10406                                 ins_flag = 0;
10407                                 break;
10408                         }
10409
10410                         /* Optimize the ldobj+stobj combination */
10411                         /* The reference case ends up being a load+store anyway */
10412                         /* Skip this if the operation is volatile. */
10413                         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)) {
10414                                 CHECK_STACK (1);
10415
10416                                 sp --;
10417
10418                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
10419
10420                                 ip += 5 + 5;
10421                                 ins_flag = 0;
10422                                 break;
10423                         }
10424
10425                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10426                         ins->flags |= ins_flag;
10427                         *sp++ = ins;
10428
10429                         if (ins_flag & MONO_INST_VOLATILE) {
10430                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10431                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10432                         }
10433
10434                         ip += 5;
10435                         ins_flag = 0;
10436                         inline_costs += 1;
10437                         break;
10438                 }
10439                 case CEE_LDSTR:
10440                         CHECK_STACK_OVF (1);
10441                         CHECK_OPSIZE (5);
10442                         n = read32 (ip + 1);
10443
10444                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
10445                                 EMIT_NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
10446                                 ins->type = STACK_OBJ;
10447                                 *sp = ins;
10448                         }
10449                         else if (method->wrapper_type != MONO_WRAPPER_NONE) {
10450                                 MonoInst *iargs [1];
10451                                 char *str = mono_method_get_wrapper_data (method, n);
10452
10453                                 if (cfg->compile_aot)
10454                                         EMIT_NEW_LDSTRLITCONST (cfg, iargs [0], str);
10455                                 else
10456                                         EMIT_NEW_PCONST (cfg, iargs [0], str);
10457                                 *sp = mono_emit_jit_icall (cfg, mono_string_new_wrapper, iargs);
10458                         } else {
10459                                 if (cfg->opt & MONO_OPT_SHARED) {
10460                                         MonoInst *iargs [3];
10461
10462                                         if (cfg->compile_aot) {
10463                                                 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
10464                                         }
10465                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10466                                         EMIT_NEW_IMAGECONST (cfg, iargs [1], image);
10467                                         EMIT_NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
10468                                         *sp = mono_emit_jit_icall (cfg, mono_ldstr, iargs);
10469                                         mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
10470                                 } else {
10471                                         if (cfg->cbb->out_of_line) {
10472                                                 MonoInst *iargs [2];
10473
10474                                                 if (image == mono_defaults.corlib) {
10475                                                         /* 
10476                                                          * Avoid relocations in AOT and save some space by using a 
10477                                                          * version of helper_ldstr specialized to mscorlib.
10478                                                          */
10479                                                         EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (n));
10480                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr_mscorlib, iargs);
10481                                                 } else {
10482                                                         /* Avoid creating the string object */
10483                                                         EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
10484                                                         EMIT_NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n));
10485                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr, iargs);
10486                                                 }
10487                                         } 
10488                                         else
10489                                         if (cfg->compile_aot) {
10490                                                 NEW_LDSTRCONST (cfg, ins, image, n);
10491                                                 *sp = ins;
10492                                                 MONO_ADD_INS (cfg->cbb, ins);
10493                                         } 
10494                                         else {
10495                                                 NEW_PCONST (cfg, ins, NULL);
10496                                                 ins->type = STACK_OBJ;
10497                                                 ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
10498                                                 if (!ins->inst_p0)
10499                                                         OUT_OF_MEMORY_FAILURE;
10500
10501                                                 *sp = ins;
10502                                                 MONO_ADD_INS (cfg->cbb, ins);
10503                                         }
10504                                 }
10505                         }
10506
10507                         sp++;
10508                         ip += 5;
10509                         break;
10510                 case CEE_NEWOBJ: {
10511                         MonoInst *iargs [2];
10512                         MonoMethodSignature *fsig;
10513                         MonoInst this_ins;
10514                         MonoInst *alloc;
10515                         MonoInst *vtable_arg = NULL;
10516
10517                         CHECK_OPSIZE (5);
10518                         token = read32 (ip + 1);
10519                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
10520                         if (!cmethod || mono_loader_get_last_error ())
10521                                 LOAD_ERROR;
10522                         fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
10523                         CHECK_CFG_ERROR;
10524
10525                         mono_save_token_info (cfg, image, token, cmethod);
10526
10527                         if (!mono_class_init (cmethod->klass))
10528                                 TYPE_LOAD_ERROR (cmethod->klass);
10529
10530                         context_used = mini_method_check_context_used (cfg, cmethod);
10531
10532                         if (mono_security_core_clr_enabled ())
10533                                 ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
10534
10535                         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)) {
10536                                 emit_class_init (cfg, cmethod->klass);
10537                                 CHECK_TYPELOAD (cmethod->klass);
10538                         }
10539
10540                         /*
10541                         if (cfg->gsharedvt) {
10542                                 if (mini_is_gsharedvt_variable_signature (sig))
10543                                         GSHAREDVT_FAILURE (*ip);
10544                         }
10545                         */
10546
10547                         n = fsig->param_count;
10548                         CHECK_STACK (n);
10549
10550                         /* 
10551                          * Generate smaller code for the common newobj <exception> instruction in
10552                          * argument checking code.
10553                          */
10554                         if (cfg->cbb->out_of_line && cmethod->klass->image == mono_defaults.corlib &&
10555                                 is_exception_class (cmethod->klass) && n <= 2 &&
10556                                 ((n < 1) || (!fsig->params [0]->byref && fsig->params [0]->type == MONO_TYPE_STRING)) && 
10557                                 ((n < 2) || (!fsig->params [1]->byref && fsig->params [1]->type == MONO_TYPE_STRING))) {
10558                                 MonoInst *iargs [3];
10559
10560                                 sp -= n;
10561
10562                                 EMIT_NEW_ICONST (cfg, iargs [0], cmethod->klass->type_token);
10563                                 switch (n) {
10564                                 case 0:
10565                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_0, iargs);
10566                                         break;
10567                                 case 1:
10568                                         iargs [1] = sp [0];
10569                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_1, iargs);
10570                                         break;
10571                                 case 2:
10572                                         iargs [1] = sp [0];
10573                                         iargs [2] = sp [1];
10574                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_2, iargs);
10575                                         break;
10576                                 default:
10577                                         g_assert_not_reached ();
10578                                 }
10579
10580                                 ip += 5;
10581                                 inline_costs += 5;
10582                                 break;
10583                         }
10584
10585                         /* move the args to allow room for 'this' in the first position */
10586                         while (n--) {
10587                                 --sp;
10588                                 sp [1] = sp [0];
10589                         }
10590
10591                         /* check_call_signature () requires sp[0] to be set */
10592                         this_ins.type = STACK_OBJ;
10593                         sp [0] = &this_ins;
10594                         if (check_call_signature (cfg, fsig, sp))
10595                                 UNVERIFIED;
10596
10597                         iargs [0] = NULL;
10598
10599                         if (mini_class_is_system_array (cmethod->klass)) {
10600                                 *sp = emit_get_rgctx_method (cfg, context_used,
10601                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
10602
10603                                 /* Avoid varargs in the common case */
10604                                 if (fsig->param_count == 1)
10605                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_1, sp);
10606                                 else if (fsig->param_count == 2)
10607                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_2, sp);
10608                                 else if (fsig->param_count == 3)
10609                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_3, sp);
10610                                 else if (fsig->param_count == 4)
10611                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_4, sp);
10612                                 else
10613                                         alloc = handle_array_new (cfg, fsig->param_count, sp, ip);
10614                         } else if (cmethod->string_ctor) {
10615                                 g_assert (!context_used);
10616                                 g_assert (!vtable_arg);
10617                                 /* we simply pass a null pointer */
10618                                 EMIT_NEW_PCONST (cfg, *sp, NULL); 
10619                                 /* now call the string ctor */
10620                                 alloc = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, NULL, NULL, NULL);
10621                         } else {
10622                                 if (cmethod->klass->valuetype) {
10623                                         iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
10624                                         emit_init_rvar (cfg, iargs [0]->dreg, &cmethod->klass->byval_arg);
10625                                         EMIT_NEW_TEMPLOADA (cfg, *sp, iargs [0]->inst_c0);
10626
10627                                         alloc = NULL;
10628
10629                                         /* 
10630                                          * The code generated by mini_emit_virtual_call () expects
10631                                          * iargs [0] to be a boxed instance, but luckily the vcall
10632                                          * will be transformed into a normal call there.
10633                                          */
10634                                 } else if (context_used) {
10635                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, context_used);
10636                                         *sp = alloc;
10637                                 } else {
10638                                         MonoVTable *vtable = NULL;
10639
10640                                         if (!cfg->compile_aot)
10641                                                 vtable = mono_class_vtable (cfg->domain, cmethod->klass);
10642                                         CHECK_TYPELOAD (cmethod->klass);
10643
10644                                         /*
10645                                          * TypeInitializationExceptions thrown from the mono_runtime_class_init
10646                                          * call in mono_jit_runtime_invoke () can abort the finalizer thread.
10647                                          * As a workaround, we call class cctors before allocating objects.
10648                                          */
10649                                         if (mini_field_access_needs_cctor_run (cfg, method, cmethod->klass, vtable) && !(g_slist_find (class_inits, cmethod->klass))) {
10650                                                 emit_class_init (cfg, cmethod->klass);
10651                                                 if (cfg->verbose_level > 2)
10652                                                         printf ("class %s.%s needs init call for ctor\n", cmethod->klass->name_space, cmethod->klass->name);
10653                                                 class_inits = g_slist_prepend (class_inits, cmethod->klass);
10654                                         }
10655
10656                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, 0);
10657                                         *sp = alloc;
10658                                 }
10659                                 CHECK_CFG_EXCEPTION; /*for handle_alloc*/
10660
10661                                 if (alloc)
10662                                         MONO_EMIT_NEW_UNALU (cfg, OP_NOT_NULL, -1, alloc->dreg);
10663
10664                                 /* Now call the actual ctor */
10665                                 handle_ctor_call (cfg, cmethod, fsig, context_used, sp, ip, &inline_costs);
10666                                 CHECK_CFG_EXCEPTION;
10667                         }
10668
10669                         if (alloc == NULL) {
10670                                 /* Valuetype */
10671                                 EMIT_NEW_TEMPLOAD (cfg, ins, iargs [0]->inst_c0);
10672                                 type_to_eval_stack_type (cfg, &ins->klass->byval_arg, ins);
10673                                 *sp++= ins;
10674                         } else {
10675                                 *sp++ = alloc;
10676                         }
10677                         
10678                         ip += 5;
10679                         inline_costs += 5;
10680                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip - header->code)))
10681                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
10682                         break;
10683                 }
10684                 case CEE_CASTCLASS:
10685                         CHECK_STACK (1);
10686                         --sp;
10687                         CHECK_OPSIZE (5);
10688                         token = read32 (ip + 1);
10689                         klass = mini_get_class (method, token, generic_context);
10690                         CHECK_TYPELOAD (klass);
10691                         if (sp [0]->type != STACK_OBJ)
10692                                 UNVERIFIED;
10693
10694                         ins = handle_castclass (cfg, klass, *sp, ip, &inline_costs);
10695                         CHECK_CFG_EXCEPTION;
10696
10697                         *sp ++ = ins;
10698                         ip += 5;
10699                         break;
10700                 case CEE_ISINST: {
10701                         CHECK_STACK (1);
10702                         --sp;
10703                         CHECK_OPSIZE (5);
10704                         token = read32 (ip + 1);
10705                         klass = mini_get_class (method, token, generic_context);
10706                         CHECK_TYPELOAD (klass);
10707                         if (sp [0]->type != STACK_OBJ)
10708                                 UNVERIFIED;
10709  
10710                         context_used = mini_class_check_context_used (cfg, klass);
10711
10712                         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
10713                                 MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
10714                                 MonoInst *args [3];
10715                                 int idx;
10716
10717                                 /* obj */
10718                                 args [0] = *sp;
10719
10720                                 /* klass */
10721                                 EMIT_NEW_CLASSCONST (cfg, args [1], klass);
10722
10723                                 /* inline cache*/
10724                                 if (cfg->compile_aot) {
10725                                         idx = get_castclass_cache_idx (cfg);
10726                                         EMIT_NEW_AOTCONST (cfg, args [2], MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
10727                                 } else {
10728                                         EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));
10729                                 }
10730
10731                                 *sp++ = mono_emit_method_call (cfg, mono_isinst, args, NULL);
10732                                 ip += 5;
10733                                 inline_costs += 2;
10734                         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
10735                                 MonoMethod *mono_isinst;
10736                                 MonoInst *iargs [1];
10737                                 int costs;
10738
10739                                 mono_isinst = mono_marshal_get_isinst (klass); 
10740                                 iargs [0] = sp [0];
10741
10742                                 costs = inline_method (cfg, mono_isinst, mono_method_signature (mono_isinst), 
10743                                                                            iargs, ip, cfg->real_offset, TRUE);
10744                                 CHECK_CFG_EXCEPTION;
10745                                 g_assert (costs > 0);
10746                                 
10747                                 ip += 5;
10748                                 cfg->real_offset += 5;
10749
10750                                 *sp++= iargs [0];
10751
10752                                 inline_costs += costs;
10753                         }
10754                         else {
10755                                 ins = handle_isinst (cfg, klass, *sp, context_used);
10756                                 CHECK_CFG_EXCEPTION;
10757                                 *sp ++ = ins;
10758                                 ip += 5;
10759                         }
10760                         break;
10761                 }
10762                 case CEE_UNBOX_ANY: {
10763                         MonoInst *res, *addr;
10764
10765                         CHECK_STACK (1);
10766                         --sp;
10767                         CHECK_OPSIZE (5);
10768                         token = read32 (ip + 1);
10769                         klass = mini_get_class (method, token, generic_context);
10770                         CHECK_TYPELOAD (klass);
10771
10772                         mono_save_token_info (cfg, image, token, klass);
10773
10774                         context_used = mini_class_check_context_used (cfg, klass);
10775
10776                         if (mini_is_gsharedvt_klass (klass)) {
10777                                 res = handle_unbox_gsharedvt (cfg, klass, *sp);
10778                                 inline_costs += 2;
10779                         } else if (generic_class_is_reference_type (cfg, klass)) {
10780                                 res = handle_castclass (cfg, klass, *sp, ip, &inline_costs);
10781                                 CHECK_CFG_EXCEPTION;
10782                         } else if (mono_class_is_nullable (klass)) {
10783                                 res = handle_unbox_nullable (cfg, *sp, klass, context_used);
10784                         } else {
10785                                 addr = handle_unbox (cfg, klass, sp, context_used);
10786                                 /* LDOBJ */
10787                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
10788                                 res = ins;
10789                                 inline_costs += 2;
10790                         }
10791
10792                         *sp ++ = res;
10793                         ip += 5;
10794                         break;
10795                 }
10796                 case CEE_BOX: {
10797                         MonoInst *val;
10798                         MonoClass *enum_class;
10799                         MonoMethod *has_flag;
10800
10801                         CHECK_STACK (1);
10802                         --sp;
10803                         val = *sp;
10804                         CHECK_OPSIZE (5);
10805                         token = read32 (ip + 1);
10806                         klass = mini_get_class (method, token, generic_context);
10807                         CHECK_TYPELOAD (klass);
10808
10809                         mono_save_token_info (cfg, image, token, klass);
10810
10811                         context_used = mini_class_check_context_used (cfg, klass);
10812
10813                         if (generic_class_is_reference_type (cfg, klass)) {
10814                                 *sp++ = val;
10815                                 ip += 5;
10816                                 break;
10817                         }
10818
10819                         if (klass == mono_defaults.void_class)
10820                                 UNVERIFIED;
10821                         if (target_type_is_incompatible (cfg, &klass->byval_arg, *sp))
10822                                 UNVERIFIED;
10823                         /* frequent check in generic code: box (struct), brtrue */
10824
10825                         /*
10826                          * Look for:
10827                          *
10828                          *   <push int/long ptr>
10829                          *   <push int/long>
10830                          *   box MyFlags
10831                          *   constrained. MyFlags
10832                          *   callvirt instace bool class [mscorlib] System.Enum::HasFlag (class [mscorlib] System.Enum)
10833                          *
10834                          * If we find this sequence and the operand types on box and constrained
10835                          * are equal, we can emit a specialized instruction sequence instead of
10836                          * the very slow HasFlag () call.
10837                          */
10838                         if ((cfg->opt & MONO_OPT_INTRINS) &&
10839                             /* Cheap checks first. */
10840                             ip + 5 + 6 + 5 < end &&
10841                             ip [5] == CEE_PREFIX1 &&
10842                             ip [6] == CEE_CONSTRAINED_ &&
10843                             ip [11] == CEE_CALLVIRT &&
10844                             ip_in_bb (cfg, cfg->cbb, ip + 5 + 6 + 5) &&
10845                             mono_class_is_enum (klass) &&
10846                             (enum_class = mini_get_class (method, read32 (ip + 7), generic_context)) &&
10847                             (has_flag = mini_get_method (cfg, method, read32 (ip + 12), NULL, generic_context)) &&
10848                             has_flag->klass == mono_defaults.enum_class &&
10849                             !strcmp (has_flag->name, "HasFlag") &&
10850                             has_flag->signature->hasthis &&
10851                             has_flag->signature->param_count == 1) {
10852                                 CHECK_TYPELOAD (enum_class);
10853
10854                                 if (enum_class == klass) {
10855                                         MonoInst *enum_this, *enum_flag;
10856
10857                                         ip += 5 + 6 + 5;
10858                                         --sp;
10859
10860                                         enum_this = sp [0];
10861                                         enum_flag = sp [1];
10862
10863                                         *sp++ = handle_enum_has_flag (cfg, klass, enum_this, enum_flag);
10864                                         break;
10865                                 }
10866                         }
10867
10868                         // FIXME: LLVM can't handle the inconsistent bb linking
10869                         if (!mono_class_is_nullable (klass) &&
10870                                 !mini_is_gsharedvt_klass (klass) &&
10871                                 ip + 5 < end && ip_in_bb (cfg, cfg->cbb, ip + 5) &&
10872                                 (ip [5] == CEE_BRTRUE || 
10873                                  ip [5] == CEE_BRTRUE_S ||
10874                                  ip [5] == CEE_BRFALSE ||
10875                                  ip [5] == CEE_BRFALSE_S)) {
10876                                 gboolean is_true = ip [5] == CEE_BRTRUE || ip [5] == CEE_BRTRUE_S;
10877                                 int dreg;
10878                                 MonoBasicBlock *true_bb, *false_bb;
10879
10880                                 ip += 5;
10881
10882                                 if (cfg->verbose_level > 3) {
10883                                         printf ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
10884                                         printf ("<box+brtrue opt>\n");
10885                                 }
10886
10887                                 switch (*ip) {
10888                                 case CEE_BRTRUE_S:
10889                                 case CEE_BRFALSE_S:
10890                                         CHECK_OPSIZE (2);
10891                                         ip++;
10892                                         target = ip + 1 + (signed char)(*ip);
10893                                         ip++;
10894                                         break;
10895                                 case CEE_BRTRUE:
10896                                 case CEE_BRFALSE:
10897                                         CHECK_OPSIZE (5);
10898                                         ip++;
10899                                         target = ip + 4 + (gint)(read32 (ip));
10900                                         ip += 4;
10901                                         break;
10902                                 default:
10903                                         g_assert_not_reached ();
10904                                 }
10905
10906                                 /* 
10907                                  * We need to link both bblocks, since it is needed for handling stack
10908                                  * arguments correctly (See test_0_box_brtrue_opt_regress_81102).
10909                                  * Branching to only one of them would lead to inconsistencies, so
10910                                  * generate an ICONST+BRTRUE, the branch opts will get rid of them.
10911                                  */
10912                                 GET_BBLOCK (cfg, true_bb, target);
10913                                 GET_BBLOCK (cfg, false_bb, ip);
10914
10915                                 mono_link_bblock (cfg, cfg->cbb, true_bb);
10916                                 mono_link_bblock (cfg, cfg->cbb, false_bb);
10917
10918                                 if (sp != stack_start) {
10919                                         handle_stack_args (cfg, stack_start, sp - stack_start);
10920                                         sp = stack_start;
10921                                         CHECK_UNVERIFIABLE (cfg);
10922                                 }
10923
10924                                 if (COMPILE_LLVM (cfg)) {
10925                                         dreg = alloc_ireg (cfg);
10926                                         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
10927                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, dreg, is_true ? 0 : 1);
10928
10929                                         MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, OP_IBEQ, true_bb, false_bb);
10930                                 } else {
10931                                         /* The JIT can't eliminate the iconst+compare */
10932                                         MONO_INST_NEW (cfg, ins, OP_BR);
10933                                         ins->inst_target_bb = is_true ? true_bb : false_bb;
10934                                         MONO_ADD_INS (cfg->cbb, ins);
10935                                 }
10936
10937                                 start_new_bblock = 1;
10938                                 break;
10939                         }
10940
10941                         *sp++ = handle_box (cfg, val, klass, context_used);
10942
10943                         CHECK_CFG_EXCEPTION;
10944                         ip += 5;
10945                         inline_costs += 1;
10946                         break;
10947                 }
10948                 case CEE_UNBOX: {
10949                         CHECK_STACK (1);
10950                         --sp;
10951                         CHECK_OPSIZE (5);
10952                         token = read32 (ip + 1);
10953                         klass = mini_get_class (method, token, generic_context);
10954                         CHECK_TYPELOAD (klass);
10955
10956                         mono_save_token_info (cfg, image, token, klass);
10957
10958                         context_used = mini_class_check_context_used (cfg, klass);
10959
10960                         if (mono_class_is_nullable (klass)) {
10961                                 MonoInst *val;
10962
10963                                 val = handle_unbox_nullable (cfg, *sp, klass, context_used);
10964                                 EMIT_NEW_VARLOADA (cfg, ins, get_vreg_to_inst (cfg, val->dreg), &val->klass->byval_arg);
10965
10966                                 *sp++= ins;
10967                         } else {
10968                                 ins = handle_unbox (cfg, klass, sp, context_used);
10969                                 *sp++ = ins;
10970                         }
10971                         ip += 5;
10972                         inline_costs += 2;
10973                         break;
10974                 }
10975                 case CEE_LDFLD:
10976                 case CEE_LDFLDA:
10977                 case CEE_STFLD:
10978                 case CEE_LDSFLD:
10979                 case CEE_LDSFLDA:
10980                 case CEE_STSFLD: {
10981                         MonoClassField *field;
10982 #ifndef DISABLE_REMOTING
10983                         int costs;
10984 #endif
10985                         guint foffset;
10986                         gboolean is_instance;
10987                         int op;
10988                         gpointer addr = NULL;
10989                         gboolean is_special_static;
10990                         MonoType *ftype;
10991                         MonoInst *store_val = NULL;
10992                         MonoInst *thread_ins;
10993
10994                         op = *ip;
10995                         is_instance = (op == CEE_LDFLD || op == CEE_LDFLDA || op == CEE_STFLD);
10996                         if (is_instance) {
10997                                 if (op == CEE_STFLD) {
10998                                         CHECK_STACK (2);
10999                                         sp -= 2;
11000                                         store_val = sp [1];
11001                                 } else {
11002                                         CHECK_STACK (1);
11003                                         --sp;
11004                                 }
11005                                 if (sp [0]->type == STACK_I4 || sp [0]->type == STACK_I8 || sp [0]->type == STACK_R8)
11006                                         UNVERIFIED;
11007                                 if (*ip != CEE_LDFLD && sp [0]->type == STACK_VTYPE)
11008                                         UNVERIFIED;
11009                         } else {
11010                                 if (op == CEE_STSFLD) {
11011                                         CHECK_STACK (1);
11012                                         sp--;
11013                                         store_val = sp [0];
11014                                 }
11015                         }
11016
11017                         CHECK_OPSIZE (5);
11018                         token = read32 (ip + 1);
11019                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
11020                                 field = mono_method_get_wrapper_data (method, token);
11021                                 klass = field->parent;
11022                         }
11023                         else {
11024                                 field = mono_field_from_token_checked (image, token, &klass, generic_context, &cfg->error);
11025                                 CHECK_CFG_ERROR;
11026                         }
11027                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
11028                                 FIELD_ACCESS_FAILURE (method, field);
11029                         mono_class_init (klass);
11030
11031                         /* if the class is Critical then transparent code cannot access it's fields */
11032                         if (!is_instance && mono_security_core_clr_enabled ())
11033                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
11034
11035                         /* XXX this is technically required but, so far (SL2), no [SecurityCritical] types (not many exists) have
11036                            any visible *instance* field  (in fact there's a single case for a static field in Marshal) XXX
11037                         if (mono_security_core_clr_enabled ())
11038                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
11039                         */
11040
11041                         ftype = mono_field_get_type (field);
11042
11043                         /*
11044                          * LDFLD etc. is usable on static fields as well, so convert those cases to
11045                          * the static case.
11046                          */
11047                         if (is_instance && ftype->attrs & FIELD_ATTRIBUTE_STATIC) {
11048                                 switch (op) {
11049                                 case CEE_LDFLD:
11050                                         op = CEE_LDSFLD;
11051                                         break;
11052                                 case CEE_STFLD:
11053                                         op = CEE_STSFLD;
11054                                         break;
11055                                 case CEE_LDFLDA:
11056                                         op = CEE_LDSFLDA;
11057                                         break;
11058                                 default:
11059                                         g_assert_not_reached ();
11060                                 }
11061                                 is_instance = FALSE;
11062                         }
11063
11064                         context_used = mini_class_check_context_used (cfg, klass);
11065
11066                         /* INSTANCE CASE */
11067
11068                         foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
11069                         if (op == CEE_STFLD) {
11070                                 if (target_type_is_incompatible (cfg, field->type, sp [1]))
11071                                         UNVERIFIED;
11072 #ifndef DISABLE_REMOTING
11073                                 if ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class) {
11074                                         MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type); 
11075                                         MonoInst *iargs [5];
11076
11077                                         GSHAREDVT_FAILURE (op);
11078
11079                                         iargs [0] = sp [0];
11080                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11081                                         EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
11082                                         EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : 
11083                                                     field->offset);
11084                                         iargs [4] = sp [1];
11085
11086                                         if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
11087                                                 costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), 
11088                                                                                            iargs, ip, cfg->real_offset, TRUE);
11089                                                 CHECK_CFG_EXCEPTION;
11090                                                 g_assert (costs > 0);
11091                                                       
11092                                                 cfg->real_offset += 5;
11093
11094                                                 inline_costs += costs;
11095                                         } else {
11096                                                 mono_emit_method_call (cfg, stfld_wrapper, iargs, NULL);
11097                                         }
11098                                 } else
11099 #endif
11100                                 {
11101                                         MonoInst *store;
11102
11103                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
11104
11105                                         if (mini_is_gsharedvt_klass (klass)) {
11106                                                 MonoInst *offset_ins;
11107
11108                                                 context_used = mini_class_check_context_used (cfg, klass);
11109
11110                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11111                                                 dreg = alloc_ireg_mp (cfg);
11112                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11113                                                 /* The decomposition will call mini_emit_stobj () which will emit a wbarrier if needed */
11114                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, dreg, 0, sp [1]->dreg);
11115                                         } else {
11116                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, sp [0]->dreg, foffset, sp [1]->dreg);
11117                                         }
11118                                         if (sp [0]->opcode != OP_LDADDR)
11119                                                 store->flags |= MONO_INST_FAULT;
11120
11121                                 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)) {
11122                                         /* insert call to write barrier */
11123                                         MonoInst *ptr;
11124                                         int dreg;
11125
11126                                         dreg = alloc_ireg_mp (cfg);
11127                                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
11128                                         emit_write_barrier (cfg, ptr, sp [1]);
11129                                 }
11130
11131                                         store->flags |= ins_flag;
11132                                 }
11133                                 ins_flag = 0;
11134                                 ip += 5;
11135                                 break;
11136                         }
11137
11138 #ifndef DISABLE_REMOTING
11139                         if (is_instance && ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class)) {
11140                                 MonoMethod *wrapper = (op == CEE_LDFLDA) ? mono_marshal_get_ldflda_wrapper (field->type) : mono_marshal_get_ldfld_wrapper (field->type); 
11141                                 MonoInst *iargs [4];
11142
11143                                 GSHAREDVT_FAILURE (op);
11144
11145                                 iargs [0] = sp [0];
11146                                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11147                                 EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
11148                                 EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
11149                                 if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
11150                                         costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), 
11151                                                                                    iargs, ip, cfg->real_offset, TRUE);
11152                                         CHECK_CFG_EXCEPTION;
11153                                         g_assert (costs > 0);
11154                                                       
11155                                         cfg->real_offset += 5;
11156
11157                                         *sp++ = iargs [0];
11158
11159                                         inline_costs += costs;
11160                                 } else {
11161                                         ins = mono_emit_method_call (cfg, wrapper, iargs, NULL);
11162                                         *sp++ = ins;
11163                                 }
11164                         } else 
11165 #endif
11166                         if (is_instance) {
11167                                 if (sp [0]->type == STACK_VTYPE) {
11168                                         MonoInst *var;
11169
11170                                         /* Have to compute the address of the variable */
11171
11172                                         var = get_vreg_to_inst (cfg, sp [0]->dreg);
11173                                         if (!var)
11174                                                 var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, sp [0]->dreg);
11175                                         else
11176                                                 g_assert (var->klass == klass);
11177                                         
11178                                         EMIT_NEW_VARLOADA (cfg, ins, var, &var->klass->byval_arg);
11179                                         sp [0] = ins;
11180                                 }
11181
11182                                 if (op == CEE_LDFLDA) {
11183                                         if (sp [0]->type == STACK_OBJ) {
11184                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
11185                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "NullReferenceException");
11186                                         }
11187
11188                                         dreg = alloc_ireg_mp (cfg);
11189
11190                                         if (mini_is_gsharedvt_klass (klass)) {
11191                                                 MonoInst *offset_ins;
11192
11193                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11194                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11195                                         } else {
11196                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
11197                                         }
11198                                         ins->klass = mono_class_from_mono_type (field->type);
11199                                         ins->type = STACK_MP;
11200                                         *sp++ = ins;
11201                                 } else {
11202                                         MonoInst *load;
11203
11204                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
11205
11206                                         if (mini_is_gsharedvt_klass (klass)) {
11207                                                 MonoInst *offset_ins;
11208
11209                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11210                                                 dreg = alloc_ireg_mp (cfg);
11211                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11212                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, dreg, 0);
11213                                         } else {
11214                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, sp [0]->dreg, foffset);
11215                                         }
11216                                         load->flags |= ins_flag;
11217                                         if (sp [0]->opcode != OP_LDADDR)
11218                                                 load->flags |= MONO_INST_FAULT;
11219                                         *sp++ = load;
11220                                 }
11221                         }
11222
11223                         if (is_instance) {
11224                                 ins_flag = 0;
11225                                 ip += 5;
11226                                 break;
11227                         }
11228
11229                         /* STATIC CASE */
11230                         context_used = mini_class_check_context_used (cfg, klass);
11231
11232                         if (ftype->attrs & FIELD_ATTRIBUTE_LITERAL)
11233                                 UNVERIFIED;
11234
11235                         /* The special_static_fields field is init'd in mono_class_vtable, so it needs
11236                          * to be called here.
11237                          */
11238                         if (!context_used && !(cfg->opt & MONO_OPT_SHARED)) {
11239                                 mono_class_vtable (cfg->domain, klass);
11240                                 CHECK_TYPELOAD (klass);
11241                         }
11242                         mono_domain_lock (cfg->domain);
11243                         if (cfg->domain->special_static_fields)
11244                                 addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
11245                         mono_domain_unlock (cfg->domain);
11246
11247                         is_special_static = mono_class_field_is_special_static (field);
11248
11249                         if (is_special_static && ((gsize)addr & 0x80000000) == 0)
11250                                 thread_ins = mono_get_thread_intrinsic (cfg);
11251                         else
11252                                 thread_ins = NULL;
11253
11254                         /* Generate IR to compute the field address */
11255                         if (is_special_static && ((gsize)addr & 0x80000000) == 0 && thread_ins && !(cfg->opt & MONO_OPT_SHARED) && !context_used) {
11256                                 /*
11257                                  * Fast access to TLS data
11258                                  * Inline version of get_thread_static_data () in
11259                                  * threads.c.
11260                                  */
11261                                 guint32 offset;
11262                                 int idx, static_data_reg, array_reg, dreg;
11263
11264                                 GSHAREDVT_FAILURE (op);
11265
11266                                 MONO_ADD_INS (cfg->cbb, thread_ins);
11267                                 static_data_reg = alloc_ireg (cfg);
11268                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, MONO_STRUCT_OFFSET (MonoInternalThread, static_data));
11269
11270                                 if (cfg->compile_aot) {
11271                                         int offset_reg, offset2_reg, idx_reg;
11272
11273                                         /* For TLS variables, this will return the TLS offset */
11274                                         EMIT_NEW_SFLDACONST (cfg, ins, field);
11275                                         offset_reg = ins->dreg;
11276                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset_reg, offset_reg, 0x7fffffff);
11277                                         idx_reg = alloc_ireg (cfg);
11278                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, idx_reg, offset_reg, 0x3f);
11279                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
11280                                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
11281                                         array_reg = alloc_ireg (cfg);
11282                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
11283                                         offset2_reg = alloc_ireg (cfg);
11284                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, offset2_reg, offset_reg, 6);
11285                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset2_reg, 0x1ffffff);
11286                                         dreg = alloc_ireg (cfg);
11287                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, array_reg, offset2_reg);
11288                                 } else {
11289                                         offset = (gsize)addr & 0x7fffffff;
11290                                         idx = offset & 0x3f;
11291
11292                                         array_reg = alloc_ireg (cfg);
11293                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, idx * sizeof (gpointer));
11294                                         dreg = alloc_ireg (cfg);
11295                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_ADD_IMM, dreg, array_reg, ((offset >> 6) & 0x1ffffff));
11296                                 }
11297                         } else if ((cfg->opt & MONO_OPT_SHARED) ||
11298                                         (cfg->compile_aot && is_special_static) ||
11299                                         (context_used && is_special_static)) {
11300                                 MonoInst *iargs [2];
11301
11302                                 g_assert (field->parent);
11303                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11304                                 if (context_used) {
11305                                         iargs [1] = emit_get_rgctx_field (cfg, context_used,
11306                                                 field, MONO_RGCTX_INFO_CLASS_FIELD);
11307                                 } else {
11308                                         EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
11309                                 }
11310                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
11311                         } else if (context_used) {
11312                                 MonoInst *static_data;
11313
11314                                 /*
11315                                 g_print ("sharing static field access in %s.%s.%s - depth %d offset %d\n",
11316                                         method->klass->name_space, method->klass->name, method->name,
11317                                         depth, field->offset);
11318                                 */
11319
11320                                 if (mono_class_needs_cctor_run (klass, method))
11321                                         emit_class_init (cfg, klass);
11322
11323                                 /*
11324                                  * The pointer we're computing here is
11325                                  *
11326                                  *   super_info.static_data + field->offset
11327                                  */
11328                                 static_data = emit_get_rgctx_klass (cfg, context_used,
11329                                         klass, MONO_RGCTX_INFO_STATIC_DATA);
11330
11331                                 if (mini_is_gsharedvt_klass (klass)) {
11332                                         MonoInst *offset_ins;
11333
11334                                         offset_ins = emit_get_rgctx_field (cfg, context_used, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11335                                         dreg = alloc_ireg_mp (cfg);
11336                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, static_data->dreg, offset_ins->dreg);
11337                                 } else if (field->offset == 0) {
11338                                         ins = static_data;
11339                                 } else {
11340                                         int addr_reg = mono_alloc_preg (cfg);
11341                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, addr_reg, static_data->dreg, field->offset);
11342                                 }
11343                                 } else if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
11344                                 MonoInst *iargs [2];
11345
11346                                 g_assert (field->parent);
11347                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11348                                 EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
11349                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
11350                         } else {
11351                                 MonoVTable *vtable = NULL;
11352
11353                                 if (!cfg->compile_aot)
11354                                         vtable = mono_class_vtable (cfg->domain, klass);
11355                                 CHECK_TYPELOAD (klass);
11356
11357                                 if (!addr) {
11358                                         if (mini_field_access_needs_cctor_run (cfg, method, klass, vtable)) {
11359                                                 if (!(g_slist_find (class_inits, klass))) {
11360                                                         emit_class_init (cfg, klass);
11361                                                         if (cfg->verbose_level > 2)
11362                                                                 printf ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, mono_field_get_name (field));
11363                                                         class_inits = g_slist_prepend (class_inits, klass);
11364                                                 }
11365                                         } else {
11366                                                 if (cfg->run_cctors) {
11367                                                         MonoException *ex;
11368                                                         /* This makes so that inline cannot trigger */
11369                                                         /* .cctors: too many apps depend on them */
11370                                                         /* running with a specific order... */
11371                                                         g_assert (vtable);
11372                                                         if (! vtable->initialized)
11373                                                                 INLINE_FAILURE ("class init");
11374                                                         ex = mono_runtime_class_init_full (vtable, FALSE);
11375                                                         if (ex) {
11376                                                                 set_exception_object (cfg, ex);
11377                                                                 goto exception_exit;
11378                                                         }
11379                                                 }
11380                                         }
11381                                         if (cfg->compile_aot)
11382                                                 EMIT_NEW_SFLDACONST (cfg, ins, field);
11383                                         else {
11384                                                 g_assert (vtable);
11385                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11386                                                 g_assert (addr);
11387                                                 EMIT_NEW_PCONST (cfg, ins, addr);
11388                                         }
11389                                 } else {
11390                                         MonoInst *iargs [1];
11391                                         EMIT_NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
11392                                         ins = mono_emit_jit_icall (cfg, mono_get_special_static_data, iargs);
11393                                 }
11394                         }
11395
11396                         /* Generate IR to do the actual load/store operation */
11397
11398                         if ((op == CEE_STFLD || op == CEE_STSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11399                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11400                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11401                         }
11402
11403                         if (op == CEE_LDSFLDA) {
11404                                 ins->klass = mono_class_from_mono_type (ftype);
11405                                 ins->type = STACK_PTR;
11406                                 *sp++ = ins;
11407                         } else if (op == CEE_STSFLD) {
11408                                 MonoInst *store;
11409
11410                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, ftype, ins->dreg, 0, store_val->dreg);
11411                                 store->flags |= ins_flag;
11412                         } else {
11413                                 gboolean is_const = FALSE;
11414                                 MonoVTable *vtable = NULL;
11415                                 gpointer addr = NULL;
11416
11417                                 if (!context_used) {
11418                                         vtable = mono_class_vtable (cfg->domain, klass);
11419                                         CHECK_TYPELOAD (klass);
11420                                 }
11421                                 if ((ftype->attrs & FIELD_ATTRIBUTE_INIT_ONLY) && (((addr = mono_aot_readonly_field_override (field)) != NULL) ||
11422                                                 (!context_used && !((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && vtable->initialized))) {
11423                                         int ro_type = ftype->type;
11424                                         if (!addr)
11425                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11426                                         if (ro_type == MONO_TYPE_VALUETYPE && ftype->data.klass->enumtype) {
11427                                                 ro_type = mono_class_enum_basetype (ftype->data.klass)->type;
11428                                         }
11429
11430                                         GSHAREDVT_FAILURE (op);
11431
11432                                         /* printf ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, mono_field_get_name (field));*/
11433                                         is_const = TRUE;
11434                                         switch (ro_type) {
11435                                         case MONO_TYPE_BOOLEAN:
11436                                         case MONO_TYPE_U1:
11437                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint8 *)addr));
11438                                                 sp++;
11439                                                 break;
11440                                         case MONO_TYPE_I1:
11441                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint8 *)addr));
11442                                                 sp++;
11443                                                 break;                                          
11444                                         case MONO_TYPE_CHAR:
11445                                         case MONO_TYPE_U2:
11446                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint16 *)addr));
11447                                                 sp++;
11448                                                 break;
11449                                         case MONO_TYPE_I2:
11450                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint16 *)addr));
11451                                                 sp++;
11452                                                 break;
11453                                                 break;
11454                                         case MONO_TYPE_I4:
11455                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint32 *)addr));
11456                                                 sp++;
11457                                                 break;                                          
11458                                         case MONO_TYPE_U4:
11459                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint32 *)addr));
11460                                                 sp++;
11461                                                 break;
11462                                         case MONO_TYPE_I:
11463                                         case MONO_TYPE_U:
11464                                         case MONO_TYPE_PTR:
11465                                         case MONO_TYPE_FNPTR:
11466                                                 EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11467                                                 type_to_eval_stack_type ((cfg), field->type, *sp);
11468                                                 sp++;
11469                                                 break;
11470                                         case MONO_TYPE_STRING:
11471                                         case MONO_TYPE_OBJECT:
11472                                         case MONO_TYPE_CLASS:
11473                                         case MONO_TYPE_SZARRAY:
11474                                         case MONO_TYPE_ARRAY:
11475                                                 if (!mono_gc_is_moving ()) {
11476                                                         EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11477                                                         type_to_eval_stack_type ((cfg), field->type, *sp);
11478                                                         sp++;
11479                                                 } else {
11480                                                         is_const = FALSE;
11481                                                 }
11482                                                 break;
11483                                         case MONO_TYPE_I8:
11484                                         case MONO_TYPE_U8:
11485                                                 EMIT_NEW_I8CONST (cfg, *sp, *((gint64 *)addr));
11486                                                 sp++;
11487                                                 break;
11488                                         case MONO_TYPE_R4:
11489                                         case MONO_TYPE_R8:
11490                                         case MONO_TYPE_VALUETYPE:
11491                                         default:
11492                                                 is_const = FALSE;
11493                                                 break;
11494                                         }
11495                                 }
11496
11497                                 if (!is_const) {
11498                                         MonoInst *load;
11499
11500                                         CHECK_STACK_OVF (1);
11501
11502                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, ins->dreg, 0);
11503                                         load->flags |= ins_flag;
11504                                         ins_flag = 0;
11505                                         *sp++ = load;
11506                                 }
11507                         }
11508
11509                         if ((op == CEE_LDFLD || op == CEE_LDSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11510                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
11511                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
11512                         }
11513
11514                         ins_flag = 0;
11515                         ip += 5;
11516                         break;
11517                 }
11518                 case CEE_STOBJ:
11519                         CHECK_STACK (2);
11520                         sp -= 2;
11521                         CHECK_OPSIZE (5);
11522                         token = read32 (ip + 1);
11523                         klass = mini_get_class (method, token, generic_context);
11524                         CHECK_TYPELOAD (klass);
11525                         if (ins_flag & MONO_INST_VOLATILE) {
11526                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11527                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11528                         }
11529                         /* FIXME: should check item at sp [1] is compatible with the type of the store. */
11530                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0, sp [1]->dreg);
11531                         ins->flags |= ins_flag;
11532                         if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER &&
11533                                         generic_class_is_reference_type (cfg, klass)) {
11534                                 /* insert call to write barrier */
11535                                 emit_write_barrier (cfg, sp [0], sp [1]);
11536                         }
11537                         ins_flag = 0;
11538                         ip += 5;
11539                         inline_costs += 1;
11540                         break;
11541
11542                         /*
11543                          * Array opcodes
11544                          */
11545                 case CEE_NEWARR: {
11546                         MonoInst *len_ins;
11547                         const char *data_ptr;
11548                         int data_size = 0;
11549                         guint32 field_token;
11550
11551                         CHECK_STACK (1);
11552                         --sp;
11553
11554                         CHECK_OPSIZE (5);
11555                         token = read32 (ip + 1);
11556
11557                         klass = mini_get_class (method, token, generic_context);
11558                         CHECK_TYPELOAD (klass);
11559
11560                         context_used = mini_class_check_context_used (cfg, klass);
11561
11562                         if (sp [0]->type == STACK_I8 || (SIZEOF_VOID_P == 8 && sp [0]->type == STACK_PTR)) {
11563                                 MONO_INST_NEW (cfg, ins, OP_LCONV_TO_OVF_U4);
11564                                 ins->sreg1 = sp [0]->dreg;
11565                                 ins->type = STACK_I4;
11566                                 ins->dreg = alloc_ireg (cfg);
11567                                 MONO_ADD_INS (cfg->cbb, ins);
11568                                 *sp = mono_decompose_opcode (cfg, ins);
11569                         }
11570
11571                         if (context_used) {
11572                                 MonoInst *args [3];
11573                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11574                                 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
11575
11576                                 /* FIXME: Use OP_NEWARR and decompose later to help abcrem */
11577
11578                                 /* vtable */
11579                                 args [0] = emit_get_rgctx_klass (cfg, context_used,
11580                                         array_class, MONO_RGCTX_INFO_VTABLE);
11581                                 /* array len */
11582                                 args [1] = sp [0];
11583
11584                                 if (managed_alloc)
11585                                         ins = mono_emit_method_call (cfg, managed_alloc, args, NULL);
11586                                 else
11587                                         ins = mono_emit_jit_icall (cfg, mono_array_new_specific, args);
11588                         } else {
11589                                 if (cfg->opt & MONO_OPT_SHARED) {
11590                                         /* Decompose now to avoid problems with references to the domainvar */
11591                                         MonoInst *iargs [3];
11592
11593                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11594                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11595                                         iargs [2] = sp [0];
11596
11597                                         ins = mono_emit_jit_icall (cfg, mono_array_new, iargs);
11598                                 } else {
11599                                         /* Decompose later since it is needed by abcrem */
11600                                         MonoClass *array_type = mono_array_class_get (klass, 1);
11601                                         mono_class_vtable (cfg->domain, array_type);
11602                                         CHECK_TYPELOAD (array_type);
11603
11604                                         MONO_INST_NEW (cfg, ins, OP_NEWARR);
11605                                         ins->dreg = alloc_ireg_ref (cfg);
11606                                         ins->sreg1 = sp [0]->dreg;
11607                                         ins->inst_newa_class = klass;
11608                                         ins->type = STACK_OBJ;
11609                                         ins->klass = array_type;
11610                                         MONO_ADD_INS (cfg->cbb, ins);
11611                                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11612                                         cfg->cbb->has_array_access = TRUE;
11613
11614                                         /* Needed so mono_emit_load_get_addr () gets called */
11615                                         mono_get_got_var (cfg);
11616                                 }
11617                         }
11618
11619                         len_ins = sp [0];
11620                         ip += 5;
11621                         *sp++ = ins;
11622                         inline_costs += 1;
11623
11624                         /* 
11625                          * we inline/optimize the initialization sequence if possible.
11626                          * we should also allocate the array as not cleared, since we spend as much time clearing to 0 as initializing
11627                          * for small sizes open code the memcpy
11628                          * ensure the rva field is big enough
11629                          */
11630                         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))) {
11631                                 MonoMethod *memcpy_method = get_memcpy_method ();
11632                                 MonoInst *iargs [3];
11633                                 int add_reg = alloc_ireg_mp (cfg);
11634
11635                                 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, add_reg, ins->dreg, MONO_STRUCT_OFFSET (MonoArray, vector));
11636                                 if (cfg->compile_aot) {
11637                                         EMIT_NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(field_token), STACK_PTR, NULL);
11638                                 } else {
11639                                         EMIT_NEW_PCONST (cfg, iargs [1], (char*)data_ptr);
11640                                 }
11641                                 EMIT_NEW_ICONST (cfg, iargs [2], data_size);
11642                                 mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
11643                                 ip += 11;
11644                         }
11645
11646                         break;
11647                 }
11648                 case CEE_LDLEN:
11649                         CHECK_STACK (1);
11650                         --sp;
11651                         if (sp [0]->type != STACK_OBJ)
11652                                 UNVERIFIED;
11653
11654                         MONO_INST_NEW (cfg, ins, OP_LDLEN);
11655                         ins->dreg = alloc_preg (cfg);
11656                         ins->sreg1 = sp [0]->dreg;
11657                         ins->type = STACK_I4;
11658                         /* This flag will be inherited by the decomposition */
11659                         ins->flags |= MONO_INST_FAULT;
11660                         MONO_ADD_INS (cfg->cbb, ins);
11661                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11662                         cfg->cbb->has_array_access = TRUE;
11663                         ip ++;
11664                         *sp++ = ins;
11665                         break;
11666                 case CEE_LDELEMA:
11667                         CHECK_STACK (2);
11668                         sp -= 2;
11669                         CHECK_OPSIZE (5);
11670                         if (sp [0]->type != STACK_OBJ)
11671                                 UNVERIFIED;
11672
11673                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11674
11675                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11676                         CHECK_TYPELOAD (klass);
11677                         /* we need to make sure that this array is exactly the type it needs
11678                          * to be for correctness. the wrappers are lax with their usage
11679                          * so we need to ignore them here
11680                          */
11681                         if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE && !readonly) {
11682                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11683                                 mini_emit_check_array_type (cfg, sp [0], array_class);
11684                                 CHECK_TYPELOAD (array_class);
11685                         }
11686
11687                         readonly = FALSE;
11688                         ins = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11689                         *sp++ = ins;
11690                         ip += 5;
11691                         break;
11692                 case CEE_LDELEM:
11693                 case CEE_LDELEM_I1:
11694                 case CEE_LDELEM_U1:
11695                 case CEE_LDELEM_I2:
11696                 case CEE_LDELEM_U2:
11697                 case CEE_LDELEM_I4:
11698                 case CEE_LDELEM_U4:
11699                 case CEE_LDELEM_I8:
11700                 case CEE_LDELEM_I:
11701                 case CEE_LDELEM_R4:
11702                 case CEE_LDELEM_R8:
11703                 case CEE_LDELEM_REF: {
11704                         MonoInst *addr;
11705
11706                         CHECK_STACK (2);
11707                         sp -= 2;
11708
11709                         if (*ip == CEE_LDELEM) {
11710                                 CHECK_OPSIZE (5);
11711                                 token = read32 (ip + 1);
11712                                 klass = mini_get_class (method, token, generic_context);
11713                                 CHECK_TYPELOAD (klass);
11714                                 mono_class_init (klass);
11715                         }
11716                         else
11717                                 klass = array_access_to_klass (*ip);
11718
11719                         if (sp [0]->type != STACK_OBJ)
11720                                 UNVERIFIED;
11721
11722                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11723
11724                         if (mini_is_gsharedvt_variable_klass (klass)) {
11725                                 // FIXME-VT: OP_ICONST optimization
11726                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11727                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11728                                 ins->opcode = OP_LOADV_MEMBASE;
11729                         } else if (sp [1]->opcode == OP_ICONST) {
11730                                 int array_reg = sp [0]->dreg;
11731                                 int index_reg = sp [1]->dreg;
11732                                 int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
11733
11734                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
11735                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset);
11736                         } else {
11737                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11738                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11739                         }
11740                         *sp++ = ins;
11741                         if (*ip == CEE_LDELEM)
11742                                 ip += 5;
11743                         else
11744                                 ++ip;
11745                         break;
11746                 }
11747                 case CEE_STELEM_I:
11748                 case CEE_STELEM_I1:
11749                 case CEE_STELEM_I2:
11750                 case CEE_STELEM_I4:
11751                 case CEE_STELEM_I8:
11752                 case CEE_STELEM_R4:
11753                 case CEE_STELEM_R8:
11754                 case CEE_STELEM_REF:
11755                 case CEE_STELEM: {
11756                         CHECK_STACK (3);
11757                         sp -= 3;
11758
11759                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11760
11761                         if (*ip == CEE_STELEM) {
11762                                 CHECK_OPSIZE (5);
11763                                 token = read32 (ip + 1);
11764                                 klass = mini_get_class (method, token, generic_context);
11765                                 CHECK_TYPELOAD (klass);
11766                                 mono_class_init (klass);
11767                         }
11768                         else
11769                                 klass = array_access_to_klass (*ip);
11770
11771                         if (sp [0]->type != STACK_OBJ)
11772                                 UNVERIFIED;
11773
11774                         emit_array_store (cfg, klass, sp, TRUE);
11775
11776                         if (*ip == CEE_STELEM)
11777                                 ip += 5;
11778                         else
11779                                 ++ip;
11780                         inline_costs += 1;
11781                         break;
11782                 }
11783                 case CEE_CKFINITE: {
11784                         CHECK_STACK (1);
11785                         --sp;
11786
11787                         if (cfg->llvm_only) {
11788                                 MonoInst *iargs [1];
11789
11790                                 iargs [0] = sp [0];
11791                                 *sp++ = mono_emit_jit_icall (cfg, mono_ckfinite, iargs);
11792                         } else  {
11793                                 MONO_INST_NEW (cfg, ins, OP_CKFINITE);
11794                                 ins->sreg1 = sp [0]->dreg;
11795                                 ins->dreg = alloc_freg (cfg);
11796                                 ins->type = STACK_R8;
11797                                 MONO_ADD_INS (cfg->cbb, ins);
11798
11799                                 *sp++ = mono_decompose_opcode (cfg, ins);
11800                         }
11801
11802                         ++ip;
11803                         break;
11804                 }
11805                 case CEE_REFANYVAL: {
11806                         MonoInst *src_var, *src;
11807
11808                         int klass_reg = alloc_preg (cfg);
11809                         int dreg = alloc_preg (cfg);
11810
11811                         GSHAREDVT_FAILURE (*ip);
11812
11813                         CHECK_STACK (1);
11814                         MONO_INST_NEW (cfg, ins, *ip);
11815                         --sp;
11816                         CHECK_OPSIZE (5);
11817                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11818                         CHECK_TYPELOAD (klass);
11819
11820                         context_used = mini_class_check_context_used (cfg, klass);
11821
11822                         // FIXME:
11823                         src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
11824                         if (!src_var)
11825                                 src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
11826                         EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
11827                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass));
11828
11829                         if (context_used) {
11830                                 MonoInst *klass_ins;
11831
11832                                 klass_ins = emit_get_rgctx_klass (cfg, context_used,
11833                                                 klass, MONO_RGCTX_INFO_KLASS);
11834
11835                                 // FIXME:
11836                                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_ins->dreg);
11837                                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
11838                         } else {
11839                                 mini_emit_class_check (cfg, klass_reg, klass);
11840                         }
11841                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value));
11842                         ins->type = STACK_MP;
11843                         ins->klass = klass;
11844                         *sp++ = ins;
11845                         ip += 5;
11846                         break;
11847                 }
11848                 case CEE_MKREFANY: {
11849                         MonoInst *loc, *addr;
11850
11851                         GSHAREDVT_FAILURE (*ip);
11852
11853                         CHECK_STACK (1);
11854                         MONO_INST_NEW (cfg, ins, *ip);
11855                         --sp;
11856                         CHECK_OPSIZE (5);
11857                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11858                         CHECK_TYPELOAD (klass);
11859
11860                         context_used = mini_class_check_context_used (cfg, klass);
11861
11862                         loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
11863                         EMIT_NEW_TEMPLOADA (cfg, addr, loc->inst_c0);
11864
11865                         if (context_used) {
11866                                 MonoInst *const_ins;
11867                                 int type_reg = alloc_preg (cfg);
11868
11869                                 const_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
11870                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_ins->dreg);
11871                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_ins->dreg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
11872                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
11873                         } else if (cfg->compile_aot) {
11874                                 int const_reg = alloc_preg (cfg);
11875                                 int type_reg = alloc_preg (cfg);
11876
11877                                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
11878                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_reg);
11879                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_reg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
11880                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
11881                         } else {
11882                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), &klass->byval_arg);
11883                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), klass);
11884                         }
11885                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value), sp [0]->dreg);
11886
11887                         EMIT_NEW_TEMPLOAD (cfg, ins, loc->inst_c0);
11888                         ins->type = STACK_VTYPE;
11889                         ins->klass = mono_defaults.typed_reference_class;
11890                         *sp++ = ins;
11891                         ip += 5;
11892                         break;
11893                 }
11894                 case CEE_LDTOKEN: {
11895                         gpointer handle;
11896                         MonoClass *handle_class;
11897
11898                         CHECK_STACK_OVF (1);
11899
11900                         CHECK_OPSIZE (5);
11901                         n = read32 (ip + 1);
11902
11903                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD ||
11904                                         method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
11905                                 handle = mono_method_get_wrapper_data (method, n);
11906                                 handle_class = mono_method_get_wrapper_data (method, n + 1);
11907                                 if (handle_class == mono_defaults.typehandle_class)
11908                                         handle = &((MonoClass*)handle)->byval_arg;
11909                         }
11910                         else {
11911                                 handle = mono_ldtoken_checked (image, n, &handle_class, generic_context, &cfg->error);
11912                                 CHECK_CFG_ERROR;
11913                         }
11914                         if (!handle)
11915                                 LOAD_ERROR;
11916                         mono_class_init (handle_class);
11917                         if (cfg->gshared) {
11918                                 if (mono_metadata_token_table (n) == MONO_TABLE_TYPEDEF ||
11919                                                 mono_metadata_token_table (n) == MONO_TABLE_TYPEREF) {
11920                                         /* This case handles ldtoken
11921                                            of an open type, like for
11922                                            typeof(Gen<>). */
11923                                         context_used = 0;
11924                                 } else if (handle_class == mono_defaults.typehandle_class) {
11925                                         context_used = mini_class_check_context_used (cfg, mono_class_from_mono_type (handle));
11926                                 } else if (handle_class == mono_defaults.fieldhandle_class)
11927                                         context_used = mini_class_check_context_used (cfg, ((MonoClassField*)handle)->parent);
11928                                 else if (handle_class == mono_defaults.methodhandle_class)
11929                                         context_used = mini_method_check_context_used (cfg, handle);
11930                                 else
11931                                         g_assert_not_reached ();
11932                         }
11933
11934                         if ((cfg->opt & MONO_OPT_SHARED) &&
11935                                         method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD &&
11936                                         method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED) {
11937                                 MonoInst *addr, *vtvar, *iargs [3];
11938                                 int method_context_used;
11939
11940                                 method_context_used = mini_method_check_context_used (cfg, method);
11941
11942                                 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL); 
11943
11944                                 EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
11945                                 EMIT_NEW_ICONST (cfg, iargs [1], n);
11946                                 if (method_context_used) {
11947                                         iargs [2] = emit_get_rgctx_method (cfg, method_context_used,
11948                                                 method, MONO_RGCTX_INFO_METHOD);
11949                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper_generic_shared, iargs);
11950                                 } else {
11951                                         EMIT_NEW_PCONST (cfg, iargs [2], generic_context);
11952                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper, iargs);
11953                                 }
11954                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
11955
11956                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
11957
11958                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
11959                         } else {
11960                                 if ((ip + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 5) && 
11961                                         ((ip [5] == CEE_CALL) || (ip [5] == CEE_CALLVIRT)) && 
11962                                         (cmethod = mini_get_method (cfg, method, read32 (ip + 6), NULL, generic_context)) &&
11963                                         (cmethod->klass == mono_defaults.systemtype_class) &&
11964                                         (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
11965                                         MonoClass *tclass = mono_class_from_mono_type (handle);
11966
11967                                         mono_class_init (tclass);
11968                                         if (context_used) {
11969                                                 ins = emit_get_rgctx_klass (cfg, context_used,
11970                                                         tclass, MONO_RGCTX_INFO_REFLECTION_TYPE);
11971                                         } else if (cfg->compile_aot) {
11972                                                 if (method->wrapper_type) {
11973                                                         mono_error_init (&error); //got to do it since there are multiple conditionals below
11974                                                         if (mono_class_get_checked (tclass->image, tclass->type_token, &error) == tclass && !generic_context) {
11975                                                                 /* Special case for static synchronized wrappers */
11976                                                                 EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, tclass->image, tclass->type_token, generic_context);
11977                                                         } else {
11978                                                                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
11979                                                                 /* FIXME: n is not a normal token */
11980                                                                 DISABLE_AOT (cfg);
11981                                                                 EMIT_NEW_PCONST (cfg, ins, NULL);
11982                                                         }
11983                                                 } else {
11984                                                         EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n, generic_context);
11985                                                 }
11986                                         } else {
11987                                                 EMIT_NEW_PCONST (cfg, ins, mono_type_get_object (cfg->domain, handle));
11988                                         }
11989                                         ins->type = STACK_OBJ;
11990                                         ins->klass = cmethod->klass;
11991                                         ip += 5;
11992                                 } else {
11993                                         MonoInst *addr, *vtvar;
11994
11995                                         vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
11996
11997                                         if (context_used) {
11998                                                 if (handle_class == mono_defaults.typehandle_class) {
11999                                                         ins = emit_get_rgctx_klass (cfg, context_used,
12000                                                                         mono_class_from_mono_type (handle),
12001                                                                         MONO_RGCTX_INFO_TYPE);
12002                                                 } else if (handle_class == mono_defaults.methodhandle_class) {
12003                                                         ins = emit_get_rgctx_method (cfg, context_used,
12004                                                                         handle, MONO_RGCTX_INFO_METHOD);
12005                                                 } else if (handle_class == mono_defaults.fieldhandle_class) {
12006                                                         ins = emit_get_rgctx_field (cfg, context_used,
12007                                                                         handle, MONO_RGCTX_INFO_CLASS_FIELD);
12008                                                 } else {
12009                                                         g_assert_not_reached ();
12010                                                 }
12011                                         } else if (cfg->compile_aot) {
12012                                                 EMIT_NEW_LDTOKENCONST (cfg, ins, image, n, generic_context);
12013                                         } else {
12014                                                 EMIT_NEW_PCONST (cfg, ins, handle);
12015                                         }
12016                                         EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
12017                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
12018                                         EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
12019                                 }
12020                         }
12021
12022                         *sp++ = ins;
12023                         ip += 5;
12024                         break;
12025                 }
12026                 case CEE_THROW:
12027                         CHECK_STACK (1);
12028                         MONO_INST_NEW (cfg, ins, OP_THROW);
12029                         --sp;
12030                         ins->sreg1 = sp [0]->dreg;
12031                         ip++;
12032                         cfg->cbb->out_of_line = TRUE;
12033                         MONO_ADD_INS (cfg->cbb, ins);
12034                         MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
12035                         MONO_ADD_INS (cfg->cbb, ins);
12036                         sp = stack_start;
12037                         
12038                         link_bblock (cfg, cfg->cbb, end_bblock);
12039                         start_new_bblock = 1;
12040                         /* This can complicate code generation for llvm since the return value might not be defined */
12041                         if (COMPILE_LLVM (cfg))
12042                                 INLINE_FAILURE ("throw");
12043                         break;
12044                 case CEE_ENDFINALLY:
12045                         /* mono_save_seq_point_info () depends on this */
12046                         if (sp != stack_start)
12047                                 emit_seq_point (cfg, method, ip, FALSE, FALSE);
12048                         MONO_INST_NEW (cfg, ins, OP_ENDFINALLY);
12049                         MONO_ADD_INS (cfg->cbb, ins);
12050                         ip++;
12051                         start_new_bblock = 1;
12052
12053                         /*
12054                          * Control will leave the method so empty the stack, otherwise
12055                          * the next basic block will start with a nonempty stack.
12056                          */
12057                         while (sp != stack_start) {
12058                                 sp--;
12059                         }
12060                         break;
12061                 case CEE_LEAVE:
12062                 case CEE_LEAVE_S: {
12063                         GList *handlers;
12064
12065                         if (*ip == CEE_LEAVE) {
12066                                 CHECK_OPSIZE (5);
12067                                 target = ip + 5 + (gint32)read32(ip + 1);
12068                         } else {
12069                                 CHECK_OPSIZE (2);
12070                                 target = ip + 2 + (signed char)(ip [1]);
12071                         }
12072
12073                         /* empty the stack */
12074                         while (sp != stack_start) {
12075                                 sp--;
12076                         }
12077
12078                         /* 
12079                          * If this leave statement is in a catch block, check for a
12080                          * pending exception, and rethrow it if necessary.
12081                          * We avoid doing this in runtime invoke wrappers, since those are called
12082                          * by native code which excepts the wrapper to catch all exceptions.
12083                          */
12084                         for (i = 0; i < header->num_clauses; ++i) {
12085                                 MonoExceptionClause *clause = &header->clauses [i];
12086
12087                                 /* 
12088                                  * Use <= in the final comparison to handle clauses with multiple
12089                                  * leave statements, like in bug #78024.
12090                                  * The ordering of the exception clauses guarantees that we find the
12091                                  * innermost clause.
12092                                  */
12093                                 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) {
12094                                         MonoInst *exc_ins;
12095                                         MonoBasicBlock *dont_throw;
12096
12097                                         /*
12098                                           MonoInst *load;
12099
12100                                           NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, clause->handler_offset)->inst_c0);
12101                                         */
12102
12103                                         exc_ins = mono_emit_jit_icall (cfg, mono_thread_get_undeniable_exception, NULL);
12104
12105                                         NEW_BBLOCK (cfg, dont_throw);
12106
12107                                         /*
12108                                          * Currently, we always rethrow the abort exception, despite the 
12109                                          * fact that this is not correct. See thread6.cs for an example. 
12110                                          * But propagating the abort exception is more important than 
12111                                          * getting the sematics right.
12112                                          */
12113                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, exc_ins->dreg, 0);
12114                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, dont_throw);
12115                                         MONO_EMIT_NEW_UNALU (cfg, OP_THROW, -1, exc_ins->dreg);
12116
12117                                         MONO_START_BB (cfg, dont_throw);
12118                                 }
12119                         }
12120
12121 #ifdef ENABLE_LLVM
12122                         cfg->cbb->try_end = (intptr_t)(ip - header->code);
12123 #endif
12124
12125                         if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
12126                                 GList *tmp;
12127                                 MonoExceptionClause *clause;
12128
12129                                 for (tmp = handlers; tmp; tmp = tmp->next) {
12130                                         clause = tmp->data;
12131                                         tblock = cfg->cil_offset_to_bb [clause->handler_offset];
12132                                         g_assert (tblock);
12133                                         link_bblock (cfg, cfg->cbb, tblock);
12134                                         MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
12135                                         ins->inst_target_bb = tblock;
12136                                         ins->inst_eh_block = clause;
12137                                         MONO_ADD_INS (cfg->cbb, ins);
12138                                         cfg->cbb->has_call_handler = 1;
12139                                         if (COMPILE_LLVM (cfg)) {
12140                                                 MonoBasicBlock *target_bb;
12141
12142                                                 /* 
12143                                                  * Link the finally bblock with the target, since it will
12144                                                  * conceptually branch there.
12145                                                  * FIXME: Have to link the bblock containing the endfinally.
12146                                                  */
12147                                                 GET_BBLOCK (cfg, target_bb, target);
12148                                                 link_bblock (cfg, tblock, target_bb);
12149                                         }
12150                                 }
12151                                 g_list_free (handlers);
12152                         } 
12153
12154                         MONO_INST_NEW (cfg, ins, OP_BR);
12155                         MONO_ADD_INS (cfg->cbb, ins);
12156                         GET_BBLOCK (cfg, tblock, target);
12157                         link_bblock (cfg, cfg->cbb, tblock);
12158                         ins->inst_target_bb = tblock;
12159
12160                         start_new_bblock = 1;
12161
12162                         if (*ip == CEE_LEAVE)
12163                                 ip += 5;
12164                         else
12165                                 ip += 2;
12166
12167                         break;
12168                 }
12169
12170                         /*
12171                          * Mono specific opcodes
12172                          */
12173                 case MONO_CUSTOM_PREFIX: {
12174
12175                         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
12176
12177                         CHECK_OPSIZE (2);
12178                         switch (ip [1]) {
12179                         case CEE_MONO_ICALL: {
12180                                 gpointer func;
12181                                 MonoJitICallInfo *info;
12182
12183                                 token = read32 (ip + 2);
12184                                 func = mono_method_get_wrapper_data (method, token);
12185                                 info = mono_find_jit_icall_by_addr (func);
12186                                 if (!info)
12187                                         g_error ("Could not find icall address in wrapper %s", mono_method_full_name (method, 1));
12188                                 g_assert (info);
12189
12190                                 CHECK_STACK (info->sig->param_count);
12191                                 sp -= info->sig->param_count;
12192
12193                                 ins = mono_emit_jit_icall (cfg, info->func, sp);
12194                                 if (!MONO_TYPE_IS_VOID (info->sig->ret))
12195                                         *sp++ = ins;
12196
12197                                 ip += 6;
12198                                 inline_costs += 10 * num_calls++;
12199
12200                                 break;
12201                         }
12202                         case CEE_MONO_LDPTR_CARD_TABLE:
12203                         case CEE_MONO_LDPTR_NURSERY_START:
12204                         case CEE_MONO_LDPTR_NURSERY_BITS:
12205                         case CEE_MONO_LDPTR_INT_REQ_FLAG: {
12206                                 CHECK_STACK_OVF (1);
12207
12208                                 switch (ip [1]) {
12209                                         case CEE_MONO_LDPTR_CARD_TABLE:
12210                                                 emit_runtime_constant (cfg, &ins, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR);
12211                                                 break;
12212                                         case CEE_MONO_LDPTR_NURSERY_START:
12213                                                 emit_runtime_constant (cfg, &ins, MONO_PATCH_INFO_GC_NURSERY_START);
12214                                                 break;
12215                                         case CEE_MONO_LDPTR_NURSERY_BITS:
12216                                                 emit_runtime_constant (cfg, &ins, MONO_PATCH_INFO_GC_NURSERY_BITS);
12217                                                 break;
12218                                         case CEE_MONO_LDPTR_INT_REQ_FLAG:
12219                                                 emit_runtime_constant (cfg, &ins, MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG);
12220                                                 break;
12221                                 }
12222
12223                                 *sp++ = ins;
12224                                 ip += 2;
12225                                 inline_costs += 10 * num_calls++;
12226                                 break;
12227                         }
12228                         case CEE_MONO_LDPTR: {
12229                                 gpointer ptr;
12230
12231                                 CHECK_STACK_OVF (1);
12232                                 CHECK_OPSIZE (6);
12233                                 token = read32 (ip + 2);
12234
12235                                 ptr = mono_method_get_wrapper_data (method, token);
12236                                 EMIT_NEW_PCONST (cfg, ins, ptr);
12237                                 *sp++ = ins;
12238                                 ip += 6;
12239                                 inline_costs += 10 * num_calls++;
12240                                 /* Can't embed random pointers into AOT code */
12241                                 DISABLE_AOT (cfg);
12242                                 break;
12243                         }
12244                         case CEE_MONO_JIT_ICALL_ADDR: {
12245                                 MonoJitICallInfo *callinfo;
12246                                 gpointer ptr;
12247
12248                                 CHECK_STACK_OVF (1);
12249                                 CHECK_OPSIZE (6);
12250                                 token = read32 (ip + 2);
12251
12252                                 ptr = mono_method_get_wrapper_data (method, token);
12253                                 callinfo = mono_find_jit_icall_by_addr (ptr);
12254                                 g_assert (callinfo);
12255                                 EMIT_NEW_JIT_ICALL_ADDRCONST (cfg, ins, (char*)callinfo->name);
12256                                 *sp++ = ins;
12257                                 ip += 6;
12258                                 inline_costs += 10 * num_calls++;
12259                                 break;
12260                         }
12261                         case CEE_MONO_ICALL_ADDR: {
12262                                 MonoMethod *cmethod;
12263                                 gpointer ptr;
12264
12265                                 CHECK_STACK_OVF (1);
12266                                 CHECK_OPSIZE (6);
12267                                 token = read32 (ip + 2);
12268
12269                                 cmethod = mono_method_get_wrapper_data (method, token);
12270
12271                                 if (cfg->compile_aot) {
12272                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, cmethod);
12273                                 } else {
12274                                         ptr = mono_lookup_internal_call (cmethod);
12275                                         g_assert (ptr);
12276                                         EMIT_NEW_PCONST (cfg, ins, ptr);
12277                                 }
12278                                 *sp++ = ins;
12279                                 ip += 6;
12280                                 break;
12281                         }
12282                         case CEE_MONO_VTADDR: {
12283                                 MonoInst *src_var, *src;
12284
12285                                 CHECK_STACK (1);
12286                                 --sp;
12287
12288                                 // FIXME:
12289                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
12290                                 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
12291                                 *sp++ = src;
12292                                 ip += 2;
12293                                 break;
12294                         }
12295                         case CEE_MONO_NEWOBJ: {
12296                                 MonoInst *iargs [2];
12297
12298                                 CHECK_STACK_OVF (1);
12299                                 CHECK_OPSIZE (6);
12300                                 token = read32 (ip + 2);
12301                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12302                                 mono_class_init (klass);
12303                                 NEW_DOMAINCONST (cfg, iargs [0]);
12304                                 MONO_ADD_INS (cfg->cbb, iargs [0]);
12305                                 NEW_CLASSCONST (cfg, iargs [1], klass);
12306                                 MONO_ADD_INS (cfg->cbb, iargs [1]);
12307                                 *sp++ = mono_emit_jit_icall (cfg, mono_object_new, iargs);
12308                                 ip += 6;
12309                                 inline_costs += 10 * num_calls++;
12310                                 break;
12311                         }
12312                         case CEE_MONO_OBJADDR:
12313                                 CHECK_STACK (1);
12314                                 --sp;
12315                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
12316                                 ins->dreg = alloc_ireg_mp (cfg);
12317                                 ins->sreg1 = sp [0]->dreg;
12318                                 ins->type = STACK_MP;
12319                                 MONO_ADD_INS (cfg->cbb, ins);
12320                                 *sp++ = ins;
12321                                 ip += 2;
12322                                 break;
12323                         case CEE_MONO_LDNATIVEOBJ:
12324                                 /*
12325                                  * Similar to LDOBJ, but instead load the unmanaged 
12326                                  * representation of the vtype to the stack.
12327                                  */
12328                                 CHECK_STACK (1);
12329                                 CHECK_OPSIZE (6);
12330                                 --sp;
12331                                 token = read32 (ip + 2);
12332                                 klass = mono_method_get_wrapper_data (method, token);
12333                                 g_assert (klass->valuetype);
12334                                 mono_class_init (klass);
12335
12336                                 {
12337                                         MonoInst *src, *dest, *temp;
12338
12339                                         src = sp [0];
12340                                         temp = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
12341                                         temp->backend.is_pinvoke = 1;
12342                                         EMIT_NEW_TEMPLOADA (cfg, dest, temp->inst_c0);
12343                                         mini_emit_stobj (cfg, dest, src, klass, TRUE);
12344
12345                                         EMIT_NEW_TEMPLOAD (cfg, dest, temp->inst_c0);
12346                                         dest->type = STACK_VTYPE;
12347                                         dest->klass = klass;
12348
12349                                         *sp ++ = dest;
12350                                         ip += 6;
12351                                 }
12352                                 break;
12353                         case CEE_MONO_RETOBJ: {
12354                                 /*
12355                                  * Same as RET, but return the native representation of a vtype
12356                                  * to the caller.
12357                                  */
12358                                 g_assert (cfg->ret);
12359                                 g_assert (mono_method_signature (method)->pinvoke); 
12360                                 CHECK_STACK (1);
12361                                 --sp;
12362                                 
12363                                 CHECK_OPSIZE (6);
12364                                 token = read32 (ip + 2);    
12365                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12366
12367                                 if (!cfg->vret_addr) {
12368                                         g_assert (cfg->ret_var_is_local);
12369
12370                                         EMIT_NEW_VARLOADA (cfg, ins, cfg->ret, cfg->ret->inst_vtype);
12371                                 } else {
12372                                         EMIT_NEW_RETLOADA (cfg, ins);
12373                                 }
12374                                 mini_emit_stobj (cfg, ins, sp [0], klass, TRUE);
12375                                 
12376                                 if (sp != stack_start)
12377                                         UNVERIFIED;
12378                                 
12379                                 MONO_INST_NEW (cfg, ins, OP_BR);
12380                                 ins->inst_target_bb = end_bblock;
12381                                 MONO_ADD_INS (cfg->cbb, ins);
12382                                 link_bblock (cfg, cfg->cbb, end_bblock);
12383                                 start_new_bblock = 1;
12384                                 ip += 6;
12385                                 break;
12386                         }
12387                         case CEE_MONO_CISINST:
12388                         case CEE_MONO_CCASTCLASS: {
12389                                 int token;
12390                                 CHECK_STACK (1);
12391                                 --sp;
12392                                 CHECK_OPSIZE (6);
12393                                 token = read32 (ip + 2);
12394                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12395                                 if (ip [1] == CEE_MONO_CISINST)
12396                                         ins = handle_cisinst (cfg, klass, sp [0]);
12397                                 else
12398                                         ins = handle_ccastclass (cfg, klass, sp [0]);
12399                                 *sp++ = ins;
12400                                 ip += 6;
12401                                 break;
12402                         }
12403                         case CEE_MONO_SAVE_LMF:
12404                         case CEE_MONO_RESTORE_LMF:
12405                                 ip += 2;
12406                                 break;
12407                         case CEE_MONO_CLASSCONST:
12408                                 CHECK_STACK_OVF (1);
12409                                 CHECK_OPSIZE (6);
12410                                 token = read32 (ip + 2);
12411                                 EMIT_NEW_CLASSCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
12412                                 *sp++ = ins;
12413                                 ip += 6;
12414                                 inline_costs += 10 * num_calls++;
12415                                 break;
12416                         case CEE_MONO_NOT_TAKEN:
12417                                 cfg->cbb->out_of_line = TRUE;
12418                                 ip += 2;
12419                                 break;
12420                         case CEE_MONO_TLS: {
12421                                 int key;
12422
12423                                 CHECK_STACK_OVF (1);
12424                                 CHECK_OPSIZE (6);
12425                                 key = (gint32)read32 (ip + 2);
12426                                 g_assert (key < TLS_KEY_NUM);
12427
12428                                 ins = mono_create_tls_get (cfg, key);
12429                                 if (!ins) {
12430                                         if (cfg->compile_aot) {
12431                                                 DISABLE_AOT (cfg);
12432                                                 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
12433                                                 ins->dreg = alloc_preg (cfg);
12434                                                 ins->type = STACK_PTR;
12435                                         } else {
12436                                                 g_assert_not_reached ();
12437                                         }
12438                                 }
12439                                 ins->type = STACK_PTR;
12440                                 MONO_ADD_INS (cfg->cbb, ins);
12441                                 *sp++ = ins;
12442                                 ip += 6;
12443                                 break;
12444                         }
12445                         case CEE_MONO_DYN_CALL: {
12446                                 MonoCallInst *call;
12447
12448                                 /* It would be easier to call a trampoline, but that would put an
12449                                  * extra frame on the stack, confusing exception handling. So
12450                                  * implement it inline using an opcode for now.
12451                                  */
12452
12453                                 if (!cfg->dyn_call_var) {
12454                                         cfg->dyn_call_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12455                                         /* prevent it from being register allocated */
12456                                         cfg->dyn_call_var->flags |= MONO_INST_VOLATILE;
12457                                 }
12458
12459                                 /* Has to use a call inst since it local regalloc expects it */
12460                                 MONO_INST_NEW_CALL (cfg, call, OP_DYN_CALL);
12461                                 ins = (MonoInst*)call;
12462                                 sp -= 2;
12463                                 ins->sreg1 = sp [0]->dreg;
12464                                 ins->sreg2 = sp [1]->dreg;
12465                                 MONO_ADD_INS (cfg->cbb, ins);
12466
12467                                 cfg->param_area = MAX (cfg->param_area, cfg->backend->dyn_call_param_area);
12468
12469                                 ip += 2;
12470                                 inline_costs += 10 * num_calls++;
12471
12472                                 break;
12473                         }
12474                         case CEE_MONO_MEMORY_BARRIER: {
12475                                 CHECK_OPSIZE (6);
12476                                 emit_memory_barrier (cfg, (int)read32 (ip + 2));
12477                                 ip += 6;
12478                                 break;
12479                         }
12480                         case CEE_MONO_JIT_ATTACH: {
12481                                 MonoInst *args [16], *domain_ins;
12482                                 MonoInst *ad_ins, *jit_tls_ins;
12483                                 MonoBasicBlock *next_bb = NULL, *call_bb = NULL;
12484
12485                                 cfg->orig_domain_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12486
12487                                 EMIT_NEW_PCONST (cfg, ins, NULL);
12488                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12489
12490                                 ad_ins = mono_get_domain_intrinsic (cfg);
12491                                 jit_tls_ins = mono_get_jit_tls_intrinsic (cfg);
12492
12493                                 if (cfg->backend->have_tls_get && ad_ins && jit_tls_ins) {
12494                                         NEW_BBLOCK (cfg, next_bb);
12495                                         NEW_BBLOCK (cfg, call_bb);
12496
12497                                         if (cfg->compile_aot) {
12498                                                 /* AOT code is only used in the root domain */
12499                                                 EMIT_NEW_PCONST (cfg, domain_ins, NULL);
12500                                         } else {
12501                                                 EMIT_NEW_PCONST (cfg, domain_ins, cfg->domain);
12502                                         }
12503                                         MONO_ADD_INS (cfg->cbb, ad_ins);
12504                                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, ad_ins->dreg, domain_ins->dreg);
12505                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, call_bb);
12506
12507                                         MONO_ADD_INS (cfg->cbb, jit_tls_ins);
12508                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, jit_tls_ins->dreg, 0);
12509                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, call_bb);
12510
12511                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, next_bb);
12512                                         MONO_START_BB (cfg, call_bb);
12513                                 }
12514
12515                                 if (cfg->compile_aot) {
12516                                         /* AOT code is only used in the root domain */
12517                                         EMIT_NEW_PCONST (cfg, args [0], NULL);
12518                                 } else {
12519                                         EMIT_NEW_PCONST (cfg, args [0], cfg->domain);
12520                                 }
12521                                 ins = mono_emit_jit_icall (cfg, mono_jit_thread_attach, args);
12522                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12523
12524                                 if (next_bb)
12525                                         MONO_START_BB (cfg, next_bb);
12526                                 ip += 2;
12527                                 break;
12528                         }
12529                         case CEE_MONO_JIT_DETACH: {
12530                                 MonoInst *args [16];
12531
12532                                 /* Restore the original domain */
12533                                 dreg = alloc_ireg (cfg);
12534                                 EMIT_NEW_UNALU (cfg, args [0], OP_MOVE, dreg, cfg->orig_domain_var->dreg);
12535                                 mono_emit_jit_icall (cfg, mono_jit_set_domain, args);
12536                                 ip += 2;
12537                                 break;
12538                         }
12539                         default:
12540                                 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
12541                                 break;
12542                         }
12543                         break;
12544                 }
12545
12546                 case CEE_PREFIX1: {
12547                         CHECK_OPSIZE (2);
12548                         switch (ip [1]) {
12549                         case CEE_ARGLIST: {
12550                                 /* somewhat similar to LDTOKEN */
12551                                 MonoInst *addr, *vtvar;
12552                                 CHECK_STACK_OVF (1);
12553                                 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL); 
12554
12555                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
12556                                 EMIT_NEW_UNALU (cfg, ins, OP_ARGLIST, -1, addr->dreg);
12557
12558                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
12559                                 ins->type = STACK_VTYPE;
12560                                 ins->klass = mono_defaults.argumenthandle_class;
12561                                 *sp++ = ins;
12562                                 ip += 2;
12563                                 break;
12564                         }
12565                         case CEE_CEQ:
12566                         case CEE_CGT:
12567                         case CEE_CGT_UN:
12568                         case CEE_CLT:
12569                         case CEE_CLT_UN: {
12570                                 MonoInst *cmp, *arg1, *arg2;
12571
12572                                 CHECK_STACK (2);
12573                                 sp -= 2;
12574                                 arg1 = sp [0];
12575                                 arg2 = sp [1];
12576
12577                                 /*
12578                                  * The following transforms:
12579                                  *    CEE_CEQ    into OP_CEQ
12580                                  *    CEE_CGT    into OP_CGT
12581                                  *    CEE_CGT_UN into OP_CGT_UN
12582                                  *    CEE_CLT    into OP_CLT
12583                                  *    CEE_CLT_UN into OP_CLT_UN
12584                                  */
12585                                 MONO_INST_NEW (cfg, cmp, (OP_CEQ - CEE_CEQ) + ip [1]);
12586
12587                                 MONO_INST_NEW (cfg, ins, cmp->opcode);
12588                                 cmp->sreg1 = arg1->dreg;
12589                                 cmp->sreg2 = arg2->dreg;
12590                                 type_from_op (cfg, cmp, arg1, arg2);
12591                                 CHECK_TYPE (cmp);
12592                                 add_widen_op (cfg, cmp, &arg1, &arg2);
12593                                 if ((arg1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((arg1->type == STACK_PTR) || (arg1->type == STACK_OBJ) || (arg1->type == STACK_MP))))
12594                                         cmp->opcode = OP_LCOMPARE;
12595                                 else if (arg1->type == STACK_R4)
12596                                         cmp->opcode = OP_RCOMPARE;
12597                                 else if (arg1->type == STACK_R8)
12598                                         cmp->opcode = OP_FCOMPARE;
12599                                 else
12600                                         cmp->opcode = OP_ICOMPARE;
12601                                 MONO_ADD_INS (cfg->cbb, cmp);
12602                                 ins->type = STACK_I4;
12603                                 ins->dreg = alloc_dreg (cfg, ins->type);
12604                                 type_from_op (cfg, ins, arg1, arg2);
12605
12606                                 if (cmp->opcode == OP_FCOMPARE || cmp->opcode == OP_RCOMPARE) {
12607                                         /*
12608                                          * The backends expect the fceq opcodes to do the
12609                                          * comparison too.
12610                                          */
12611                                         ins->sreg1 = cmp->sreg1;
12612                                         ins->sreg2 = cmp->sreg2;
12613                                         NULLIFY_INS (cmp);
12614                                 }
12615                                 MONO_ADD_INS (cfg->cbb, ins);
12616                                 *sp++ = ins;
12617                                 ip += 2;
12618                                 break;
12619                         }
12620                         case CEE_LDFTN: {
12621                                 MonoInst *argconst;
12622                                 MonoMethod *cil_method;
12623
12624                                 CHECK_STACK_OVF (1);
12625                                 CHECK_OPSIZE (6);
12626                                 n = read32 (ip + 2);
12627                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
12628                                 if (!cmethod || mono_loader_get_last_error ())
12629                                         LOAD_ERROR;
12630                                 mono_class_init (cmethod->klass);
12631
12632                                 mono_save_token_info (cfg, image, n, cmethod);
12633
12634                                 context_used = mini_method_check_context_used (cfg, cmethod);
12635
12636                                 cil_method = cmethod;
12637                                 if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
12638                                         METHOD_ACCESS_FAILURE (method, cil_method);
12639
12640                                 if (mono_security_core_clr_enabled ())
12641                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
12642
12643                                 /* 
12644                                  * Optimize the common case of ldftn+delegate creation
12645                                  */
12646                                 if ((sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 6) && (ip [6] == CEE_NEWOBJ)) {
12647                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
12648                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
12649                                                 MonoInst *target_ins, *handle_ins;
12650                                                 MonoMethod *invoke;
12651                                                 int invoke_context_used;
12652
12653                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
12654                                                 if (!invoke || !mono_method_signature (invoke))
12655                                                         LOAD_ERROR;
12656
12657                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
12658
12659                                                 target_ins = sp [-1];
12660
12661                                                 if (mono_security_core_clr_enabled ())
12662                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
12663
12664                                                 if (!(cmethod->flags & METHOD_ATTRIBUTE_STATIC)) {
12665                                                         /*LAME IMPL: We must not add a null check for virtual invoke delegates.*/
12666                                                         if (mono_method_signature (invoke)->param_count == mono_method_signature (cmethod)->param_count) {
12667                                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, target_ins->dreg, 0);
12668                                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "ArgumentException");
12669                                                         }
12670                                                 }
12671
12672                                                 /* FIXME: SGEN support */
12673                                                 if (invoke_context_used == 0) {
12674                                                         ip += 6;
12675                                                         if (cfg->verbose_level > 3)
12676                                                                 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));
12677                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, FALSE))) {
12678                                                                 sp --;
12679                                                                 *sp = handle_ins;
12680                                                                 CHECK_CFG_EXCEPTION;
12681                                                                 ip += 5;
12682                                                                 sp ++;
12683                                                                 break;
12684                                                         }
12685                                                         ip -= 6;
12686                                                 }
12687                                         }
12688                                 }
12689
12690                                 argconst = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD);
12691                                 ins = mono_emit_jit_icall (cfg, mono_ldftn, &argconst);
12692                                 *sp++ = ins;
12693                                 
12694                                 ip += 6;
12695                                 inline_costs += 10 * num_calls++;
12696                                 break;
12697                         }
12698                         case CEE_LDVIRTFTN: {
12699                                 MonoInst *args [2];
12700
12701                                 CHECK_STACK (1);
12702                                 CHECK_OPSIZE (6);
12703                                 n = read32 (ip + 2);
12704                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
12705                                 if (!cmethod || mono_loader_get_last_error ())
12706                                         LOAD_ERROR;
12707                                 mono_class_init (cmethod->klass);
12708  
12709                                 context_used = mini_method_check_context_used (cfg, cmethod);
12710
12711                                 if (mono_security_core_clr_enabled ())
12712                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
12713
12714                                 /*
12715                                  * Optimize the common case of ldvirtftn+delegate creation
12716                                  */
12717                                 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)) {
12718                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
12719                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
12720                                                 MonoInst *target_ins, *handle_ins;
12721                                                 MonoMethod *invoke;
12722                                                 int invoke_context_used;
12723                                                 gboolean is_virtual = cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL;
12724
12725                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
12726                                                 if (!invoke || !mono_method_signature (invoke))
12727                                                         LOAD_ERROR;
12728
12729                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
12730
12731                                                 target_ins = sp [-1];
12732
12733                                                 if (mono_security_core_clr_enabled ())
12734                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
12735
12736                                                 /* FIXME: SGEN support */
12737                                                 if (invoke_context_used == 0 || cfg->llvm_only) {
12738                                                         ip += 6;
12739                                                         if (cfg->verbose_level > 3)
12740                                                                 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));
12741                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, is_virtual))) {
12742                                                                 sp -= 2;
12743                                                                 *sp = handle_ins;
12744                                                                 CHECK_CFG_EXCEPTION;
12745                                                                 ip += 5;
12746                                                                 sp ++;
12747                                                                 break;
12748                                                         }
12749                                                         ip -= 6;
12750                                                 }
12751                                         }
12752                                 }
12753
12754                                 --sp;
12755                                 args [0] = *sp;
12756
12757                                 args [1] = emit_get_rgctx_method (cfg, context_used,
12758                                                                                                   cmethod, MONO_RGCTX_INFO_METHOD);
12759
12760                                 if (context_used)
12761                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn_gshared, args);
12762                                 else
12763                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn, args);
12764
12765                                 ip += 6;
12766                                 inline_costs += 10 * num_calls++;
12767                                 break;
12768                         }
12769                         case CEE_LDARG:
12770                                 CHECK_STACK_OVF (1);
12771                                 CHECK_OPSIZE (4);
12772                                 n = read16 (ip + 2);
12773                                 CHECK_ARG (n);
12774                                 EMIT_NEW_ARGLOAD (cfg, ins, n);
12775                                 *sp++ = ins;
12776                                 ip += 4;
12777                                 break;
12778                         case CEE_LDARGA:
12779                                 CHECK_STACK_OVF (1);
12780                                 CHECK_OPSIZE (4);
12781                                 n = read16 (ip + 2);
12782                                 CHECK_ARG (n);
12783                                 NEW_ARGLOADA (cfg, ins, n);
12784                                 MONO_ADD_INS (cfg->cbb, ins);
12785                                 *sp++ = ins;
12786                                 ip += 4;
12787                                 break;
12788                         case CEE_STARG:
12789                                 CHECK_STACK (1);
12790                                 --sp;
12791                                 CHECK_OPSIZE (4);
12792                                 n = read16 (ip + 2);
12793                                 CHECK_ARG (n);
12794                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
12795                                         UNVERIFIED;
12796                                 EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
12797                                 ip += 4;
12798                                 break;
12799                         case CEE_LDLOC:
12800                                 CHECK_STACK_OVF (1);
12801                                 CHECK_OPSIZE (4);
12802                                 n = read16 (ip + 2);
12803                                 CHECK_LOCAL (n);
12804                                 EMIT_NEW_LOCLOAD (cfg, ins, n);
12805                                 *sp++ = ins;
12806                                 ip += 4;
12807                                 break;
12808                         case CEE_LDLOCA: {
12809                                 unsigned char *tmp_ip;
12810                                 CHECK_STACK_OVF (1);
12811                                 CHECK_OPSIZE (4);
12812                                 n = read16 (ip + 2);
12813                                 CHECK_LOCAL (n);
12814
12815                                 if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 2))) {
12816                                         ip = tmp_ip;
12817                                         inline_costs += 1;
12818                                         break;
12819                                 }                       
12820                                 
12821                                 EMIT_NEW_LOCLOADA (cfg, ins, n);
12822                                 *sp++ = ins;
12823                                 ip += 4;
12824                                 break;
12825                         }
12826                         case CEE_STLOC:
12827                                 CHECK_STACK (1);
12828                                 --sp;
12829                                 CHECK_OPSIZE (4);
12830                                 n = read16 (ip + 2);
12831                                 CHECK_LOCAL (n);
12832                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
12833                                         UNVERIFIED;
12834                                 emit_stloc_ir (cfg, sp, header, n);
12835                                 ip += 4;
12836                                 inline_costs += 1;
12837                                 break;
12838                         case CEE_LOCALLOC:
12839                                 CHECK_STACK (1);
12840                                 --sp;
12841                                 if (sp != stack_start) 
12842                                         UNVERIFIED;
12843                                 if (cfg->method != method) 
12844                                         /* 
12845                                          * Inlining this into a loop in a parent could lead to 
12846                                          * stack overflows which is different behavior than the
12847                                          * non-inlined case, thus disable inlining in this case.
12848                                          */
12849                                         INLINE_FAILURE("localloc");
12850
12851                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
12852                                 ins->dreg = alloc_preg (cfg);
12853                                 ins->sreg1 = sp [0]->dreg;
12854                                 ins->type = STACK_PTR;
12855                                 MONO_ADD_INS (cfg->cbb, ins);
12856
12857                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12858                                 if (init_locals)
12859                                         ins->flags |= MONO_INST_INIT;
12860
12861                                 *sp++ = ins;
12862                                 ip += 2;
12863                                 break;
12864                         case CEE_ENDFILTER: {
12865                                 MonoExceptionClause *clause, *nearest;
12866                                 int cc;
12867
12868                                 CHECK_STACK (1);
12869                                 --sp;
12870                                 if ((sp != stack_start) || (sp [0]->type != STACK_I4)) 
12871                                         UNVERIFIED;
12872                                 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
12873                                 ins->sreg1 = (*sp)->dreg;
12874                                 MONO_ADD_INS (cfg->cbb, ins);
12875                                 start_new_bblock = 1;
12876                                 ip += 2;
12877
12878                                 nearest = NULL;
12879                                 for (cc = 0; cc < header->num_clauses; ++cc) {
12880                                         clause = &header->clauses [cc];
12881                                         if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
12882                                                 ((ip - header->code) > clause->data.filter_offset && (ip - header->code) <= clause->handler_offset) &&
12883                                             (!nearest || (clause->data.filter_offset < nearest->data.filter_offset)))
12884                                                 nearest = clause;
12885                                 }
12886                                 g_assert (nearest);
12887                                 if ((ip - header->code) != nearest->handler_offset)
12888                                         UNVERIFIED;
12889
12890                                 break;
12891                         }
12892                         case CEE_UNALIGNED_:
12893                                 ins_flag |= MONO_INST_UNALIGNED;
12894                                 /* FIXME: record alignment? we can assume 1 for now */
12895                                 CHECK_OPSIZE (3);
12896                                 ip += 3;
12897                                 break;
12898                         case CEE_VOLATILE_:
12899                                 ins_flag |= MONO_INST_VOLATILE;
12900                                 ip += 2;
12901                                 break;
12902                         case CEE_TAIL_:
12903                                 ins_flag   |= MONO_INST_TAILCALL;
12904                                 cfg->flags |= MONO_CFG_HAS_TAIL;
12905                                 /* Can't inline tail calls at this time */
12906                                 inline_costs += 100000;
12907                                 ip += 2;
12908                                 break;
12909                         case CEE_INITOBJ:
12910                                 CHECK_STACK (1);
12911                                 --sp;
12912                                 CHECK_OPSIZE (6);
12913                                 token = read32 (ip + 2);
12914                                 klass = mini_get_class (method, token, generic_context);
12915                                 CHECK_TYPELOAD (klass);
12916                                 if (generic_class_is_reference_type (cfg, klass))
12917                                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, sp [0]->dreg, 0, 0);
12918                                 else
12919                                         mini_emit_initobj (cfg, *sp, NULL, klass);
12920                                 ip += 6;
12921                                 inline_costs += 1;
12922                                 break;
12923                         case CEE_CONSTRAINED_:
12924                                 CHECK_OPSIZE (6);
12925                                 token = read32 (ip + 2);
12926                                 constrained_class = mini_get_class (method, token, generic_context);
12927                                 CHECK_TYPELOAD (constrained_class);
12928                                 ip += 6;
12929                                 break;
12930                         case CEE_CPBLK:
12931                         case CEE_INITBLK: {
12932                                 MonoInst *iargs [3];
12933                                 CHECK_STACK (3);
12934                                 sp -= 3;
12935
12936                                 /* Skip optimized paths for volatile operations. */
12937                                 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)) {
12938                                         mini_emit_memcpy (cfg, sp [0]->dreg, 0, sp [1]->dreg, 0, sp [2]->inst_c0, 0);
12939                                 } 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)) {
12940                                         /* emit_memset only works when val == 0 */
12941                                         mini_emit_memset (cfg, sp [0]->dreg, 0, sp [2]->inst_c0, sp [1]->inst_c0, 0);
12942                                 } else {
12943                                         MonoInst *call;
12944                                         iargs [0] = sp [0];
12945                                         iargs [1] = sp [1];
12946                                         iargs [2] = sp [2];
12947                                         if (ip [1] == CEE_CPBLK) {
12948                                                 /*
12949                                                  * FIXME: It's unclear whether we should be emitting both the acquire
12950                                                  * and release barriers for cpblk. It is technically both a load and
12951                                                  * store operation, so it seems like that's the sensible thing to do.
12952                                                  *
12953                                                  * FIXME: We emit full barriers on both sides of the operation for
12954                                                  * simplicity. We should have a separate atomic memcpy method instead.
12955                                                  */
12956                                                 MonoMethod *memcpy_method = get_memcpy_method ();
12957
12958                                                 if (ins_flag & MONO_INST_VOLATILE)
12959                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
12960
12961                                                 call = mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
12962                                                 call->flags |= ins_flag;
12963
12964                                                 if (ins_flag & MONO_INST_VOLATILE)
12965                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
12966                                         } else {
12967                                                 MonoMethod *memset_method = get_memset_method ();
12968                                                 if (ins_flag & MONO_INST_VOLATILE) {
12969                                                         /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
12970                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
12971                                                 }
12972                                                 call = mono_emit_method_call (cfg, memset_method, iargs, NULL);
12973                                                 call->flags |= ins_flag;
12974                                         }
12975                                 }
12976                                 ip += 2;
12977                                 ins_flag = 0;
12978                                 inline_costs += 1;
12979                                 break;
12980                         }
12981                         case CEE_NO_:
12982                                 CHECK_OPSIZE (3);
12983                                 if (ip [2] & 0x1)
12984                                         ins_flag |= MONO_INST_NOTYPECHECK;
12985                                 if (ip [2] & 0x2)
12986                                         ins_flag |= MONO_INST_NORANGECHECK;
12987                                 /* we ignore the no-nullcheck for now since we
12988                                  * really do it explicitly only when doing callvirt->call
12989                                  */
12990                                 ip += 3;
12991                                 break;
12992                         case CEE_RETHROW: {
12993                                 MonoInst *load;
12994                                 int handler_offset = -1;
12995
12996                                 for (i = 0; i < header->num_clauses; ++i) {
12997                                         MonoExceptionClause *clause = &header->clauses [i];
12998                                         if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
12999                                                 handler_offset = clause->handler_offset;
13000                                                 break;
13001                                         }
13002                                 }
13003
13004                                 cfg->cbb->flags |= BB_EXCEPTION_UNSAFE;
13005
13006                                 if (handler_offset == -1)
13007                                         UNVERIFIED;
13008
13009                                 EMIT_NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
13010                                 MONO_INST_NEW (cfg, ins, OP_RETHROW);
13011                                 ins->sreg1 = load->dreg;
13012                                 MONO_ADD_INS (cfg->cbb, ins);
13013
13014                                 MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
13015                                 MONO_ADD_INS (cfg->cbb, ins);
13016
13017                                 sp = stack_start;
13018                                 link_bblock (cfg, cfg->cbb, end_bblock);
13019                                 start_new_bblock = 1;
13020                                 ip += 2;
13021                                 break;
13022                         }
13023                         case CEE_SIZEOF: {
13024                                 guint32 val;
13025                                 int ialign;
13026
13027                                 CHECK_STACK_OVF (1);
13028                                 CHECK_OPSIZE (6);
13029                                 token = read32 (ip + 2);
13030                                 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC && !image_is_dynamic (method->klass->image) && !generic_context) {
13031                                         MonoType *type = mono_type_create_from_typespec_checked (image, token, &cfg->error);
13032                                         CHECK_CFG_ERROR;
13033
13034                                         val = mono_type_size (type, &ialign);
13035                                 } else {
13036                                         MonoClass *klass = mini_get_class (method, token, generic_context);
13037                                         CHECK_TYPELOAD (klass);
13038
13039                                         val = mono_type_size (&klass->byval_arg, &ialign);
13040
13041                                         if (mini_is_gsharedvt_klass (klass))
13042                                                 GSHAREDVT_FAILURE (*ip);
13043                                 }
13044                                 EMIT_NEW_ICONST (cfg, ins, val);
13045                                 *sp++= ins;
13046                                 ip += 6;
13047                                 break;
13048                         }
13049                         case CEE_REFANYTYPE: {
13050                                 MonoInst *src_var, *src;
13051
13052                                 GSHAREDVT_FAILURE (*ip);
13053
13054                                 CHECK_STACK (1);
13055                                 --sp;
13056
13057                                 // FIXME:
13058                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
13059                                 if (!src_var)
13060                                         src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
13061                                 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
13062                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &mono_defaults.typehandle_class->byval_arg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type));
13063                                 *sp++ = ins;
13064                                 ip += 2;
13065                                 break;
13066                         }
13067                         case CEE_READONLY_:
13068                                 readonly = TRUE;
13069                                 ip += 2;
13070                                 break;
13071
13072                         case CEE_UNUSED56:
13073                         case CEE_UNUSED57:
13074                         case CEE_UNUSED70:
13075                         case CEE_UNUSED:
13076                         case CEE_UNUSED99:
13077                                 UNVERIFIED;
13078                                 
13079                         default:
13080                                 g_warning ("opcode 0xfe 0x%02x not handled", ip [1]);
13081                                 UNVERIFIED;
13082                         }
13083                         break;
13084                 }
13085                 case CEE_UNUSED58:
13086                 case CEE_UNUSED1:
13087                         UNVERIFIED;
13088
13089                 default:
13090                         g_warning ("opcode 0x%02x not handled", *ip);
13091                         UNVERIFIED;
13092                 }
13093         }
13094         if (start_new_bblock != 1)
13095                 UNVERIFIED;
13096
13097         cfg->cbb->cil_length = ip - cfg->cbb->cil_code;
13098         if (cfg->cbb->next_bb) {
13099                 /* This could already be set because of inlining, #693905 */
13100                 MonoBasicBlock *bb = cfg->cbb;
13101
13102                 while (bb->next_bb)
13103                         bb = bb->next_bb;
13104                 bb->next_bb = end_bblock;
13105         } else {
13106                 cfg->cbb->next_bb = end_bblock;
13107         }
13108
13109         if (cfg->method == method && cfg->domainvar) {
13110                 MonoInst *store;
13111                 MonoInst *get_domain;
13112
13113                 cfg->cbb = init_localsbb;
13114
13115                 if ((get_domain = mono_get_domain_intrinsic (cfg))) {
13116                         MONO_ADD_INS (cfg->cbb, get_domain);
13117                 } else {
13118                         get_domain = mono_emit_jit_icall (cfg, mono_domain_get, NULL);
13119                 }
13120                 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, get_domain);
13121                 MONO_ADD_INS (cfg->cbb, store);
13122         }
13123
13124 #if defined(TARGET_POWERPC) || defined(TARGET_X86)
13125         if (cfg->compile_aot)
13126                 /* FIXME: The plt slots require a GOT var even if the method doesn't use it */
13127                 mono_get_got_var (cfg);
13128 #endif
13129
13130         if (cfg->method == method && cfg->got_var)
13131                 mono_emit_load_got_addr (cfg);
13132
13133         if (init_localsbb) {
13134                 cfg->cbb = init_localsbb;
13135                 cfg->ip = NULL;
13136                 for (i = 0; i < header->num_locals; ++i) {
13137                         emit_init_local (cfg, i, header->locals [i], init_locals);
13138                 }
13139         }
13140
13141         if (cfg->init_ref_vars && cfg->method == method) {
13142                 /* Emit initialization for ref vars */
13143                 // FIXME: Avoid duplication initialization for IL locals.
13144                 for (i = 0; i < cfg->num_varinfo; ++i) {
13145                         MonoInst *ins = cfg->varinfo [i];
13146
13147                         if (ins->opcode == OP_LOCAL && ins->type == STACK_OBJ)
13148                                 MONO_EMIT_NEW_PCONST (cfg, ins->dreg, NULL);
13149                 }
13150         }
13151
13152         if (cfg->lmf_var && cfg->method == method && !cfg->llvm_only) {
13153                 cfg->cbb = init_localsbb;
13154                 emit_push_lmf (cfg);
13155         }
13156
13157         cfg->cbb = init_localsbb;
13158         emit_instrumentation_call (cfg, mono_profiler_method_enter);
13159
13160         if (seq_points) {
13161                 MonoBasicBlock *bb;
13162
13163                 /*
13164                  * Make seq points at backward branch targets interruptable.
13165                  */
13166                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
13167                         if (bb->code && bb->in_count > 1 && bb->code->opcode == OP_SEQ_POINT)
13168                                 bb->code->flags |= MONO_INST_SINGLE_STEP_LOC;
13169         }
13170
13171         /* Add a sequence point for method entry/exit events */
13172         if (seq_points && cfg->gen_sdb_seq_points) {
13173                 NEW_SEQ_POINT (cfg, ins, METHOD_ENTRY_IL_OFFSET, FALSE);
13174                 MONO_ADD_INS (init_localsbb, ins);
13175                 NEW_SEQ_POINT (cfg, ins, METHOD_EXIT_IL_OFFSET, FALSE);
13176                 MONO_ADD_INS (cfg->bb_exit, ins);
13177         }
13178
13179         /*
13180          * Add seq points for IL offsets which have line number info, but wasn't generated a seq point during JITting because
13181          * the code they refer to was dead (#11880).
13182          */
13183         if (sym_seq_points) {
13184                 for (i = 0; i < header->code_size; ++i) {
13185                         if (mono_bitset_test_fast (seq_point_locs, i) && !mono_bitset_test_fast (seq_point_set_locs, i)) {
13186                                 MonoInst *ins;
13187
13188                                 NEW_SEQ_POINT (cfg, ins, i, FALSE);
13189                                 mono_add_seq_point (cfg, NULL, ins, SEQ_POINT_NATIVE_OFFSET_DEAD_CODE);
13190                         }
13191                 }
13192         }
13193
13194         cfg->ip = NULL;
13195
13196         if (cfg->method == method) {
13197                 MonoBasicBlock *bb;
13198                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13199                         bb->region = mono_find_block_region (cfg, bb->real_offset);
13200                         if (cfg->spvars)
13201                                 mono_create_spvar_for_region (cfg, bb->region);
13202                         if (cfg->verbose_level > 2)
13203                                 printf ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
13204                 }
13205         }
13206
13207         if (inline_costs < 0) {
13208                 char *mname;
13209
13210                 /* Method is too large */
13211                 mname = mono_method_full_name (method, TRUE);
13212                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
13213                 cfg->exception_message = g_strdup_printf ("Method %s is too complex.", mname);
13214                 g_free (mname);
13215         }
13216
13217         if ((cfg->verbose_level > 2) && (cfg->method == method)) 
13218                 mono_print_code (cfg, "AFTER METHOD-TO-IR");
13219
13220         goto cleanup;
13221
13222 mono_error_exit:
13223         g_assert (!mono_error_ok (&cfg->error));
13224         goto cleanup;
13225  
13226  exception_exit:
13227         g_assert (cfg->exception_type != MONO_EXCEPTION_NONE);
13228         goto cleanup;
13229
13230  unverified:
13231         set_exception_type_from_invalid_il (cfg, method, ip);
13232         goto cleanup;
13233
13234  cleanup:
13235         g_slist_free (class_inits);
13236         mono_basic_block_free (original_bb);
13237         cfg->dont_inline = g_list_remove (cfg->dont_inline, method);
13238         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
13239         if (cfg->exception_type)
13240                 return -1;
13241         else
13242                 return inline_costs;
13243 }
13244
13245 static int
13246 store_membase_reg_to_store_membase_imm (int opcode)
13247 {
13248         switch (opcode) {
13249         case OP_STORE_MEMBASE_REG:
13250                 return OP_STORE_MEMBASE_IMM;
13251         case OP_STOREI1_MEMBASE_REG:
13252                 return OP_STOREI1_MEMBASE_IMM;
13253         case OP_STOREI2_MEMBASE_REG:
13254                 return OP_STOREI2_MEMBASE_IMM;
13255         case OP_STOREI4_MEMBASE_REG:
13256                 return OP_STOREI4_MEMBASE_IMM;
13257         case OP_STOREI8_MEMBASE_REG:
13258                 return OP_STOREI8_MEMBASE_IMM;
13259         default:
13260                 g_assert_not_reached ();
13261         }
13262
13263         return -1;
13264 }               
13265
13266 int
13267 mono_op_to_op_imm (int opcode)
13268 {
13269         switch (opcode) {
13270         case OP_IADD:
13271                 return OP_IADD_IMM;
13272         case OP_ISUB:
13273                 return OP_ISUB_IMM;
13274         case OP_IDIV:
13275                 return OP_IDIV_IMM;
13276         case OP_IDIV_UN:
13277                 return OP_IDIV_UN_IMM;
13278         case OP_IREM:
13279                 return OP_IREM_IMM;
13280         case OP_IREM_UN:
13281                 return OP_IREM_UN_IMM;
13282         case OP_IMUL:
13283                 return OP_IMUL_IMM;
13284         case OP_IAND:
13285                 return OP_IAND_IMM;
13286         case OP_IOR:
13287                 return OP_IOR_IMM;
13288         case OP_IXOR:
13289                 return OP_IXOR_IMM;
13290         case OP_ISHL:
13291                 return OP_ISHL_IMM;
13292         case OP_ISHR:
13293                 return OP_ISHR_IMM;
13294         case OP_ISHR_UN:
13295                 return OP_ISHR_UN_IMM;
13296
13297         case OP_LADD:
13298                 return OP_LADD_IMM;
13299         case OP_LSUB:
13300                 return OP_LSUB_IMM;
13301         case OP_LAND:
13302                 return OP_LAND_IMM;
13303         case OP_LOR:
13304                 return OP_LOR_IMM;
13305         case OP_LXOR:
13306                 return OP_LXOR_IMM;
13307         case OP_LSHL:
13308                 return OP_LSHL_IMM;
13309         case OP_LSHR:
13310                 return OP_LSHR_IMM;
13311         case OP_LSHR_UN:
13312                 return OP_LSHR_UN_IMM;
13313 #if SIZEOF_REGISTER == 8
13314         case OP_LREM:
13315                 return OP_LREM_IMM;
13316 #endif
13317
13318         case OP_COMPARE:
13319                 return OP_COMPARE_IMM;
13320         case OP_ICOMPARE:
13321                 return OP_ICOMPARE_IMM;
13322         case OP_LCOMPARE:
13323                 return OP_LCOMPARE_IMM;
13324
13325         case OP_STORE_MEMBASE_REG:
13326                 return OP_STORE_MEMBASE_IMM;
13327         case OP_STOREI1_MEMBASE_REG:
13328                 return OP_STOREI1_MEMBASE_IMM;
13329         case OP_STOREI2_MEMBASE_REG:
13330                 return OP_STOREI2_MEMBASE_IMM;
13331         case OP_STOREI4_MEMBASE_REG:
13332                 return OP_STOREI4_MEMBASE_IMM;
13333
13334 #if defined(TARGET_X86) || defined (TARGET_AMD64)
13335         case OP_X86_PUSH:
13336                 return OP_X86_PUSH_IMM;
13337         case OP_X86_COMPARE_MEMBASE_REG:
13338                 return OP_X86_COMPARE_MEMBASE_IMM;
13339 #endif
13340 #if defined(TARGET_AMD64)
13341         case OP_AMD64_ICOMPARE_MEMBASE_REG:
13342                 return OP_AMD64_ICOMPARE_MEMBASE_IMM;
13343 #endif
13344         case OP_VOIDCALL_REG:
13345                 return OP_VOIDCALL;
13346         case OP_CALL_REG:
13347                 return OP_CALL;
13348         case OP_LCALL_REG:
13349                 return OP_LCALL;
13350         case OP_FCALL_REG:
13351                 return OP_FCALL;
13352         case OP_LOCALLOC:
13353                 return OP_LOCALLOC_IMM;
13354         }
13355
13356         return -1;
13357 }
13358
13359 static int
13360 ldind_to_load_membase (int opcode)
13361 {
13362         switch (opcode) {
13363         case CEE_LDIND_I1:
13364                 return OP_LOADI1_MEMBASE;
13365         case CEE_LDIND_U1:
13366                 return OP_LOADU1_MEMBASE;
13367         case CEE_LDIND_I2:
13368                 return OP_LOADI2_MEMBASE;
13369         case CEE_LDIND_U2:
13370                 return OP_LOADU2_MEMBASE;
13371         case CEE_LDIND_I4:
13372                 return OP_LOADI4_MEMBASE;
13373         case CEE_LDIND_U4:
13374                 return OP_LOADU4_MEMBASE;
13375         case CEE_LDIND_I:
13376                 return OP_LOAD_MEMBASE;
13377         case CEE_LDIND_REF:
13378                 return OP_LOAD_MEMBASE;
13379         case CEE_LDIND_I8:
13380                 return OP_LOADI8_MEMBASE;
13381         case CEE_LDIND_R4:
13382                 return OP_LOADR4_MEMBASE;
13383         case CEE_LDIND_R8:
13384                 return OP_LOADR8_MEMBASE;
13385         default:
13386                 g_assert_not_reached ();
13387         }
13388
13389         return -1;
13390 }
13391
13392 static int
13393 stind_to_store_membase (int opcode)
13394 {
13395         switch (opcode) {
13396         case CEE_STIND_I1:
13397                 return OP_STOREI1_MEMBASE_REG;
13398         case CEE_STIND_I2:
13399                 return OP_STOREI2_MEMBASE_REG;
13400         case CEE_STIND_I4:
13401                 return OP_STOREI4_MEMBASE_REG;
13402         case CEE_STIND_I:
13403         case CEE_STIND_REF:
13404                 return OP_STORE_MEMBASE_REG;
13405         case CEE_STIND_I8:
13406                 return OP_STOREI8_MEMBASE_REG;
13407         case CEE_STIND_R4:
13408                 return OP_STORER4_MEMBASE_REG;
13409         case CEE_STIND_R8:
13410                 return OP_STORER8_MEMBASE_REG;
13411         default:
13412                 g_assert_not_reached ();
13413         }
13414
13415         return -1;
13416 }
13417
13418 int
13419 mono_load_membase_to_load_mem (int opcode)
13420 {
13421         // FIXME: Add a MONO_ARCH_HAVE_LOAD_MEM macro
13422 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13423         switch (opcode) {
13424         case OP_LOAD_MEMBASE:
13425                 return OP_LOAD_MEM;
13426         case OP_LOADU1_MEMBASE:
13427                 return OP_LOADU1_MEM;
13428         case OP_LOADU2_MEMBASE:
13429                 return OP_LOADU2_MEM;
13430         case OP_LOADI4_MEMBASE:
13431                 return OP_LOADI4_MEM;
13432         case OP_LOADU4_MEMBASE:
13433                 return OP_LOADU4_MEM;
13434 #if SIZEOF_REGISTER == 8
13435         case OP_LOADI8_MEMBASE:
13436                 return OP_LOADI8_MEM;
13437 #endif
13438         }
13439 #endif
13440
13441         return -1;
13442 }
13443
13444 static inline int
13445 op_to_op_dest_membase (int store_opcode, int opcode)
13446 {
13447 #if defined(TARGET_X86)
13448         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG)))
13449                 return -1;
13450
13451         switch (opcode) {
13452         case OP_IADD:
13453                 return OP_X86_ADD_MEMBASE_REG;
13454         case OP_ISUB:
13455                 return OP_X86_SUB_MEMBASE_REG;
13456         case OP_IAND:
13457                 return OP_X86_AND_MEMBASE_REG;
13458         case OP_IOR:
13459                 return OP_X86_OR_MEMBASE_REG;
13460         case OP_IXOR:
13461                 return OP_X86_XOR_MEMBASE_REG;
13462         case OP_ADD_IMM:
13463         case OP_IADD_IMM:
13464                 return OP_X86_ADD_MEMBASE_IMM;
13465         case OP_SUB_IMM:
13466         case OP_ISUB_IMM:
13467                 return OP_X86_SUB_MEMBASE_IMM;
13468         case OP_AND_IMM:
13469         case OP_IAND_IMM:
13470                 return OP_X86_AND_MEMBASE_IMM;
13471         case OP_OR_IMM:
13472         case OP_IOR_IMM:
13473                 return OP_X86_OR_MEMBASE_IMM;
13474         case OP_XOR_IMM:
13475         case OP_IXOR_IMM:
13476                 return OP_X86_XOR_MEMBASE_IMM;
13477         case OP_MOVE:
13478                 return OP_NOP;
13479         }
13480 #endif
13481
13482 #if defined(TARGET_AMD64)
13483         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG) || (store_opcode == OP_STOREI8_MEMBASE_REG)))
13484                 return -1;
13485
13486         switch (opcode) {
13487         case OP_IADD:
13488                 return OP_X86_ADD_MEMBASE_REG;
13489         case OP_ISUB:
13490                 return OP_X86_SUB_MEMBASE_REG;
13491         case OP_IAND:
13492                 return OP_X86_AND_MEMBASE_REG;
13493         case OP_IOR:
13494                 return OP_X86_OR_MEMBASE_REG;
13495         case OP_IXOR:
13496                 return OP_X86_XOR_MEMBASE_REG;
13497         case OP_IADD_IMM:
13498                 return OP_X86_ADD_MEMBASE_IMM;
13499         case OP_ISUB_IMM:
13500                 return OP_X86_SUB_MEMBASE_IMM;
13501         case OP_IAND_IMM:
13502                 return OP_X86_AND_MEMBASE_IMM;
13503         case OP_IOR_IMM:
13504                 return OP_X86_OR_MEMBASE_IMM;
13505         case OP_IXOR_IMM:
13506                 return OP_X86_XOR_MEMBASE_IMM;
13507         case OP_LADD:
13508                 return OP_AMD64_ADD_MEMBASE_REG;
13509         case OP_LSUB:
13510                 return OP_AMD64_SUB_MEMBASE_REG;
13511         case OP_LAND:
13512                 return OP_AMD64_AND_MEMBASE_REG;
13513         case OP_LOR:
13514                 return OP_AMD64_OR_MEMBASE_REG;
13515         case OP_LXOR:
13516                 return OP_AMD64_XOR_MEMBASE_REG;
13517         case OP_ADD_IMM:
13518         case OP_LADD_IMM:
13519                 return OP_AMD64_ADD_MEMBASE_IMM;
13520         case OP_SUB_IMM:
13521         case OP_LSUB_IMM:
13522                 return OP_AMD64_SUB_MEMBASE_IMM;
13523         case OP_AND_IMM:
13524         case OP_LAND_IMM:
13525                 return OP_AMD64_AND_MEMBASE_IMM;
13526         case OP_OR_IMM:
13527         case OP_LOR_IMM:
13528                 return OP_AMD64_OR_MEMBASE_IMM;
13529         case OP_XOR_IMM:
13530         case OP_LXOR_IMM:
13531                 return OP_AMD64_XOR_MEMBASE_IMM;
13532         case OP_MOVE:
13533                 return OP_NOP;
13534         }
13535 #endif
13536
13537         return -1;
13538 }
13539
13540 static inline int
13541 op_to_op_store_membase (int store_opcode, int opcode)
13542 {
13543 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13544         switch (opcode) {
13545         case OP_ICEQ:
13546                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13547                         return OP_X86_SETEQ_MEMBASE;
13548         case OP_CNE:
13549                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13550                         return OP_X86_SETNE_MEMBASE;
13551         }
13552 #endif
13553
13554         return -1;
13555 }
13556
13557 static inline int
13558 op_to_op_src1_membase (MonoCompile *cfg, int load_opcode, int opcode)
13559 {
13560 #ifdef TARGET_X86
13561         /* FIXME: This has sign extension issues */
13562         /*
13563         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
13564                 return OP_X86_COMPARE_MEMBASE8_IMM;
13565         */
13566
13567         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
13568                 return -1;
13569
13570         switch (opcode) {
13571         case OP_X86_PUSH:
13572                 return OP_X86_PUSH_MEMBASE;
13573         case OP_COMPARE_IMM:
13574         case OP_ICOMPARE_IMM:
13575                 return OP_X86_COMPARE_MEMBASE_IMM;
13576         case OP_COMPARE:
13577         case OP_ICOMPARE:
13578                 return OP_X86_COMPARE_MEMBASE_REG;
13579         }
13580 #endif
13581
13582 #ifdef TARGET_AMD64
13583         /* FIXME: This has sign extension issues */
13584         /*
13585         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
13586                 return OP_X86_COMPARE_MEMBASE8_IMM;
13587         */
13588
13589         switch (opcode) {
13590         case OP_X86_PUSH:
13591                 if ((load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32) || (load_opcode == OP_LOADI8_MEMBASE))
13592                         return OP_X86_PUSH_MEMBASE;
13593                 break;
13594                 /* FIXME: This only works for 32 bit immediates
13595         case OP_COMPARE_IMM:
13596         case OP_LCOMPARE_IMM:
13597                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
13598                         return OP_AMD64_COMPARE_MEMBASE_IMM;
13599                 */
13600         case OP_ICOMPARE_IMM:
13601                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
13602                         return OP_AMD64_ICOMPARE_MEMBASE_IMM;
13603                 break;
13604         case OP_COMPARE:
13605         case OP_LCOMPARE:
13606                 if (cfg->backend->ilp32 && load_opcode == OP_LOAD_MEMBASE)
13607                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
13608                 if ((load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32) || (load_opcode == OP_LOADI8_MEMBASE))
13609                         return OP_AMD64_COMPARE_MEMBASE_REG;
13610                 break;
13611         case OP_ICOMPARE:
13612                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
13613                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
13614                 break;
13615         }
13616 #endif
13617
13618         return -1;
13619 }
13620
13621 static inline int
13622 op_to_op_src2_membase (MonoCompile *cfg, int load_opcode, int opcode)
13623 {
13624 #ifdef TARGET_X86
13625         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
13626                 return -1;
13627         
13628         switch (opcode) {
13629         case OP_COMPARE:
13630         case OP_ICOMPARE:
13631                 return OP_X86_COMPARE_REG_MEMBASE;
13632         case OP_IADD:
13633                 return OP_X86_ADD_REG_MEMBASE;
13634         case OP_ISUB:
13635                 return OP_X86_SUB_REG_MEMBASE;
13636         case OP_IAND:
13637                 return OP_X86_AND_REG_MEMBASE;
13638         case OP_IOR:
13639                 return OP_X86_OR_REG_MEMBASE;
13640         case OP_IXOR:
13641                 return OP_X86_XOR_REG_MEMBASE;
13642         }
13643 #endif
13644
13645 #ifdef TARGET_AMD64
13646         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE && cfg->backend->ilp32)) {
13647                 switch (opcode) {
13648                 case OP_ICOMPARE:
13649                         return OP_AMD64_ICOMPARE_REG_MEMBASE;
13650                 case OP_IADD:
13651                         return OP_X86_ADD_REG_MEMBASE;
13652                 case OP_ISUB:
13653                         return OP_X86_SUB_REG_MEMBASE;
13654                 case OP_IAND:
13655                         return OP_X86_AND_REG_MEMBASE;
13656                 case OP_IOR:
13657                         return OP_X86_OR_REG_MEMBASE;
13658                 case OP_IXOR:
13659                         return OP_X86_XOR_REG_MEMBASE;
13660                 }
13661         } else if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32)) {
13662                 switch (opcode) {
13663                 case OP_COMPARE:
13664                 case OP_LCOMPARE:
13665                         return OP_AMD64_COMPARE_REG_MEMBASE;
13666                 case OP_LADD:
13667                         return OP_AMD64_ADD_REG_MEMBASE;
13668                 case OP_LSUB:
13669                         return OP_AMD64_SUB_REG_MEMBASE;
13670                 case OP_LAND:
13671                         return OP_AMD64_AND_REG_MEMBASE;
13672                 case OP_LOR:
13673                         return OP_AMD64_OR_REG_MEMBASE;
13674                 case OP_LXOR:
13675                         return OP_AMD64_XOR_REG_MEMBASE;
13676                 }
13677         }
13678 #endif
13679
13680         return -1;
13681 }
13682
13683 int
13684 mono_op_to_op_imm_noemul (int opcode)
13685 {
13686         switch (opcode) {
13687 #if SIZEOF_REGISTER == 4 && !defined(MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS)
13688         case OP_LSHR:
13689         case OP_LSHL:
13690         case OP_LSHR_UN:
13691                 return -1;
13692 #endif
13693 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
13694         case OP_IDIV:
13695         case OP_IDIV_UN:
13696         case OP_IREM:
13697         case OP_IREM_UN:
13698                 return -1;
13699 #endif
13700 #if defined(MONO_ARCH_EMULATE_MUL_DIV)
13701         case OP_IMUL:
13702                 return -1;
13703 #endif
13704         default:
13705                 return mono_op_to_op_imm (opcode);
13706         }
13707 }
13708
13709 /**
13710  * mono_handle_global_vregs:
13711  *
13712  *   Make vregs used in more than one bblock 'global', i.e. allocate a variable
13713  * for them.
13714  */
13715 void
13716 mono_handle_global_vregs (MonoCompile *cfg)
13717 {
13718         gint32 *vreg_to_bb;
13719         MonoBasicBlock *bb;
13720         int i, pos;
13721
13722         vreg_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (gint32*) * cfg->next_vreg + 1);
13723
13724 #ifdef MONO_ARCH_SIMD_INTRINSICS
13725         if (cfg->uses_simd_intrinsics)
13726                 mono_simd_simplify_indirection (cfg);
13727 #endif
13728
13729         /* Find local vregs used in more than one bb */
13730         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13731                 MonoInst *ins = bb->code;       
13732                 int block_num = bb->block_num;
13733
13734                 if (cfg->verbose_level > 2)
13735                         printf ("\nHANDLE-GLOBAL-VREGS BLOCK %d:\n", bb->block_num);
13736
13737                 cfg->cbb = bb;
13738                 for (; ins; ins = ins->next) {
13739                         const char *spec = INS_INFO (ins->opcode);
13740                         int regtype = 0, regindex;
13741                         gint32 prev_bb;
13742
13743                         if (G_UNLIKELY (cfg->verbose_level > 2))
13744                                 mono_print_ins (ins);
13745
13746                         g_assert (ins->opcode >= MONO_CEE_LAST);
13747
13748                         for (regindex = 0; regindex < 4; regindex ++) {
13749                                 int vreg = 0;
13750
13751                                 if (regindex == 0) {
13752                                         regtype = spec [MONO_INST_DEST];
13753                                         if (regtype == ' ')
13754                                                 continue;
13755                                         vreg = ins->dreg;
13756                                 } else if (regindex == 1) {
13757                                         regtype = spec [MONO_INST_SRC1];
13758                                         if (regtype == ' ')
13759                                                 continue;
13760                                         vreg = ins->sreg1;
13761                                 } else if (regindex == 2) {
13762                                         regtype = spec [MONO_INST_SRC2];
13763                                         if (regtype == ' ')
13764                                                 continue;
13765                                         vreg = ins->sreg2;
13766                                 } else if (regindex == 3) {
13767                                         regtype = spec [MONO_INST_SRC3];
13768                                         if (regtype == ' ')
13769                                                 continue;
13770                                         vreg = ins->sreg3;
13771                                 }
13772
13773 #if SIZEOF_REGISTER == 4
13774                                 /* In the LLVM case, the long opcodes are not decomposed */
13775                                 if (regtype == 'l' && !COMPILE_LLVM (cfg)) {
13776                                         /*
13777                                          * Since some instructions reference the original long vreg,
13778                                          * and some reference the two component vregs, it is quite hard
13779                                          * to determine when it needs to be global. So be conservative.
13780                                          */
13781                                         if (!get_vreg_to_inst (cfg, vreg)) {
13782                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
13783
13784                                                 if (cfg->verbose_level > 2)
13785                                                         printf ("LONG VREG R%d made global.\n", vreg);
13786                                         }
13787
13788                                         /*
13789                                          * Make the component vregs volatile since the optimizations can
13790                                          * get confused otherwise.
13791                                          */
13792                                         get_vreg_to_inst (cfg, vreg + 1)->flags |= MONO_INST_VOLATILE;
13793                                         get_vreg_to_inst (cfg, vreg + 2)->flags |= MONO_INST_VOLATILE;
13794                                 }
13795 #endif
13796
13797                                 g_assert (vreg != -1);
13798
13799                                 prev_bb = vreg_to_bb [vreg];
13800                                 if (prev_bb == 0) {
13801                                         /* 0 is a valid block num */
13802                                         vreg_to_bb [vreg] = block_num + 1;
13803                                 } else if ((prev_bb != block_num + 1) && (prev_bb != -1)) {
13804                                         if (((regtype == 'i' && (vreg < MONO_MAX_IREGS))) || (regtype == 'f' && (vreg < MONO_MAX_FREGS)))
13805                                                 continue;
13806
13807                                         if (!get_vreg_to_inst (cfg, vreg)) {
13808                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
13809                                                         printf ("VREG R%d used in BB%d and BB%d made global.\n", vreg, vreg_to_bb [vreg], block_num);
13810
13811                                                 switch (regtype) {
13812                                                 case 'i':
13813                                                         if (vreg_is_ref (cfg, vreg))
13814                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL, vreg);
13815                                                         else
13816                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL, vreg);
13817                                                         break;
13818                                                 case 'l':
13819                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
13820                                                         break;
13821                                                 case 'f':
13822                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL, vreg);
13823                                                         break;
13824                                                 case 'v':
13825                                                         mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, vreg);
13826                                                         break;
13827                                                 default:
13828                                                         g_assert_not_reached ();
13829                                                 }
13830                                         }
13831
13832                                         /* Flag as having been used in more than one bb */
13833                                         vreg_to_bb [vreg] = -1;
13834                                 }
13835                         }
13836                 }
13837         }
13838
13839         /* If a variable is used in only one bblock, convert it into a local vreg */
13840         for (i = 0; i < cfg->num_varinfo; i++) {
13841                 MonoInst *var = cfg->varinfo [i];
13842                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
13843
13844                 switch (var->type) {
13845                 case STACK_I4:
13846                 case STACK_OBJ:
13847                 case STACK_PTR:
13848                 case STACK_MP:
13849                 case STACK_VTYPE:
13850 #if SIZEOF_REGISTER == 8
13851                 case STACK_I8:
13852 #endif
13853 #if !defined(TARGET_X86)
13854                 /* Enabling this screws up the fp stack on x86 */
13855                 case STACK_R8:
13856 #endif
13857                         if (mono_arch_is_soft_float ())
13858                                 break;
13859
13860                         /* Arguments are implicitly global */
13861                         /* Putting R4 vars into registers doesn't work currently */
13862                         /* The gsharedvt vars are implicitly referenced by ldaddr opcodes, but those opcodes are only generated later */
13863                         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) {
13864                                 /* 
13865                                  * Make that the variable's liveness interval doesn't contain a call, since
13866                                  * that would cause the lvreg to be spilled, making the whole optimization
13867                                  * useless.
13868                                  */
13869                                 /* This is too slow for JIT compilation */
13870 #if 0
13871                                 if (cfg->compile_aot && vreg_to_bb [var->dreg]) {
13872                                         MonoInst *ins;
13873                                         int def_index, call_index, ins_index;
13874                                         gboolean spilled = FALSE;
13875
13876                                         def_index = -1;
13877                                         call_index = -1;
13878                                         ins_index = 0;
13879                                         for (ins = vreg_to_bb [var->dreg]->code; ins; ins = ins->next) {
13880                                                 const char *spec = INS_INFO (ins->opcode);
13881
13882                                                 if ((spec [MONO_INST_DEST] != ' ') && (ins->dreg == var->dreg))
13883                                                         def_index = ins_index;
13884
13885                                                 if (((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg)) ||
13886                                                         ((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg))) {
13887                                                         if (call_index > def_index) {
13888                                                                 spilled = TRUE;
13889                                                                 break;
13890                                                         }
13891                                                 }
13892
13893                                                 if (MONO_IS_CALL (ins))
13894                                                         call_index = ins_index;
13895
13896                                                 ins_index ++;
13897                                         }
13898
13899                                         if (spilled)
13900                                                 break;
13901                                 }
13902 #endif
13903
13904                                 if (G_UNLIKELY (cfg->verbose_level > 2))
13905                                         printf ("CONVERTED R%d(%d) TO VREG.\n", var->dreg, vmv->idx);
13906                                 var->flags |= MONO_INST_IS_DEAD;
13907                                 cfg->vreg_to_inst [var->dreg] = NULL;
13908                         }
13909                         break;
13910                 }
13911         }
13912
13913         /* 
13914          * Compress the varinfo and vars tables so the liveness computation is faster and
13915          * takes up less space.
13916          */
13917         pos = 0;
13918         for (i = 0; i < cfg->num_varinfo; ++i) {
13919                 MonoInst *var = cfg->varinfo [i];
13920                 if (pos < i && cfg->locals_start == i)
13921                         cfg->locals_start = pos;
13922                 if (!(var->flags & MONO_INST_IS_DEAD)) {
13923                         if (pos < i) {
13924                                 cfg->varinfo [pos] = cfg->varinfo [i];
13925                                 cfg->varinfo [pos]->inst_c0 = pos;
13926                                 memcpy (&cfg->vars [pos], &cfg->vars [i], sizeof (MonoMethodVar));
13927                                 cfg->vars [pos].idx = pos;
13928 #if SIZEOF_REGISTER == 4
13929                                 if (cfg->varinfo [pos]->type == STACK_I8) {
13930                                         /* Modify the two component vars too */
13931                                         MonoInst *var1;
13932
13933                                         var1 = get_vreg_to_inst (cfg, cfg->varinfo [pos]->dreg + 1);
13934                                         var1->inst_c0 = pos;
13935                                         var1 = get_vreg_to_inst (cfg, cfg->varinfo [pos]->dreg + 2);
13936                                         var1->inst_c0 = pos;
13937                                 }
13938 #endif
13939                         }
13940                         pos ++;
13941                 }
13942         }
13943         cfg->num_varinfo = pos;
13944         if (cfg->locals_start > cfg->num_varinfo)
13945                 cfg->locals_start = cfg->num_varinfo;
13946 }
13947
13948 /**
13949  * mono_spill_global_vars:
13950  *
13951  *   Generate spill code for variables which are not allocated to registers, 
13952  * and replace vregs with their allocated hregs. *need_local_opts is set to TRUE if
13953  * code is generated which could be optimized by the local optimization passes.
13954  */
13955 void
13956 mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
13957 {
13958         MonoBasicBlock *bb;
13959         char spec2 [16];
13960         int orig_next_vreg;
13961         guint32 *vreg_to_lvreg;
13962         guint32 *lvregs;
13963         guint32 i, lvregs_len;
13964         gboolean dest_has_lvreg = FALSE;
13965         guint32 stacktypes [128];
13966         MonoInst **live_range_start, **live_range_end;
13967         MonoBasicBlock **live_range_start_bb, **live_range_end_bb;
13968         int *gsharedvt_vreg_to_idx = NULL;
13969
13970         *need_local_opts = FALSE;
13971
13972         memset (spec2, 0, sizeof (spec2));
13973
13974         /* FIXME: Move this function to mini.c */
13975         stacktypes ['i'] = STACK_PTR;
13976         stacktypes ['l'] = STACK_I8;
13977         stacktypes ['f'] = STACK_R8;
13978 #ifdef MONO_ARCH_SIMD_INTRINSICS
13979         stacktypes ['x'] = STACK_VTYPE;
13980 #endif
13981
13982 #if SIZEOF_REGISTER == 4
13983         /* Create MonoInsts for longs */
13984         for (i = 0; i < cfg->num_varinfo; i++) {
13985                 MonoInst *ins = cfg->varinfo [i];
13986
13987                 if ((ins->opcode != OP_REGVAR) && !(ins->flags & MONO_INST_IS_DEAD)) {
13988                         switch (ins->type) {
13989                         case STACK_R8:
13990                         case STACK_I8: {
13991                                 MonoInst *tree;
13992
13993                                 if (ins->type == STACK_R8 && !COMPILE_SOFT_FLOAT (cfg))
13994                                         break;
13995
13996                                 g_assert (ins->opcode == OP_REGOFFSET);
13997
13998                                 tree = get_vreg_to_inst (cfg, ins->dreg + 1);
13999                                 g_assert (tree);
14000                                 tree->opcode = OP_REGOFFSET;
14001                                 tree->inst_basereg = ins->inst_basereg;
14002                                 tree->inst_offset = ins->inst_offset + MINI_LS_WORD_OFFSET;
14003
14004                                 tree = get_vreg_to_inst (cfg, ins->dreg + 2);
14005                                 g_assert (tree);
14006                                 tree->opcode = OP_REGOFFSET;
14007                                 tree->inst_basereg = ins->inst_basereg;
14008                                 tree->inst_offset = ins->inst_offset + MINI_MS_WORD_OFFSET;
14009                                 break;
14010                         }
14011                         default:
14012                                 break;
14013                         }
14014                 }
14015         }
14016 #endif
14017
14018         if (cfg->compute_gc_maps) {
14019                 /* registers need liveness info even for !non refs */
14020                 for (i = 0; i < cfg->num_varinfo; i++) {
14021                         MonoInst *ins = cfg->varinfo [i];
14022
14023                         if (ins->opcode == OP_REGVAR)
14024                                 ins->flags |= MONO_INST_GC_TRACK;
14025                 }
14026         }
14027
14028         if (cfg->gsharedvt) {
14029                 gsharedvt_vreg_to_idx = mono_mempool_alloc0 (cfg->mempool, sizeof (int) * cfg->next_vreg);
14030
14031                 for (i = 0; i < cfg->num_varinfo; ++i) {
14032                         MonoInst *ins = cfg->varinfo [i];
14033                         int idx;
14034
14035                         if (mini_is_gsharedvt_variable_type (ins->inst_vtype)) {
14036                                 if (i >= cfg->locals_start) {
14037                                         /* Local */
14038                                         idx = get_gsharedvt_info_slot (cfg, ins->inst_vtype, MONO_RGCTX_INFO_LOCAL_OFFSET);
14039                                         gsharedvt_vreg_to_idx [ins->dreg] = idx + 1;
14040                                         ins->opcode = OP_GSHAREDVT_LOCAL;
14041                                         ins->inst_imm = idx;
14042                                 } else {
14043                                         /* Arg */
14044                                         gsharedvt_vreg_to_idx [ins->dreg] = -1;
14045                                         ins->opcode = OP_GSHAREDVT_ARG_REGOFFSET;
14046                                 }
14047                         }
14048                 }
14049         }
14050                 
14051         /* FIXME: widening and truncation */
14052
14053         /*
14054          * As an optimization, when a variable allocated to the stack is first loaded into 
14055          * an lvreg, we will remember the lvreg and use it the next time instead of loading
14056          * the variable again.
14057          */
14058         orig_next_vreg = cfg->next_vreg;
14059         vreg_to_lvreg = mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * cfg->next_vreg);
14060         lvregs = mono_mempool_alloc (cfg->mempool, sizeof (guint32) * 1024);
14061         lvregs_len = 0;
14062
14063         /* 
14064          * These arrays contain the first and last instructions accessing a given
14065          * variable.
14066          * Since we emit bblocks in the same order we process them here, and we
14067          * don't split live ranges, these will precisely describe the live range of
14068          * the variable, i.e. the instruction range where a valid value can be found
14069          * in the variables location.
14070          * The live range is computed using the liveness info computed by the liveness pass.
14071          * We can't use vmv->range, since that is an abstract live range, and we need
14072          * one which is instruction precise.
14073          * FIXME: Variables used in out-of-line bblocks have a hole in their live range.
14074          */
14075         /* FIXME: Only do this if debugging info is requested */
14076         live_range_start = g_new0 (MonoInst*, cfg->next_vreg);
14077         live_range_end = g_new0 (MonoInst*, cfg->next_vreg);
14078         live_range_start_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
14079         live_range_end_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
14080         
14081         /* Add spill loads/stores */
14082         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
14083                 MonoInst *ins;
14084
14085                 if (cfg->verbose_level > 2)
14086                         printf ("\nSPILL BLOCK %d:\n", bb->block_num);
14087
14088                 /* Clear vreg_to_lvreg array */
14089                 for (i = 0; i < lvregs_len; i++)
14090                         vreg_to_lvreg [lvregs [i]] = 0;
14091                 lvregs_len = 0;
14092
14093                 cfg->cbb = bb;
14094                 MONO_BB_FOR_EACH_INS (bb, ins) {
14095                         const char *spec = INS_INFO (ins->opcode);
14096                         int regtype, srcindex, sreg, tmp_reg, prev_dreg, num_sregs;
14097                         gboolean store, no_lvreg;
14098                         int sregs [MONO_MAX_SRC_REGS];
14099
14100                         if (G_UNLIKELY (cfg->verbose_level > 2))
14101                                 mono_print_ins (ins);
14102
14103                         if (ins->opcode == OP_NOP)
14104                                 continue;
14105
14106                         /* 
14107                          * We handle LDADDR here as well, since it can only be decomposed
14108                          * when variable addresses are known.
14109                          */
14110                         if (ins->opcode == OP_LDADDR) {
14111                                 MonoInst *var = ins->inst_p0;
14112
14113                                 if (var->opcode == OP_VTARG_ADDR) {
14114                                         /* Happens on SPARC/S390 where vtypes are passed by reference */
14115                                         MonoInst *vtaddr = var->inst_left;
14116                                         if (vtaddr->opcode == OP_REGVAR) {
14117                                                 ins->opcode = OP_MOVE;
14118                                                 ins->sreg1 = vtaddr->dreg;
14119                                         }
14120                                         else if (var->inst_left->opcode == OP_REGOFFSET) {
14121                                                 ins->opcode = OP_LOAD_MEMBASE;
14122                                                 ins->inst_basereg = vtaddr->inst_basereg;
14123                                                 ins->inst_offset = vtaddr->inst_offset;
14124                                         } else
14125                                                 NOT_IMPLEMENTED;
14126                                 } else if (cfg->gsharedvt && gsharedvt_vreg_to_idx [var->dreg] < 0) {
14127                                         /* gsharedvt arg passed by ref */
14128                                         g_assert (var->opcode == OP_GSHAREDVT_ARG_REGOFFSET);
14129
14130                                         ins->opcode = OP_LOAD_MEMBASE;
14131                                         ins->inst_basereg = var->inst_basereg;
14132                                         ins->inst_offset = var->inst_offset;
14133                                 } else if (cfg->gsharedvt && gsharedvt_vreg_to_idx [var->dreg]) {
14134                                         MonoInst *load, *load2, *load3;
14135                                         int idx = gsharedvt_vreg_to_idx [var->dreg] - 1;
14136                                         int reg1, reg2, reg3;
14137                                         MonoInst *info_var = cfg->gsharedvt_info_var;
14138                                         MonoInst *locals_var = cfg->gsharedvt_locals_var;
14139
14140                                         /*
14141                                          * gsharedvt local.
14142                                          * Compute the address of the local as gsharedvt_locals_var + gsharedvt_info_var->locals_offsets [idx].
14143                                          */
14144
14145                                         g_assert (var->opcode == OP_GSHAREDVT_LOCAL);
14146
14147                                         g_assert (info_var);
14148                                         g_assert (locals_var);
14149
14150                                         /* Mark the instruction used to compute the locals var as used */
14151                                         cfg->gsharedvt_locals_var_ins = NULL;
14152
14153                                         /* Load the offset */
14154                                         if (info_var->opcode == OP_REGOFFSET) {
14155                                                 reg1 = alloc_ireg (cfg);
14156                                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, reg1, info_var->inst_basereg, info_var->inst_offset);
14157                                         } else if (info_var->opcode == OP_REGVAR) {
14158                                                 load = NULL;
14159                                                 reg1 = info_var->dreg;
14160                                         } else {
14161                                                 g_assert_not_reached ();
14162                                         }
14163                                         reg2 = alloc_ireg (cfg);
14164                                         NEW_LOAD_MEMBASE (cfg, load2, OP_LOADI4_MEMBASE, reg2, reg1, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
14165                                         /* Load the locals area address */
14166                                         reg3 = alloc_ireg (cfg);
14167                                         if (locals_var->opcode == OP_REGOFFSET) {
14168                                                 NEW_LOAD_MEMBASE (cfg, load3, OP_LOAD_MEMBASE, reg3, locals_var->inst_basereg, locals_var->inst_offset);
14169                                         } else if (locals_var->opcode == OP_REGVAR) {
14170                                                 NEW_UNALU (cfg, load3, OP_MOVE, reg3, locals_var->dreg);
14171                                         } else {
14172                                                 g_assert_not_reached ();
14173                                         }
14174                                         /* Compute the address */
14175                                         ins->opcode = OP_PADD;
14176                                         ins->sreg1 = reg3;
14177                                         ins->sreg2 = reg2;
14178
14179                                         mono_bblock_insert_before_ins (bb, ins, load3);
14180                                         mono_bblock_insert_before_ins (bb, load3, load2);
14181                                         if (load)
14182                                                 mono_bblock_insert_before_ins (bb, load2, load);
14183                                 } else {
14184                                         g_assert (var->opcode == OP_REGOFFSET);
14185
14186                                         ins->opcode = OP_ADD_IMM;
14187                                         ins->sreg1 = var->inst_basereg;
14188                                         ins->inst_imm = var->inst_offset;
14189                                 }
14190
14191                                 *need_local_opts = TRUE;
14192                                 spec = INS_INFO (ins->opcode);
14193                         }
14194
14195                         if (ins->opcode < MONO_CEE_LAST) {
14196                                 mono_print_ins (ins);
14197                                 g_assert_not_reached ();
14198                         }
14199
14200                         /*
14201                          * Store opcodes have destbasereg in the dreg, but in reality, it is an
14202                          * src register.
14203                          * FIXME:
14204                          */
14205                         if (MONO_IS_STORE_MEMBASE (ins)) {
14206                                 tmp_reg = ins->dreg;
14207                                 ins->dreg = ins->sreg2;
14208                                 ins->sreg2 = tmp_reg;
14209                                 store = TRUE;
14210
14211                                 spec2 [MONO_INST_DEST] = ' ';
14212                                 spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14213                                 spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14214                                 spec2 [MONO_INST_SRC3] = ' ';
14215                                 spec = spec2;
14216                         } else if (MONO_IS_STORE_MEMINDEX (ins))
14217                                 g_assert_not_reached ();
14218                         else
14219                                 store = FALSE;
14220                         no_lvreg = FALSE;
14221
14222                         if (G_UNLIKELY (cfg->verbose_level > 2)) {
14223                                 printf ("\t %.3s %d", spec, ins->dreg);
14224                                 num_sregs = mono_inst_get_src_registers (ins, sregs);
14225                                 for (srcindex = 0; srcindex < num_sregs; ++srcindex)
14226                                         printf (" %d", sregs [srcindex]);
14227                                 printf ("\n");
14228                         }
14229
14230                         /***************/
14231                         /*    DREG     */
14232                         /***************/
14233                         regtype = spec [MONO_INST_DEST];
14234                         g_assert (((ins->dreg == -1) && (regtype == ' ')) || ((ins->dreg != -1) && (regtype != ' ')));
14235                         prev_dreg = -1;
14236
14237                         if ((ins->dreg != -1) && get_vreg_to_inst (cfg, ins->dreg)) {
14238                                 MonoInst *var = get_vreg_to_inst (cfg, ins->dreg);
14239                                 MonoInst *store_ins;
14240                                 int store_opcode;
14241                                 MonoInst *def_ins = ins;
14242                                 int dreg = ins->dreg; /* The original vreg */
14243
14244                                 store_opcode = mono_type_to_store_membase (cfg, var->inst_vtype);
14245
14246                                 if (var->opcode == OP_REGVAR) {
14247                                         ins->dreg = var->dreg;
14248                                 } 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)) {
14249                                         /* 
14250                                          * Instead of emitting a load+store, use a _membase opcode.
14251                                          */
14252                                         g_assert (var->opcode == OP_REGOFFSET);
14253                                         if (ins->opcode == OP_MOVE) {
14254                                                 NULLIFY_INS (ins);
14255                                                 def_ins = NULL;
14256                                         } else {
14257                                                 ins->opcode = op_to_op_dest_membase (store_opcode, ins->opcode);
14258                                                 ins->inst_basereg = var->inst_basereg;
14259                                                 ins->inst_offset = var->inst_offset;
14260                                                 ins->dreg = -1;
14261                                         }
14262                                         spec = INS_INFO (ins->opcode);
14263                                 } else {
14264                                         guint32 lvreg;
14265
14266                                         g_assert (var->opcode == OP_REGOFFSET);
14267
14268                                         prev_dreg = ins->dreg;
14269
14270                                         /* Invalidate any previous lvreg for this vreg */
14271                                         vreg_to_lvreg [ins->dreg] = 0;
14272
14273                                         lvreg = 0;
14274
14275                                         if (COMPILE_SOFT_FLOAT (cfg) && store_opcode == OP_STORER8_MEMBASE_REG) {
14276                                                 regtype = 'l';
14277                                                 store_opcode = OP_STOREI8_MEMBASE_REG;
14278                                         }
14279
14280                                         ins->dreg = alloc_dreg (cfg, stacktypes [regtype]);
14281
14282 #if SIZEOF_REGISTER != 8
14283                                         if (regtype == 'l') {
14284                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET, ins->dreg + 1);
14285                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14286                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET, ins->dreg + 2);
14287                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14288                                                 def_ins = store_ins;
14289                                         }
14290                                         else
14291 #endif
14292                                         {
14293                                                 g_assert (store_opcode != OP_STOREV_MEMBASE);
14294
14295                                                 /* Try to fuse the store into the instruction itself */
14296                                                 /* FIXME: Add more instructions */
14297                                                 if (!lvreg && ((ins->opcode == OP_ICONST) || ((ins->opcode == OP_I8CONST) && (ins->inst_c0 == 0)))) {
14298                                                         ins->opcode = store_membase_reg_to_store_membase_imm (store_opcode);
14299                                                         ins->inst_imm = ins->inst_c0;
14300                                                         ins->inst_destbasereg = var->inst_basereg;
14301                                                         ins->inst_offset = var->inst_offset;
14302                                                         spec = INS_INFO (ins->opcode);
14303                                                 } else if (!lvreg && ((ins->opcode == OP_MOVE) || (ins->opcode == OP_FMOVE) || (ins->opcode == OP_LMOVE) || (ins->opcode == OP_RMOVE))) {
14304                                                         ins->opcode = store_opcode;
14305                                                         ins->inst_destbasereg = var->inst_basereg;
14306                                                         ins->inst_offset = var->inst_offset;
14307
14308                                                         no_lvreg = TRUE;
14309
14310                                                         tmp_reg = ins->dreg;
14311                                                         ins->dreg = ins->sreg2;
14312                                                         ins->sreg2 = tmp_reg;
14313                                                         store = TRUE;
14314
14315                                                         spec2 [MONO_INST_DEST] = ' ';
14316                                                         spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14317                                                         spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14318                                                         spec2 [MONO_INST_SRC3] = ' ';
14319                                                         spec = spec2;
14320                                                 } else if (!lvreg && (op_to_op_store_membase (store_opcode, ins->opcode) != -1)) {
14321                                                         // FIXME: The backends expect the base reg to be in inst_basereg
14322                                                         ins->opcode = op_to_op_store_membase (store_opcode, ins->opcode);
14323                                                         ins->dreg = -1;
14324                                                         ins->inst_basereg = var->inst_basereg;
14325                                                         ins->inst_offset = var->inst_offset;
14326                                                         spec = INS_INFO (ins->opcode);
14327                                                 } else {
14328                                                         /* printf ("INS: "); mono_print_ins (ins); */
14329                                                         /* Create a store instruction */
14330                                                         NEW_STORE_MEMBASE (cfg, store_ins, store_opcode, var->inst_basereg, var->inst_offset, ins->dreg);
14331
14332                                                         /* Insert it after the instruction */
14333                                                         mono_bblock_insert_after_ins (bb, ins, store_ins);
14334
14335                                                         def_ins = store_ins;
14336
14337                                                         /* 
14338                                                          * We can't assign ins->dreg to var->dreg here, since the
14339                                                          * sregs could use it. So set a flag, and do it after
14340                                                          * the sregs.
14341                                                          */
14342                                                         if ((!cfg->backend->use_fpstack || ((store_opcode != OP_STORER8_MEMBASE_REG) && (store_opcode != OP_STORER4_MEMBASE_REG))) && !((var)->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT)))
14343                                                                 dest_has_lvreg = TRUE;
14344                                                 }
14345                                         }
14346                                 }
14347
14348                                 if (def_ins && !live_range_start [dreg]) {
14349                                         live_range_start [dreg] = def_ins;
14350                                         live_range_start_bb [dreg] = bb;
14351                                 }
14352
14353                                 if (cfg->compute_gc_maps && def_ins && (var->flags & MONO_INST_GC_TRACK)) {
14354                                         MonoInst *tmp;
14355
14356                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
14357                                         tmp->inst_c1 = dreg;
14358                                         mono_bblock_insert_after_ins (bb, def_ins, tmp);
14359                                 }
14360                         }
14361
14362                         /************/
14363                         /*  SREGS   */
14364                         /************/
14365                         num_sregs = mono_inst_get_src_registers (ins, sregs);
14366                         for (srcindex = 0; srcindex < 3; ++srcindex) {
14367                                 regtype = spec [MONO_INST_SRC1 + srcindex];
14368                                 sreg = sregs [srcindex];
14369
14370                                 g_assert (((sreg == -1) && (regtype == ' ')) || ((sreg != -1) && (regtype != ' ')));
14371                                 if ((sreg != -1) && get_vreg_to_inst (cfg, sreg)) {
14372                                         MonoInst *var = get_vreg_to_inst (cfg, sreg);
14373                                         MonoInst *use_ins = ins;
14374                                         MonoInst *load_ins;
14375                                         guint32 load_opcode;
14376
14377                                         if (var->opcode == OP_REGVAR) {
14378                                                 sregs [srcindex] = var->dreg;
14379                                                 //mono_inst_set_src_registers (ins, sregs);
14380                                                 live_range_end [sreg] = use_ins;
14381                                                 live_range_end_bb [sreg] = bb;
14382
14383                                                 if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14384                                                         MonoInst *tmp;
14385
14386                                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14387                                                         /* var->dreg is a hreg */
14388                                                         tmp->inst_c1 = sreg;
14389                                                         mono_bblock_insert_after_ins (bb, ins, tmp);
14390                                                 }
14391
14392                                                 continue;
14393                                         }
14394
14395                                         g_assert (var->opcode == OP_REGOFFSET);
14396                                                 
14397                                         load_opcode = mono_type_to_load_membase (cfg, var->inst_vtype);
14398
14399                                         g_assert (load_opcode != OP_LOADV_MEMBASE);
14400
14401                                         if (vreg_to_lvreg [sreg]) {
14402                                                 g_assert (vreg_to_lvreg [sreg] != -1);
14403
14404                                                 /* The variable is already loaded to an lvreg */
14405                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
14406                                                         printf ("\t\tUse lvreg R%d for R%d.\n", vreg_to_lvreg [sreg], sreg);
14407                                                 sregs [srcindex] = vreg_to_lvreg [sreg];
14408                                                 //mono_inst_set_src_registers (ins, sregs);
14409                                                 continue;
14410                                         }
14411
14412                                         /* Try to fuse the load into the instruction */
14413                                         if ((srcindex == 0) && (op_to_op_src1_membase (cfg, load_opcode, ins->opcode) != -1)) {
14414                                                 ins->opcode = op_to_op_src1_membase (cfg, load_opcode, ins->opcode);
14415                                                 sregs [0] = var->inst_basereg;
14416                                                 //mono_inst_set_src_registers (ins, sregs);
14417                                                 ins->inst_offset = var->inst_offset;
14418                                         } else if ((srcindex == 1) && (op_to_op_src2_membase (cfg, load_opcode, ins->opcode) != -1)) {
14419                                                 ins->opcode = op_to_op_src2_membase (cfg, load_opcode, ins->opcode);
14420                                                 sregs [1] = var->inst_basereg;
14421                                                 //mono_inst_set_src_registers (ins, sregs);
14422                                                 ins->inst_offset = var->inst_offset;
14423                                         } else {
14424                                                 if (MONO_IS_REAL_MOVE (ins)) {
14425                                                         ins->opcode = OP_NOP;
14426                                                         sreg = ins->dreg;
14427                                                 } else {
14428                                                         //printf ("%d ", srcindex); mono_print_ins (ins);
14429
14430                                                         sreg = alloc_dreg (cfg, stacktypes [regtype]);
14431
14432                                                         if ((!cfg->backend->use_fpstack || ((load_opcode != OP_LOADR8_MEMBASE) && (load_opcode != OP_LOADR4_MEMBASE))) && !((var)->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT)) && !no_lvreg) {
14433                                                                 if (var->dreg == prev_dreg) {
14434                                                                         /*
14435                                                                          * sreg refers to the value loaded by the load
14436                                                                          * emitted below, but we need to use ins->dreg
14437                                                                          * since it refers to the store emitted earlier.
14438                                                                          */
14439                                                                         sreg = ins->dreg;
14440                                                                 }
14441                                                                 g_assert (sreg != -1);
14442                                                                 vreg_to_lvreg [var->dreg] = sreg;
14443                                                                 g_assert (lvregs_len < 1024);
14444                                                                 lvregs [lvregs_len ++] = var->dreg;
14445                                                         }
14446                                                 }
14447
14448                                                 sregs [srcindex] = sreg;
14449                                                 //mono_inst_set_src_registers (ins, sregs);
14450
14451 #if SIZEOF_REGISTER != 8
14452                                                 if (regtype == 'l') {
14453                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 2, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET);
14454                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14455                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 1, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET);
14456                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14457                                                         use_ins = load_ins;
14458                                                 }
14459                                                 else
14460 #endif
14461                                                 {
14462 #if SIZEOF_REGISTER == 4
14463                                                         g_assert (load_opcode != OP_LOADI8_MEMBASE);
14464 #endif
14465                                                         NEW_LOAD_MEMBASE (cfg, load_ins, load_opcode, sreg, var->inst_basereg, var->inst_offset);
14466                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14467                                                         use_ins = load_ins;
14468                                                 }
14469                                         }
14470
14471                                         if (var->dreg < orig_next_vreg) {
14472                                                 live_range_end [var->dreg] = use_ins;
14473                                                 live_range_end_bb [var->dreg] = bb;
14474                                         }
14475
14476                                         if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14477                                                 MonoInst *tmp;
14478
14479                                                 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14480                                                 tmp->inst_c1 = var->dreg;
14481                                                 mono_bblock_insert_after_ins (bb, ins, tmp);
14482                                         }
14483                                 }
14484                         }
14485                         mono_inst_set_src_registers (ins, sregs);
14486
14487                         if (dest_has_lvreg) {
14488                                 g_assert (ins->dreg != -1);
14489                                 vreg_to_lvreg [prev_dreg] = ins->dreg;
14490                                 g_assert (lvregs_len < 1024);
14491                                 lvregs [lvregs_len ++] = prev_dreg;
14492                                 dest_has_lvreg = FALSE;
14493                         }
14494
14495                         if (store) {
14496                                 tmp_reg = ins->dreg;
14497                                 ins->dreg = ins->sreg2;
14498                                 ins->sreg2 = tmp_reg;
14499                         }
14500
14501                         if (MONO_IS_CALL (ins)) {
14502                                 /* Clear vreg_to_lvreg array */
14503                                 for (i = 0; i < lvregs_len; i++)
14504                                         vreg_to_lvreg [lvregs [i]] = 0;
14505                                 lvregs_len = 0;
14506                         } else if (ins->opcode == OP_NOP) {
14507                                 ins->dreg = -1;
14508                                 MONO_INST_NULLIFY_SREGS (ins);
14509                         }
14510
14511                         if (cfg->verbose_level > 2)
14512                                 mono_print_ins_index (1, ins);
14513                 }
14514
14515                 /* Extend the live range based on the liveness info */
14516                 if (cfg->compute_precise_live_ranges && bb->live_out_set && bb->code) {
14517                         for (i = 0; i < cfg->num_varinfo; i ++) {
14518                                 MonoMethodVar *vi = MONO_VARINFO (cfg, i);
14519
14520                                 if (vreg_is_volatile (cfg, vi->vreg))
14521                                         /* The liveness info is incomplete */
14522                                         continue;
14523
14524                                 if (mono_bitset_test_fast (bb->live_in_set, i) && !live_range_start [vi->vreg]) {
14525                                         /* Live from at least the first ins of this bb */
14526                                         live_range_start [vi->vreg] = bb->code;
14527                                         live_range_start_bb [vi->vreg] = bb;
14528                                 }
14529
14530                                 if (mono_bitset_test_fast (bb->live_out_set, i)) {
14531                                         /* Live at least until the last ins of this bb */
14532                                         live_range_end [vi->vreg] = bb->last_ins;
14533                                         live_range_end_bb [vi->vreg] = bb;
14534                                 }
14535                         }
14536                 }
14537         }
14538         
14539         /*
14540          * Emit LIVERANGE_START/LIVERANGE_END opcodes, the backend will implement them
14541          * by storing the current native offset into MonoMethodVar->live_range_start/end.
14542          */
14543         if (cfg->backend->have_liverange_ops && cfg->compute_precise_live_ranges && cfg->comp_done & MONO_COMP_LIVENESS) {
14544                 for (i = 0; i < cfg->num_varinfo; ++i) {
14545                         int vreg = MONO_VARINFO (cfg, i)->vreg;
14546                         MonoInst *ins;
14547
14548                         if (live_range_start [vreg]) {
14549                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_START);
14550                                 ins->inst_c0 = i;
14551                                 ins->inst_c1 = vreg;
14552                                 mono_bblock_insert_after_ins (live_range_start_bb [vreg], live_range_start [vreg], ins);
14553                         }
14554                         if (live_range_end [vreg]) {
14555                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_END);
14556                                 ins->inst_c0 = i;
14557                                 ins->inst_c1 = vreg;
14558                                 if (live_range_end [vreg] == live_range_end_bb [vreg]->last_ins)
14559                                         mono_add_ins_to_end (live_range_end_bb [vreg], ins);
14560                                 else
14561                                         mono_bblock_insert_after_ins (live_range_end_bb [vreg], live_range_end [vreg], ins);
14562                         }
14563                 }
14564         }
14565
14566         if (cfg->gsharedvt_locals_var_ins) {
14567                 /* Nullify if unused */
14568                 cfg->gsharedvt_locals_var_ins->opcode = OP_PCONST;
14569                 cfg->gsharedvt_locals_var_ins->inst_imm = 0;
14570         }
14571
14572         g_free (live_range_start);
14573         g_free (live_range_end);
14574         g_free (live_range_start_bb);
14575         g_free (live_range_end_bb);
14576 }
14577
14578 /**
14579  * FIXME:
14580  * - use 'iadd' instead of 'int_add'
14581  * - handling ovf opcodes: decompose in method_to_ir.
14582  * - unify iregs/fregs
14583  *   -> partly done, the missing parts are:
14584  *   - a more complete unification would involve unifying the hregs as well, so
14585  *     code wouldn't need if (fp) all over the place. but that would mean the hregs
14586  *     would no longer map to the machine hregs, so the code generators would need to
14587  *     be modified. Also, on ia64 for example, niregs + nfregs > 256 -> bitmasks
14588  *     wouldn't work any more. Duplicating the code in mono_local_regalloc () into
14589  *     fp/non-fp branches speeds it up by about 15%.
14590  * - use sext/zext opcodes instead of shifts
14591  * - add OP_ICALL
14592  * - get rid of TEMPLOADs if possible and use vregs instead
14593  * - clean up usage of OP_P/OP_ opcodes
14594  * - cleanup usage of DUMMY_USE
14595  * - cleanup the setting of ins->type for MonoInst's which are pushed on the 
14596  *   stack
14597  * - set the stack type and allocate a dreg in the EMIT_NEW macros
14598  * - get rid of all the <foo>2 stuff when the new JIT is ready.
14599  * - make sure handle_stack_args () is called before the branch is emitted
14600  * - when the new IR is done, get rid of all unused stuff
14601  * - COMPARE/BEQ as separate instructions or unify them ?
14602  *   - keeping them separate allows specialized compare instructions like
14603  *     compare_imm, compare_membase
14604  *   - most back ends unify fp compare+branch, fp compare+ceq
14605  * - integrate mono_save_args into inline_method
14606  * - get rid of the empty bblocks created by MONO_EMIT_NEW_BRACH_BLOCK2
14607  * - handle long shift opts on 32 bit platforms somehow: they require 
14608  *   3 sregs (2 for arg1 and 1 for arg2)
14609  * - make byref a 'normal' type.
14610  * - use vregs for bb->out_stacks if possible, handle_global_vreg will make them a
14611  *   variable if needed.
14612  * - do not start a new IL level bblock when cfg->cbb is changed by a function call
14613  *   like inline_method.
14614  * - remove inlining restrictions
14615  * - fix LNEG and enable cfold of INEG
14616  * - generalize x86 optimizations like ldelema as a peephole optimization
14617  * - add store_mem_imm for amd64
14618  * - optimize the loading of the interruption flag in the managed->native wrappers
14619  * - avoid special handling of OP_NOP in passes
14620  * - move code inserting instructions into one function/macro.
14621  * - try a coalescing phase after liveness analysis
14622  * - add float -> vreg conversion + local optimizations on !x86
14623  * - figure out how to handle decomposed branches during optimizations, ie.
14624  *   compare+branch, op_jump_table+op_br etc.
14625  * - promote RuntimeXHandles to vregs
14626  * - vtype cleanups:
14627  *   - add a NEW_VARLOADA_VREG macro
14628  * - the vtype optimizations are blocked by the LDADDR opcodes generated for 
14629  *   accessing vtype fields.
14630  * - get rid of I8CONST on 64 bit platforms
14631  * - dealing with the increase in code size due to branches created during opcode
14632  *   decomposition:
14633  *   - use extended basic blocks
14634  *     - all parts of the JIT
14635  *     - handle_global_vregs () && local regalloc
14636  *   - avoid introducing global vregs during decomposition, like 'vtable' in isinst
14637  * - sources of increase in code size:
14638  *   - vtypes
14639  *   - long compares
14640  *   - isinst and castclass
14641  *   - lvregs not allocated to global registers even if used multiple times
14642  * - call cctors outside the JIT, to make -v output more readable and JIT timings more
14643  *   meaningful.
14644  * - check for fp stack leakage in other opcodes too. (-> 'exceptions' optimization)
14645  * - add all micro optimizations from the old JIT
14646  * - put tree optimizations into the deadce pass
14647  * - decompose op_start_handler/op_endfilter/op_endfinally earlier using an arch
14648  *   specific function.
14649  * - unify the float comparison opcodes with the other comparison opcodes, i.e.
14650  *   fcompare + branchCC.
14651  * - create a helper function for allocating a stack slot, taking into account 
14652  *   MONO_CFG_HAS_SPILLUP.
14653  * - merge r68207.
14654  * - merge the ia64 switch changes.
14655  * - optimize mono_regstate2_alloc_int/float.
14656  * - fix the pessimistic handling of variables accessed in exception handler blocks.
14657  * - need to write a tree optimization pass, but the creation of trees is difficult, i.e.
14658  *   parts of the tree could be separated by other instructions, killing the tree
14659  *   arguments, or stores killing loads etc. Also, should we fold loads into other
14660  *   instructions if the result of the load is used multiple times ?
14661  * - make the REM_IMM optimization in mini-x86.c arch-independent.
14662  * - LAST MERGE: 108395.
14663  * - when returning vtypes in registers, generate IR and append it to the end of the
14664  *   last bb instead of doing it in the epilog.
14665  * - change the store opcodes so they use sreg1 instead of dreg to store the base register.
14666  */
14667
14668 /*
14669
14670 NOTES
14671 -----
14672
14673 - When to decompose opcodes:
14674   - earlier: this makes some optimizations hard to implement, since the low level IR
14675   no longer contains the neccessary information. But it is easier to do.
14676   - later: harder to implement, enables more optimizations.
14677 - Branches inside bblocks:
14678   - created when decomposing complex opcodes. 
14679     - branches to another bblock: harmless, but not tracked by the branch 
14680       optimizations, so need to branch to a label at the start of the bblock.
14681     - branches to inside the same bblock: very problematic, trips up the local
14682       reg allocator. Can be fixed by spitting the current bblock, but that is a
14683       complex operation, since some local vregs can become global vregs etc.
14684 - Local/global vregs:
14685   - local vregs: temporary vregs used inside one bblock. Assigned to hregs by the
14686     local register allocator.
14687   - global vregs: used in more than one bblock. Have an associated MonoMethodVar
14688     structure, created by mono_create_var (). Assigned to hregs or the stack by
14689     the global register allocator.
14690 - When to do optimizations like alu->alu_imm:
14691   - earlier -> saves work later on since the IR will be smaller/simpler
14692   - later -> can work on more instructions
14693 - Handling of valuetypes:
14694   - When a vtype is pushed on the stack, a new temporary is created, an 
14695     instruction computing its address (LDADDR) is emitted and pushed on
14696     the stack. Need to optimize cases when the vtype is used immediately as in
14697     argument passing, stloc etc.
14698 - Instead of the to_end stuff in the old JIT, simply call the function handling
14699   the values on the stack before emitting the last instruction of the bb.
14700 */
14701
14702 #endif /* DISABLE_JIT */