0c1ad62bac972539e57f29175a3ef2c3d62328e6
[mono.git] / mono / mini / method-to-ir.c
1 /*
2  * method-to-ir.c: Convert CIL to the JIT internal representation
3  *
4  * Author:
5  *   Paolo Molaro (lupus@ximian.com)
6  *   Dietmar Maurer (dietmar@ximian.com)
7  *
8  * (C) 2002 Ximian, Inc.
9  * Copyright 2003-2010 Novell, Inc (http://www.novell.com)
10  * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
11  */
12
13 #include <config.h>
14
15 #ifndef DISABLE_JIT
16
17 #include <signal.h>
18
19 #ifdef HAVE_UNISTD_H
20 #include <unistd.h>
21 #endif
22
23 #include <math.h>
24 #include <string.h>
25 #include <ctype.h>
26
27 #ifdef HAVE_SYS_TIME_H
28 #include <sys/time.h>
29 #endif
30
31 #ifdef HAVE_ALLOCA_H
32 #include <alloca.h>
33 #endif
34
35 #include <mono/utils/memcheck.h>
36 #include "mini.h"
37 #include <mono/metadata/abi-details.h>
38 #include <mono/metadata/assembly.h>
39 #include <mono/metadata/attrdefs.h>
40 #include <mono/metadata/loader.h>
41 #include <mono/metadata/tabledefs.h>
42 #include <mono/metadata/class.h>
43 #include <mono/metadata/object.h>
44 #include <mono/metadata/exception.h>
45 #include <mono/metadata/opcodes.h>
46 #include <mono/metadata/mono-endian.h>
47 #include <mono/metadata/tokentype.h>
48 #include <mono/metadata/tabledefs.h>
49 #include <mono/metadata/marshal.h>
50 #include <mono/metadata/debug-helpers.h>
51 #include <mono/metadata/mono-debug.h>
52 #include <mono/metadata/mono-debug-debugger.h>
53 #include <mono/metadata/gc-internal.h>
54 #include <mono/metadata/security-manager.h>
55 #include <mono/metadata/threads-types.h>
56 #include <mono/metadata/security-core-clr.h>
57 #include <mono/metadata/profiler-private.h>
58 #include <mono/metadata/profiler.h>
59 #include <mono/metadata/debug-mono-symfile.h>
60 #include <mono/utils/mono-compiler.h>
61 #include <mono/utils/mono-memory-model.h>
62 #include <mono/metadata/mono-basic-block.h>
63
64 #include "trace.h"
65
66 #include "ir-emit.h"
67
68 #include "jit-icalls.h"
69 #include "jit.h"
70 #include "debugger-agent.h"
71 #include "seq-points.h"
72
73 #define BRANCH_COST 10
74 #define INLINE_LENGTH_LIMIT 20
75
76 /* These have 'cfg' as an implicit argument */
77 #define INLINE_FAILURE(msg) do {                                                                        \
78         if ((cfg->method != cfg->current_method) && (cfg->current_method->wrapper_type == MONO_WRAPPER_NONE)) { \
79                 inline_failure (cfg, msg);                                                                              \
80                 goto exception_exit;                                                                                    \
81         } \
82         } while (0)
83 #define CHECK_CFG_EXCEPTION do {\
84                 if (cfg->exception_type != MONO_EXCEPTION_NONE) \
85                         goto exception_exit;                                            \
86         } while (0)
87 #define METHOD_ACCESS_FAILURE(method, cmethod) do {                     \
88                 method_access_failure ((cfg), (method), (cmethod));                     \
89                 goto exception_exit;                                                                            \
90         } while (0)
91 #define FIELD_ACCESS_FAILURE(method, field) do {                                        \
92                 field_access_failure ((cfg), (method), (field));                        \
93                 goto exception_exit;    \
94         } while (0)
95 #define GENERIC_SHARING_FAILURE(opcode) do {            \
96                 if (cfg->gshared) {                                                                     \
97                         gshared_failure (cfg, opcode, __FILE__, __LINE__);      \
98                         goto exception_exit;    \
99                 }                       \
100         } while (0)
101 #define GSHAREDVT_FAILURE(opcode) do {          \
102         if (cfg->gsharedvt) {                                                                                           \
103                 gsharedvt_failure (cfg, opcode, __FILE__, __LINE__);                    \
104                 goto exception_exit;                                                                                    \
105         }                                                                                                                                       \
106         } while (0)
107 #define OUT_OF_MEMORY_FAILURE do {      \
108                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_OUT_OF_MEMORY);             \
109                 goto exception_exit;    \
110         } while (0)
111 #define DISABLE_AOT(cfg) do { \
112                 if ((cfg)->verbose_level >= 2)                                            \
113                         printf ("AOT disabled: %s:%d\n", __FILE__, __LINE__);   \
114                 (cfg)->disable_aot = TRUE;                                                        \
115         } while (0)
116 #define LOAD_ERROR do { \
117                 break_on_unverified ();                                                         \
118                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD); \
119                 goto exception_exit;                                                                    \
120         } while (0)
121
122 #define TYPE_LOAD_ERROR(klass) do { \
123                 cfg->exception_ptr = klass; \
124                 LOAD_ERROR;                                     \
125         } while (0)
126
127 #define CHECK_CFG_ERROR do {\
128                 if (!mono_error_ok (&cfg->error)) { \
129                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);        \
130                         goto mono_error_exit; \
131                 } \
132         } while (0)
133
134 /* Determine whenever 'ins' represents a load of the 'this' argument */
135 #define MONO_CHECK_THIS(ins) (mono_method_signature (cfg->method)->hasthis && ((ins)->opcode == OP_MOVE) && ((ins)->sreg1 == cfg->args [0]->dreg))
136
137 static int ldind_to_load_membase (int opcode);
138 static int stind_to_store_membase (int opcode);
139
140 int mono_op_to_op_imm (int opcode);
141 int mono_op_to_op_imm_noemul (int opcode);
142
143 MONO_API MonoInst* mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig, MonoInst **args);
144
145 static int inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
146                                                   guchar *ip, guint real_offset, gboolean inline_always);
147
148 /* helper methods signatures */
149 static MonoMethodSignature *helper_sig_domain_get;
150 static MonoMethodSignature *helper_sig_rgctx_lazy_fetch_trampoline;
151
152 /*
153  * Instruction metadata
154  */
155 #ifdef MINI_OP
156 #undef MINI_OP
157 #endif
158 #ifdef MINI_OP3
159 #undef MINI_OP3
160 #endif
161 #define MINI_OP(a,b,dest,src1,src2) dest, src1, src2, ' ',
162 #define MINI_OP3(a,b,dest,src1,src2,src3) dest, src1, src2, src3,
163 #define NONE ' '
164 #define IREG 'i'
165 #define FREG 'f'
166 #define VREG 'v'
167 #define XREG 'x'
168 #if SIZEOF_REGISTER == 8 && SIZEOF_REGISTER == SIZEOF_VOID_P
169 #define LREG IREG
170 #else
171 #define LREG 'l'
172 #endif
173 /* keep in sync with the enum in mini.h */
174 const char
175 ins_info[] = {
176 #include "mini-ops.h"
177 };
178 #undef MINI_OP
179 #undef MINI_OP3
180
181 #define MINI_OP(a,b,dest,src1,src2) ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0)),
182 #define MINI_OP3(a,b,dest,src1,src2,src3) ((src3) != NONE ? 3 : ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0))),
183 /* 
184  * This should contain the index of the last sreg + 1. This is not the same
185  * as the number of sregs for opcodes like IA64_CMP_EQ_IMM.
186  */
187 const gint8 ins_sreg_counts[] = {
188 #include "mini-ops.h"
189 };
190 #undef MINI_OP
191 #undef MINI_OP3
192
193 #define MONO_INIT_VARINFO(vi,id) do { \
194         (vi)->range.first_use.pos.bid = 0xffff; \
195         (vi)->reg = -1; \
196         (vi)->idx = (id); \
197 } while (0)
198
199 guint32
200 mono_alloc_ireg (MonoCompile *cfg)
201 {
202         return alloc_ireg (cfg);
203 }
204
205 guint32
206 mono_alloc_lreg (MonoCompile *cfg)
207 {
208         return alloc_lreg (cfg);
209 }
210
211 guint32
212 mono_alloc_freg (MonoCompile *cfg)
213 {
214         return alloc_freg (cfg);
215 }
216
217 guint32
218 mono_alloc_preg (MonoCompile *cfg)
219 {
220         return alloc_preg (cfg);
221 }
222
223 guint32
224 mono_alloc_dreg (MonoCompile *cfg, MonoStackType stack_type)
225 {
226         return alloc_dreg (cfg, stack_type);
227 }
228
229 /*
230  * mono_alloc_ireg_ref:
231  *
232  *   Allocate an IREG, and mark it as holding a GC ref.
233  */
234 guint32
235 mono_alloc_ireg_ref (MonoCompile *cfg)
236 {
237         return alloc_ireg_ref (cfg);
238 }
239
240 /*
241  * mono_alloc_ireg_mp:
242  *
243  *   Allocate an IREG, and mark it as holding a managed pointer.
244  */
245 guint32
246 mono_alloc_ireg_mp (MonoCompile *cfg)
247 {
248         return alloc_ireg_mp (cfg);
249 }
250
251 /*
252  * mono_alloc_ireg_copy:
253  *
254  *   Allocate an IREG with the same GC type as VREG.
255  */
256 guint32
257 mono_alloc_ireg_copy (MonoCompile *cfg, guint32 vreg)
258 {
259         if (vreg_is_ref (cfg, vreg))
260                 return alloc_ireg_ref (cfg);
261         else if (vreg_is_mp (cfg, vreg))
262                 return alloc_ireg_mp (cfg);
263         else
264                 return alloc_ireg (cfg);
265 }
266
267 guint
268 mono_type_to_regmove (MonoCompile *cfg, MonoType *type)
269 {
270         if (type->byref)
271                 return OP_MOVE;
272
273         type = mini_get_underlying_type (type);
274 handle_enum:
275         switch (type->type) {
276         case MONO_TYPE_I1:
277         case MONO_TYPE_U1:
278                 return OP_MOVE;
279         case MONO_TYPE_I2:
280         case MONO_TYPE_U2:
281                 return OP_MOVE;
282         case MONO_TYPE_I4:
283         case MONO_TYPE_U4:
284                 return OP_MOVE;
285         case MONO_TYPE_I:
286         case MONO_TYPE_U:
287         case MONO_TYPE_PTR:
288         case MONO_TYPE_FNPTR:
289                 return OP_MOVE;
290         case MONO_TYPE_CLASS:
291         case MONO_TYPE_STRING:
292         case MONO_TYPE_OBJECT:
293         case MONO_TYPE_SZARRAY:
294         case MONO_TYPE_ARRAY:    
295                 return OP_MOVE;
296         case MONO_TYPE_I8:
297         case MONO_TYPE_U8:
298 #if SIZEOF_REGISTER == 8
299                 return OP_MOVE;
300 #else
301                 return OP_LMOVE;
302 #endif
303         case MONO_TYPE_R4:
304                 return cfg->r4fp ? OP_RMOVE : OP_FMOVE;
305         case MONO_TYPE_R8:
306                 return OP_FMOVE;
307         case MONO_TYPE_VALUETYPE:
308                 if (type->data.klass->enumtype) {
309                         type = mono_class_enum_basetype (type->data.klass);
310                         goto handle_enum;
311                 }
312                 if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (type)))
313                         return OP_XMOVE;
314                 return OP_VMOVE;
315         case MONO_TYPE_TYPEDBYREF:
316                 return OP_VMOVE;
317         case MONO_TYPE_GENERICINST:
318                 type = &type->data.generic_class->container_class->byval_arg;
319                 goto handle_enum;
320         case MONO_TYPE_VAR:
321         case MONO_TYPE_MVAR:
322                 g_assert (cfg->gshared);
323                 if (mini_type_var_is_vt (type))
324                         return OP_VMOVE;
325                 else
326                         return mono_type_to_regmove (cfg, mini_get_underlying_type (type));
327         default:
328                 g_error ("unknown type 0x%02x in type_to_regstore", type->type);
329         }
330         return -1;
331 }
332
333 void
334 mono_print_bb (MonoBasicBlock *bb, const char *msg)
335 {
336         int i;
337         MonoInst *tree;
338
339         printf ("\n%s %d: [IN: ", msg, bb->block_num);
340         for (i = 0; i < bb->in_count; ++i)
341                 printf (" BB%d(%d)", bb->in_bb [i]->block_num, bb->in_bb [i]->dfn);
342         printf (", OUT: ");
343         for (i = 0; i < bb->out_count; ++i)
344                 printf (" BB%d(%d)", bb->out_bb [i]->block_num, bb->out_bb [i]->dfn);
345         printf (" ]\n");
346         for (tree = bb->code; tree; tree = tree->next)
347                 mono_print_ins_index (-1, tree);
348 }
349
350 void
351 mono_create_helper_signatures (void)
352 {
353         helper_sig_domain_get = mono_create_icall_signature ("ptr");
354         helper_sig_rgctx_lazy_fetch_trampoline = mono_create_icall_signature ("ptr ptr");
355 }
356
357 static MONO_NEVER_INLINE void
358 break_on_unverified (void)
359 {
360         if (mini_get_debug_options ()->break_on_unverified)
361                 G_BREAKPOINT ();
362 }
363
364 static MONO_NEVER_INLINE void
365 method_access_failure (MonoCompile *cfg, MonoMethod *method, MonoMethod *cil_method)
366 {
367         char *method_fname = mono_method_full_name (method, TRUE);
368         char *cil_method_fname = mono_method_full_name (cil_method, TRUE);
369         mono_cfg_set_exception (cfg, MONO_EXCEPTION_METHOD_ACCESS);
370         cfg->exception_message = g_strdup_printf ("Method `%s' is inaccessible from method `%s'\n", cil_method_fname, method_fname);
371         g_free (method_fname);
372         g_free (cil_method_fname);
373 }
374
375 static MONO_NEVER_INLINE void
376 field_access_failure (MonoCompile *cfg, MonoMethod *method, MonoClassField *field)
377 {
378         char *method_fname = mono_method_full_name (method, TRUE);
379         char *field_fname = mono_field_full_name (field);
380         mono_cfg_set_exception (cfg, MONO_EXCEPTION_FIELD_ACCESS);
381         cfg->exception_message = g_strdup_printf ("Field `%s' is inaccessible from method `%s'\n", field_fname, method_fname);
382         g_free (method_fname);
383         g_free (field_fname);
384 }
385
386 static MONO_NEVER_INLINE void
387 inline_failure (MonoCompile *cfg, const char *msg)
388 {
389         if (cfg->verbose_level >= 2)
390                 printf ("inline failed: %s\n", msg);
391         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INLINE_FAILED);
392 }
393
394 static MONO_NEVER_INLINE void
395 gshared_failure (MonoCompile *cfg, int opcode, const char *file, int line)
396 {
397         if (cfg->verbose_level > 2)                                                                                     \
398                 printf ("sharing failed for method %s.%s.%s/%d opcode %s line %d\n", cfg->current_method->klass->name_space, cfg->current_method->klass->name, cfg->current_method->name, cfg->current_method->signature->param_count, mono_opcode_name ((opcode)), line);
399         mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED);
400 }
401
402 static MONO_NEVER_INLINE void
403 gsharedvt_failure (MonoCompile *cfg, int opcode, const char *file, int line)
404 {
405         cfg->exception_message = g_strdup_printf ("gsharedvt failed for method %s.%s.%s/%d opcode %s %s:%d", cfg->current_method->klass->name_space, cfg->current_method->klass->name, cfg->current_method->name, cfg->current_method->signature->param_count, mono_opcode_name ((opcode)), file, line);
406         if (cfg->verbose_level >= 2)
407                 printf ("%s\n", cfg->exception_message);
408         mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED);
409 }
410
411 /*
412  * When using gsharedvt, some instatiations might be verifiable, and some might be not. i.e. 
413  * foo<T> (int i) { ldarg.0; box T; }
414  */
415 #define UNVERIFIED do { \
416         if (cfg->gsharedvt) { \
417                 if (cfg->verbose_level > 2)                                                                     \
418                         printf ("gsharedvt method failed to verify, falling back to instantiation.\n"); \
419                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED); \
420                 goto exception_exit;                                                                                    \
421         }                                                                                                                                       \
422         break_on_unverified ();                                                                                         \
423         goto unverified;                                                                                                        \
424 } while (0)
425
426 #define GET_BBLOCK(cfg,tblock,ip) do {  \
427                 (tblock) = cfg->cil_offset_to_bb [(ip) - cfg->cil_start]; \
428                 if (!(tblock)) {        \
429                         if ((ip) >= end || (ip) < header->code) UNVERIFIED; \
430             NEW_BBLOCK (cfg, (tblock)); \
431                         (tblock)->cil_code = (ip);      \
432                         ADD_BBLOCK (cfg, (tblock));     \
433                 } \
434         } while (0)
435
436 #if defined(TARGET_X86) || defined(TARGET_AMD64)
437 #define EMIT_NEW_X86_LEA(cfg,dest,sr1,sr2,shift,imm) do { \
438                 MONO_INST_NEW (cfg, dest, OP_X86_LEA); \
439                 (dest)->dreg = alloc_ireg_mp ((cfg)); \
440                 (dest)->sreg1 = (sr1); \
441                 (dest)->sreg2 = (sr2); \
442                 (dest)->inst_imm = (imm); \
443                 (dest)->backend.shift_amount = (shift); \
444                 MONO_ADD_INS ((cfg)->cbb, (dest)); \
445         } while (0)
446 #endif
447
448 /* Emit conversions so both operands of a binary opcode are of the same type */
449 static void
450 add_widen_op (MonoCompile *cfg, MonoInst *ins, MonoInst **arg1_ref, MonoInst **arg2_ref)
451 {
452         MonoInst *arg1 = *arg1_ref;
453         MonoInst *arg2 = *arg2_ref;
454
455         if (cfg->r4fp &&
456                 ((arg1->type == STACK_R4 && arg2->type == STACK_R8) ||
457                  (arg1->type == STACK_R8 && arg2->type == STACK_R4))) {
458                 MonoInst *conv;
459
460                 /* Mixing r4/r8 is allowed by the spec */
461                 if (arg1->type == STACK_R4) {
462                         int dreg = alloc_freg (cfg);
463
464                         EMIT_NEW_UNALU (cfg, conv, OP_RCONV_TO_R8, dreg, arg1->dreg);
465                         conv->type = STACK_R8;
466                         ins->sreg1 = dreg;
467                         *arg1_ref = conv;
468                 }
469                 if (arg2->type == STACK_R4) {
470                         int dreg = alloc_freg (cfg);
471
472                         EMIT_NEW_UNALU (cfg, conv, OP_RCONV_TO_R8, dreg, arg2->dreg);
473                         conv->type = STACK_R8;
474                         ins->sreg2 = dreg;
475                         *arg2_ref = conv;
476                 }
477         }
478
479 #if SIZEOF_REGISTER == 8
480         /* FIXME: Need to add many more cases */
481         if ((arg1)->type == STACK_PTR && (arg2)->type == STACK_I4) {
482                 MonoInst *widen;
483
484                 int dr = alloc_preg (cfg);
485                 EMIT_NEW_UNALU (cfg, widen, OP_SEXT_I4, dr, (arg2)->dreg);
486                 (ins)->sreg2 = widen->dreg;
487         }
488 #endif
489 }
490
491 #define ADD_BINOP(op) do {      \
492                 MONO_INST_NEW (cfg, ins, (op)); \
493                 sp -= 2;        \
494                 ins->sreg1 = sp [0]->dreg;      \
495                 ins->sreg2 = sp [1]->dreg;      \
496                 type_from_op (cfg, ins, sp [0], sp [1]);        \
497                 CHECK_TYPE (ins);       \
498                 /* Have to insert a widening op */               \
499         add_widen_op (cfg, ins, &sp [0], &sp [1]);               \
500         ins->dreg = alloc_dreg ((cfg), (ins)->type); \
501         MONO_ADD_INS ((cfg)->cbb, (ins)); \
502         *sp++ = mono_decompose_opcode ((cfg), (ins));   \
503         } while (0)
504
505 #define ADD_UNOP(op) do {       \
506                 MONO_INST_NEW (cfg, ins, (op)); \
507                 sp--;   \
508                 ins->sreg1 = sp [0]->dreg;      \
509                 type_from_op (cfg, ins, sp [0], NULL);  \
510                 CHECK_TYPE (ins);       \
511         (ins)->dreg = alloc_dreg ((cfg), (ins)->type); \
512         MONO_ADD_INS ((cfg)->cbb, (ins)); \
513                 *sp++ = mono_decompose_opcode (cfg, ins);       \
514         } while (0)
515
516 #define ADD_BINCOND(next_block) do {    \
517                 MonoInst *cmp;  \
518                 sp -= 2; \
519                 MONO_INST_NEW(cfg, cmp, OP_COMPARE);    \
520                 cmp->sreg1 = sp [0]->dreg;      \
521                 cmp->sreg2 = sp [1]->dreg;      \
522                 type_from_op (cfg, cmp, sp [0], sp [1]);        \
523                 CHECK_TYPE (cmp);       \
524                 add_widen_op (cfg, cmp, &sp [0], &sp [1]);                                              \
525                 type_from_op (cfg, ins, sp [0], sp [1]);                                                        \
526                 ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);      \
527                 GET_BBLOCK (cfg, tblock, target);               \
528                 link_bblock (cfg, cfg->cbb, tblock);    \
529                 ins->inst_true_bb = tblock;     \
530                 if ((next_block)) {     \
531                         link_bblock (cfg, cfg->cbb, (next_block));      \
532                         ins->inst_false_bb = (next_block);      \
533                         start_new_bblock = 1;   \
534                 } else {        \
535                         GET_BBLOCK (cfg, tblock, ip);           \
536                         link_bblock (cfg, cfg->cbb, tblock);    \
537                         ins->inst_false_bb = tblock;    \
538                         start_new_bblock = 2;   \
539                 }       \
540                 if (sp != stack_start) {                                                                        \
541                     handle_stack_args (cfg, stack_start, sp - stack_start); \
542                         CHECK_UNVERIFIABLE (cfg); \
543                 } \
544         MONO_ADD_INS (cfg->cbb, cmp); \
545                 MONO_ADD_INS (cfg->cbb, ins);   \
546         } while (0)
547
548 /* *
549  * link_bblock: Links two basic blocks
550  *
551  * links two basic blocks in the control flow graph, the 'from'
552  * argument is the starting block and the 'to' argument is the block
553  * the control flow ends to after 'from'.
554  */
555 static void
556 link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
557 {
558         MonoBasicBlock **newa;
559         int i, found;
560
561 #if 0
562         if (from->cil_code) {
563                 if (to->cil_code)
564                         printf ("edge from IL%04x to IL_%04x\n", from->cil_code - cfg->cil_code, to->cil_code - cfg->cil_code);
565                 else
566                         printf ("edge from IL%04x to exit\n", from->cil_code - cfg->cil_code);
567         } else {
568                 if (to->cil_code)
569                         printf ("edge from entry to IL_%04x\n", to->cil_code - cfg->cil_code);
570                 else
571                         printf ("edge from entry to exit\n");
572         }
573 #endif
574
575         found = FALSE;
576         for (i = 0; i < from->out_count; ++i) {
577                 if (to == from->out_bb [i]) {
578                         found = TRUE;
579                         break;
580                 }
581         }
582         if (!found) {
583                 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (from->out_count + 1));
584                 for (i = 0; i < from->out_count; ++i) {
585                         newa [i] = from->out_bb [i];
586                 }
587                 newa [i] = to;
588                 from->out_count++;
589                 from->out_bb = newa;
590         }
591
592         found = FALSE;
593         for (i = 0; i < to->in_count; ++i) {
594                 if (from == to->in_bb [i]) {
595                         found = TRUE;
596                         break;
597                 }
598         }
599         if (!found) {
600                 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (to->in_count + 1));
601                 for (i = 0; i < to->in_count; ++i) {
602                         newa [i] = to->in_bb [i];
603                 }
604                 newa [i] = from;
605                 to->in_count++;
606                 to->in_bb = newa;
607         }
608 }
609
610 void
611 mono_link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
612 {
613         link_bblock (cfg, from, to);
614 }
615
616 /**
617  * mono_find_block_region:
618  *
619  *   We mark each basic block with a region ID. We use that to avoid BB
620  *   optimizations when blocks are in different regions.
621  *
622  * Returns:
623  *   A region token that encodes where this region is, and information
624  *   about the clause owner for this block.
625  *
626  *   The region encodes the try/catch/filter clause that owns this block
627  *   as well as the type.  -1 is a special value that represents a block
628  *   that is in none of try/catch/filter.
629  */
630 static int
631 mono_find_block_region (MonoCompile *cfg, int offset)
632 {
633         MonoMethodHeader *header = cfg->header;
634         MonoExceptionClause *clause;
635         int i;
636
637         for (i = 0; i < header->num_clauses; ++i) {
638                 clause = &header->clauses [i];
639                 if ((clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) && (offset >= clause->data.filter_offset) &&
640                     (offset < (clause->handler_offset)))
641                         return ((i + 1) << 8) | MONO_REGION_FILTER | clause->flags;
642                            
643                 if (MONO_OFFSET_IN_HANDLER (clause, offset)) {
644                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY)
645                                 return ((i + 1) << 8) | MONO_REGION_FINALLY | clause->flags;
646                         else if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
647                                 return ((i + 1) << 8) | MONO_REGION_FAULT | clause->flags;
648                         else
649                                 return ((i + 1) << 8) | MONO_REGION_CATCH | clause->flags;
650                 }
651         }
652         for (i = 0; i < header->num_clauses; ++i) {
653                 clause = &header->clauses [i];
654
655                 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
656                         return ((i + 1) << 8) | clause->flags;
657         }
658
659         return -1;
660 }
661
662 static GList*
663 mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *target, int type)
664 {
665         MonoMethodHeader *header = cfg->header;
666         MonoExceptionClause *clause;
667         int i;
668         GList *res = NULL;
669
670         for (i = 0; i < header->num_clauses; ++i) {
671                 clause = &header->clauses [i];
672                 if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) && 
673                     (!MONO_OFFSET_IN_CLAUSE (clause, (target - header->code)))) {
674                         if (clause->flags == type)
675                                 res = g_list_append (res, clause);
676                 }
677         }
678         return res;
679 }
680
681 static void
682 mono_create_spvar_for_region (MonoCompile *cfg, int region)
683 {
684         MonoInst *var;
685
686         var = g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
687         if (var)
688                 return;
689
690         var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
691         /* prevent it from being register allocated */
692         var->flags |= MONO_INST_VOLATILE;
693
694         g_hash_table_insert (cfg->spvars, GINT_TO_POINTER (region), var);
695 }
696
697 MonoInst *
698 mono_find_exvar_for_offset (MonoCompile *cfg, int offset)
699 {
700         return g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
701 }
702
703 static MonoInst*
704 mono_create_exvar_for_offset (MonoCompile *cfg, int offset)
705 {
706         MonoInst *var;
707
708         var = g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
709         if (var)
710                 return var;
711
712         var = mono_compile_create_var (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL);
713         /* prevent it from being register allocated */
714         var->flags |= MONO_INST_VOLATILE;
715
716         g_hash_table_insert (cfg->exvars, GINT_TO_POINTER (offset), var);
717
718         return var;
719 }
720
721 /*
722  * Returns the type used in the eval stack when @type is loaded.
723  * FIXME: return a MonoType/MonoClass for the byref and VALUETYPE cases.
724  */
725 void
726 type_to_eval_stack_type (MonoCompile *cfg, MonoType *type, MonoInst *inst)
727 {
728         MonoClass *klass;
729
730         type = mini_get_underlying_type (type);
731         inst->klass = klass = mono_class_from_mono_type (type);
732         if (type->byref) {
733                 inst->type = STACK_MP;
734                 return;
735         }
736
737 handle_enum:
738         switch (type->type) {
739         case MONO_TYPE_VOID:
740                 inst->type = STACK_INV;
741                 return;
742         case MONO_TYPE_I1:
743         case MONO_TYPE_U1:
744         case MONO_TYPE_I2:
745         case MONO_TYPE_U2:
746         case MONO_TYPE_I4:
747         case MONO_TYPE_U4:
748                 inst->type = STACK_I4;
749                 return;
750         case MONO_TYPE_I:
751         case MONO_TYPE_U:
752         case MONO_TYPE_PTR:
753         case MONO_TYPE_FNPTR:
754                 inst->type = STACK_PTR;
755                 return;
756         case MONO_TYPE_CLASS:
757         case MONO_TYPE_STRING:
758         case MONO_TYPE_OBJECT:
759         case MONO_TYPE_SZARRAY:
760         case MONO_TYPE_ARRAY:    
761                 inst->type = STACK_OBJ;
762                 return;
763         case MONO_TYPE_I8:
764         case MONO_TYPE_U8:
765                 inst->type = STACK_I8;
766                 return;
767         case MONO_TYPE_R4:
768                 inst->type = cfg->r4_stack_type;
769                 break;
770         case MONO_TYPE_R8:
771                 inst->type = STACK_R8;
772                 return;
773         case MONO_TYPE_VALUETYPE:
774                 if (type->data.klass->enumtype) {
775                         type = mono_class_enum_basetype (type->data.klass);
776                         goto handle_enum;
777                 } else {
778                         inst->klass = klass;
779                         inst->type = STACK_VTYPE;
780                         return;
781                 }
782         case MONO_TYPE_TYPEDBYREF:
783                 inst->klass = mono_defaults.typed_reference_class;
784                 inst->type = STACK_VTYPE;
785                 return;
786         case MONO_TYPE_GENERICINST:
787                 type = &type->data.generic_class->container_class->byval_arg;
788                 goto handle_enum;
789         case MONO_TYPE_VAR:
790         case MONO_TYPE_MVAR:
791                 g_assert (cfg->gshared);
792                 if (mini_is_gsharedvt_type (type)) {
793                         g_assert (cfg->gsharedvt);
794                         inst->type = STACK_VTYPE;
795                 } else {
796                         type_to_eval_stack_type (cfg, mini_get_underlying_type (type), inst);
797                 }
798                 return;
799         default:
800                 g_error ("unknown type 0x%02x in eval stack type", type->type);
801         }
802 }
803
804 /*
805  * The following tables are used to quickly validate the IL code in type_from_op ().
806  */
807 static const char
808 bin_num_table [STACK_MAX] [STACK_MAX] = {
809         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
810         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
811         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
812         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
813         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8,  STACK_INV, STACK_INV, STACK_INV, STACK_R8},
814         {STACK_INV, STACK_MP,  STACK_INV, STACK_MP,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV},
815         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
816         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
817         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8, STACK_INV, STACK_INV, STACK_INV, STACK_R4}
818 };
819
820 static const char 
821 neg_table [] = {
822         STACK_INV, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_INV, STACK_INV, STACK_INV, STACK_R4
823 };
824
825 /* reduce the size of this table */
826 static const char
827 bin_int_table [STACK_MAX] [STACK_MAX] = {
828         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
829         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
830         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
831         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
832         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
833         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
834         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
835         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
836 };
837
838 static const char
839 bin_comp_table [STACK_MAX] [STACK_MAX] = {
840 /*      Inv i  L  p  F  &  O  vt r4 */
841         {0},
842         {0, 1, 0, 1, 0, 0, 0, 0}, /* i, int32 */
843         {0, 0, 1, 0, 0, 0, 0, 0}, /* L, int64 */
844         {0, 1, 0, 1, 0, 2, 4, 0}, /* p, ptr */
845         {0, 0, 0, 0, 1, 0, 0, 0, 1}, /* F, R8 */
846         {0, 0, 0, 2, 0, 1, 0, 0}, /* &, managed pointer */
847         {0, 0, 0, 4, 0, 0, 3, 0}, /* O, reference */
848         {0, 0, 0, 0, 0, 0, 0, 0}, /* vt value type */
849         {0, 0, 0, 0, 1, 0, 0, 0, 1}, /* r, r4 */
850 };
851
852 /* reduce the size of this table */
853 static const char
854 shift_table [STACK_MAX] [STACK_MAX] = {
855         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
856         {STACK_INV, STACK_I4,  STACK_INV, STACK_I4,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
857         {STACK_INV, STACK_I8,  STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
858         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
859         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
860         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
861         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
862         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
863 };
864
865 /*
866  * Tables to map from the non-specific opcode to the matching
867  * type-specific opcode.
868  */
869 /* handles from CEE_ADD to CEE_SHR_UN (CEE_REM_UN for floats) */
870 static const guint16
871 binops_op_map [STACK_MAX] = {
872         0, OP_IADD-CEE_ADD, OP_LADD-CEE_ADD, OP_PADD-CEE_ADD, OP_FADD-CEE_ADD, OP_PADD-CEE_ADD, 0, 0, OP_RADD-CEE_ADD
873 };
874
875 /* handles from CEE_NEG to CEE_CONV_U8 */
876 static const guint16
877 unops_op_map [STACK_MAX] = {
878         0, OP_INEG-CEE_NEG, OP_LNEG-CEE_NEG, OP_PNEG-CEE_NEG, OP_FNEG-CEE_NEG, OP_PNEG-CEE_NEG, 0, 0, OP_RNEG-CEE_NEG
879 };
880
881 /* handles from CEE_CONV_U2 to CEE_SUB_OVF_UN */
882 static const guint16
883 ovfops_op_map [STACK_MAX] = {
884         0, OP_ICONV_TO_U2-CEE_CONV_U2, OP_LCONV_TO_U2-CEE_CONV_U2, OP_PCONV_TO_U2-CEE_CONV_U2, OP_FCONV_TO_U2-CEE_CONV_U2, OP_PCONV_TO_U2-CEE_CONV_U2, OP_PCONV_TO_U2-CEE_CONV_U2, 0, OP_RCONV_TO_U2-CEE_CONV_U2
885 };
886
887 /* handles from CEE_CONV_OVF_I1_UN to CEE_CONV_OVF_U_UN */
888 static const guint16
889 ovf2ops_op_map [STACK_MAX] = {
890         0, OP_ICONV_TO_OVF_I1_UN-CEE_CONV_OVF_I1_UN, OP_LCONV_TO_OVF_I1_UN-CEE_CONV_OVF_I1_UN, OP_PCONV_TO_OVF_I1_UN-CEE_CONV_OVF_I1_UN, OP_FCONV_TO_OVF_I1_UN-CEE_CONV_OVF_I1_UN, OP_PCONV_TO_OVF_I1_UN-CEE_CONV_OVF_I1_UN, 0, 0, OP_RCONV_TO_OVF_I1_UN-CEE_CONV_OVF_I1_UN
891 };
892
893 /* handles from CEE_CONV_OVF_I1 to CEE_CONV_OVF_U8 */
894 static const guint16
895 ovf3ops_op_map [STACK_MAX] = {
896         0, OP_ICONV_TO_OVF_I1-CEE_CONV_OVF_I1, OP_LCONV_TO_OVF_I1-CEE_CONV_OVF_I1, OP_PCONV_TO_OVF_I1-CEE_CONV_OVF_I1, OP_FCONV_TO_OVF_I1-CEE_CONV_OVF_I1, OP_PCONV_TO_OVF_I1-CEE_CONV_OVF_I1, 0, 0, OP_RCONV_TO_OVF_I1-CEE_CONV_OVF_I1
897 };
898
899 /* handles from CEE_BEQ to CEE_BLT_UN */
900 static const guint16
901 beqops_op_map [STACK_MAX] = {
902         0, OP_IBEQ-CEE_BEQ, OP_LBEQ-CEE_BEQ, OP_PBEQ-CEE_BEQ, OP_FBEQ-CEE_BEQ, OP_PBEQ-CEE_BEQ, OP_PBEQ-CEE_BEQ, 0, OP_FBEQ-CEE_BEQ
903 };
904
905 /* handles from CEE_CEQ to CEE_CLT_UN */
906 static const guint16
907 ceqops_op_map [STACK_MAX] = {
908         0, OP_ICEQ-OP_CEQ, OP_LCEQ-OP_CEQ, OP_PCEQ-OP_CEQ, OP_FCEQ-OP_CEQ, OP_PCEQ-OP_CEQ, OP_PCEQ-OP_CEQ, 0, OP_RCEQ-OP_CEQ
909 };
910
911 /*
912  * Sets ins->type (the type on the eval stack) according to the
913  * type of the opcode and the arguments to it.
914  * Invalid IL code is marked by setting ins->type to the invalid value STACK_INV.
915  *
916  * FIXME: this function sets ins->type unconditionally in some cases, but
917  * it should set it to invalid for some types (a conv.x on an object)
918  */
919 static void
920 type_from_op (MonoCompile *cfg, MonoInst *ins, MonoInst *src1, MonoInst *src2)
921 {
922         switch (ins->opcode) {
923         /* binops */
924         case CEE_ADD:
925         case CEE_SUB:
926         case CEE_MUL:
927         case CEE_DIV:
928         case CEE_REM:
929                 /* FIXME: check unverifiable args for STACK_MP */
930                 ins->type = bin_num_table [src1->type] [src2->type];
931                 ins->opcode += binops_op_map [ins->type];
932                 break;
933         case CEE_DIV_UN:
934         case CEE_REM_UN:
935         case CEE_AND:
936         case CEE_OR:
937         case CEE_XOR:
938                 ins->type = bin_int_table [src1->type] [src2->type];
939                 ins->opcode += binops_op_map [ins->type];
940                 break;
941         case CEE_SHL:
942         case CEE_SHR:
943         case CEE_SHR_UN:
944                 ins->type = shift_table [src1->type] [src2->type];
945                 ins->opcode += binops_op_map [ins->type];
946                 break;
947         case OP_COMPARE:
948         case OP_LCOMPARE:
949         case OP_ICOMPARE:
950                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
951                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
952                         ins->opcode = OP_LCOMPARE;
953                 else if (src1->type == STACK_R4)
954                         ins->opcode = OP_RCOMPARE;
955                 else if (src1->type == STACK_R8)
956                         ins->opcode = OP_FCOMPARE;
957                 else
958                         ins->opcode = OP_ICOMPARE;
959                 break;
960         case OP_ICOMPARE_IMM:
961                 ins->type = bin_comp_table [src1->type] [src1->type] ? STACK_I4 : STACK_INV;
962                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
963                         ins->opcode = OP_LCOMPARE_IMM;          
964                 break;
965         case CEE_BEQ:
966         case CEE_BGE:
967         case CEE_BGT:
968         case CEE_BLE:
969         case CEE_BLT:
970         case CEE_BNE_UN:
971         case CEE_BGE_UN:
972         case CEE_BGT_UN:
973         case CEE_BLE_UN:
974         case CEE_BLT_UN:
975                 ins->opcode += beqops_op_map [src1->type];
976                 break;
977         case OP_CEQ:
978                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
979                 ins->opcode += ceqops_op_map [src1->type];
980                 break;
981         case OP_CGT:
982         case OP_CGT_UN:
983         case OP_CLT:
984         case OP_CLT_UN:
985                 ins->type = (bin_comp_table [src1->type] [src2->type] & 1) ? STACK_I4: STACK_INV;
986                 ins->opcode += ceqops_op_map [src1->type];
987                 break;
988         /* unops */
989         case CEE_NEG:
990                 ins->type = neg_table [src1->type];
991                 ins->opcode += unops_op_map [ins->type];
992                 break;
993         case CEE_NOT:
994                 if (src1->type >= STACK_I4 && src1->type <= STACK_PTR)
995                         ins->type = src1->type;
996                 else
997                         ins->type = STACK_INV;
998                 ins->opcode += unops_op_map [ins->type];
999                 break;
1000         case CEE_CONV_I1:
1001         case CEE_CONV_I2:
1002         case CEE_CONV_I4:
1003         case CEE_CONV_U4:
1004                 ins->type = STACK_I4;
1005                 ins->opcode += unops_op_map [src1->type];
1006                 break;
1007         case CEE_CONV_R_UN:
1008                 ins->type = STACK_R8;
1009                 switch (src1->type) {
1010                 case STACK_I4:
1011                 case STACK_PTR:
1012                         ins->opcode = OP_ICONV_TO_R_UN;
1013                         break;
1014                 case STACK_I8:
1015                         ins->opcode = OP_LCONV_TO_R_UN; 
1016                         break;
1017                 }
1018                 break;
1019         case CEE_CONV_OVF_I1:
1020         case CEE_CONV_OVF_U1:
1021         case CEE_CONV_OVF_I2:
1022         case CEE_CONV_OVF_U2:
1023         case CEE_CONV_OVF_I4:
1024         case CEE_CONV_OVF_U4:
1025                 ins->type = STACK_I4;
1026                 ins->opcode += ovf3ops_op_map [src1->type];
1027                 break;
1028         case CEE_CONV_OVF_I_UN:
1029         case CEE_CONV_OVF_U_UN:
1030                 ins->type = STACK_PTR;
1031                 ins->opcode += ovf2ops_op_map [src1->type];
1032                 break;
1033         case CEE_CONV_OVF_I1_UN:
1034         case CEE_CONV_OVF_I2_UN:
1035         case CEE_CONV_OVF_I4_UN:
1036         case CEE_CONV_OVF_U1_UN:
1037         case CEE_CONV_OVF_U2_UN:
1038         case CEE_CONV_OVF_U4_UN:
1039                 ins->type = STACK_I4;
1040                 ins->opcode += ovf2ops_op_map [src1->type];
1041                 break;
1042         case CEE_CONV_U:
1043                 ins->type = STACK_PTR;
1044                 switch (src1->type) {
1045                 case STACK_I4:
1046                         ins->opcode = OP_ICONV_TO_U;
1047                         break;
1048                 case STACK_PTR:
1049                 case STACK_MP:
1050 #if SIZEOF_VOID_P == 8
1051                         ins->opcode = OP_LCONV_TO_U;
1052 #else
1053                         ins->opcode = OP_MOVE;
1054 #endif
1055                         break;
1056                 case STACK_I8:
1057                         ins->opcode = OP_LCONV_TO_U;
1058                         break;
1059                 case STACK_R8:
1060                         ins->opcode = OP_FCONV_TO_U;
1061                         break;
1062                 }
1063                 break;
1064         case CEE_CONV_I8:
1065         case CEE_CONV_U8:
1066                 ins->type = STACK_I8;
1067                 ins->opcode += unops_op_map [src1->type];
1068                 break;
1069         case CEE_CONV_OVF_I8:
1070         case CEE_CONV_OVF_U8:
1071                 ins->type = STACK_I8;
1072                 ins->opcode += ovf3ops_op_map [src1->type];
1073                 break;
1074         case CEE_CONV_OVF_U8_UN:
1075         case CEE_CONV_OVF_I8_UN:
1076                 ins->type = STACK_I8;
1077                 ins->opcode += ovf2ops_op_map [src1->type];
1078                 break;
1079         case CEE_CONV_R4:
1080                 ins->type = cfg->r4_stack_type;
1081                 ins->opcode += unops_op_map [src1->type];
1082                 break;
1083         case CEE_CONV_R8:
1084                 ins->type = STACK_R8;
1085                 ins->opcode += unops_op_map [src1->type];
1086                 break;
1087         case OP_CKFINITE:
1088                 ins->type = STACK_R8;           
1089                 break;
1090         case CEE_CONV_U2:
1091         case CEE_CONV_U1:
1092                 ins->type = STACK_I4;
1093                 ins->opcode += ovfops_op_map [src1->type];
1094                 break;
1095         case CEE_CONV_I:
1096         case CEE_CONV_OVF_I:
1097         case CEE_CONV_OVF_U:
1098                 ins->type = STACK_PTR;
1099                 ins->opcode += ovfops_op_map [src1->type];
1100                 break;
1101         case CEE_ADD_OVF:
1102         case CEE_ADD_OVF_UN:
1103         case CEE_MUL_OVF:
1104         case CEE_MUL_OVF_UN:
1105         case CEE_SUB_OVF:
1106         case CEE_SUB_OVF_UN:
1107                 ins->type = bin_num_table [src1->type] [src2->type];
1108                 ins->opcode += ovfops_op_map [src1->type];
1109                 if (ins->type == STACK_R8)
1110                         ins->type = STACK_INV;
1111                 break;
1112         case OP_LOAD_MEMBASE:
1113                 ins->type = STACK_PTR;
1114                 break;
1115         case OP_LOADI1_MEMBASE:
1116         case OP_LOADU1_MEMBASE:
1117         case OP_LOADI2_MEMBASE:
1118         case OP_LOADU2_MEMBASE:
1119         case OP_LOADI4_MEMBASE:
1120         case OP_LOADU4_MEMBASE:
1121                 ins->type = STACK_PTR;
1122                 break;
1123         case OP_LOADI8_MEMBASE:
1124                 ins->type = STACK_I8;
1125                 break;
1126         case OP_LOADR4_MEMBASE:
1127                 ins->type = cfg->r4_stack_type;
1128                 break;
1129         case OP_LOADR8_MEMBASE:
1130                 ins->type = STACK_R8;
1131                 break;
1132         default:
1133                 g_error ("opcode 0x%04x not handled in type from op", ins->opcode);
1134                 break;
1135         }
1136
1137         if (ins->type == STACK_MP)
1138                 ins->klass = mono_defaults.object_class;
1139 }
1140
1141 static const char 
1142 ldind_type [] = {
1143         STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_R8, STACK_OBJ
1144 };
1145
1146 #if 0
1147
1148 static const char
1149 param_table [STACK_MAX] [STACK_MAX] = {
1150         {0},
1151 };
1152
1153 static int
1154 check_values_to_signature (MonoInst *args, MonoType *this_ins, MonoMethodSignature *sig)
1155 {
1156         int i;
1157
1158         if (sig->hasthis) {
1159                 switch (args->type) {
1160                 case STACK_I4:
1161                 case STACK_I8:
1162                 case STACK_R8:
1163                 case STACK_VTYPE:
1164                 case STACK_INV:
1165                         return 0;
1166                 }
1167                 args++;
1168         }
1169         for (i = 0; i < sig->param_count; ++i) {
1170                 switch (args [i].type) {
1171                 case STACK_INV:
1172                         return 0;
1173                 case STACK_MP:
1174                         if (!sig->params [i]->byref)
1175                                 return 0;
1176                         continue;
1177                 case STACK_OBJ:
1178                         if (sig->params [i]->byref)
1179                                 return 0;
1180                         switch (sig->params [i]->type) {
1181                         case MONO_TYPE_CLASS:
1182                         case MONO_TYPE_STRING:
1183                         case MONO_TYPE_OBJECT:
1184                         case MONO_TYPE_SZARRAY:
1185                         case MONO_TYPE_ARRAY:
1186                                 break;
1187                         default:
1188                                 return 0;
1189                         }
1190                         continue;
1191                 case STACK_R8:
1192                         if (sig->params [i]->byref)
1193                                 return 0;
1194                         if (sig->params [i]->type != MONO_TYPE_R4 && sig->params [i]->type != MONO_TYPE_R8)
1195                                 return 0;
1196                         continue;
1197                 case STACK_PTR:
1198                 case STACK_I4:
1199                 case STACK_I8:
1200                 case STACK_VTYPE:
1201                         break;
1202                 }
1203                 /*if (!param_table [args [i].type] [sig->params [i]->type])
1204                         return 0;*/
1205         }
1206         return 1;
1207 }
1208 #endif
1209
1210 /*
1211  * When we need a pointer to the current domain many times in a method, we
1212  * call mono_domain_get() once and we store the result in a local variable.
1213  * This function returns the variable that represents the MonoDomain*.
1214  */
1215 inline static MonoInst *
1216 mono_get_domainvar (MonoCompile *cfg)
1217 {
1218         if (!cfg->domainvar)
1219                 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1220         return cfg->domainvar;
1221 }
1222
1223 /*
1224  * The got_var contains the address of the Global Offset Table when AOT 
1225  * compiling.
1226  */
1227 MonoInst *
1228 mono_get_got_var (MonoCompile *cfg)
1229 {
1230 #ifdef MONO_ARCH_NEED_GOT_VAR
1231         if (!cfg->compile_aot)
1232                 return NULL;
1233         if (!cfg->got_var) {
1234                 cfg->got_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1235         }
1236         return cfg->got_var;
1237 #else
1238         return NULL;
1239 #endif
1240 }
1241
1242 static MonoInst *
1243 mono_get_vtable_var (MonoCompile *cfg)
1244 {
1245         g_assert (cfg->gshared);
1246
1247         if (!cfg->rgctx_var) {
1248                 cfg->rgctx_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1249                 /* force the var to be stack allocated */
1250                 cfg->rgctx_var->flags |= MONO_INST_VOLATILE;
1251         }
1252
1253         return cfg->rgctx_var;
1254 }
1255
1256 static MonoType*
1257 type_from_stack_type (MonoInst *ins) {
1258         switch (ins->type) {
1259         case STACK_I4: return &mono_defaults.int32_class->byval_arg;
1260         case STACK_I8: return &mono_defaults.int64_class->byval_arg;
1261         case STACK_PTR: return &mono_defaults.int_class->byval_arg;
1262         case STACK_R4: return &mono_defaults.single_class->byval_arg;
1263         case STACK_R8: return &mono_defaults.double_class->byval_arg;
1264         case STACK_MP:
1265                 return &ins->klass->this_arg;
1266         case STACK_OBJ: return &mono_defaults.object_class->byval_arg;
1267         case STACK_VTYPE: return &ins->klass->byval_arg;
1268         default:
1269                 g_error ("stack type %d to monotype not handled\n", ins->type);
1270         }
1271         return NULL;
1272 }
1273
1274 static G_GNUC_UNUSED int
1275 type_to_stack_type (MonoCompile *cfg, MonoType *t)
1276 {
1277         t = mono_type_get_underlying_type (t);
1278         switch (t->type) {
1279         case MONO_TYPE_I1:
1280         case MONO_TYPE_U1:
1281         case MONO_TYPE_I2:
1282         case MONO_TYPE_U2:
1283         case MONO_TYPE_I4:
1284         case MONO_TYPE_U4:
1285                 return STACK_I4;
1286         case MONO_TYPE_I:
1287         case MONO_TYPE_U:
1288         case MONO_TYPE_PTR:
1289         case MONO_TYPE_FNPTR:
1290                 return STACK_PTR;
1291         case MONO_TYPE_CLASS:
1292         case MONO_TYPE_STRING:
1293         case MONO_TYPE_OBJECT:
1294         case MONO_TYPE_SZARRAY:
1295         case MONO_TYPE_ARRAY:    
1296                 return STACK_OBJ;
1297         case MONO_TYPE_I8:
1298         case MONO_TYPE_U8:
1299                 return STACK_I8;
1300         case MONO_TYPE_R4:
1301                 return cfg->r4_stack_type;
1302         case MONO_TYPE_R8:
1303                 return STACK_R8;
1304         case MONO_TYPE_VALUETYPE:
1305         case MONO_TYPE_TYPEDBYREF:
1306                 return STACK_VTYPE;
1307         case MONO_TYPE_GENERICINST:
1308                 if (mono_type_generic_inst_is_valuetype (t))
1309                         return STACK_VTYPE;
1310                 else
1311                         return STACK_OBJ;
1312                 break;
1313         default:
1314                 g_assert_not_reached ();
1315         }
1316
1317         return -1;
1318 }
1319
1320 static MonoClass*
1321 array_access_to_klass (int opcode)
1322 {
1323         switch (opcode) {
1324         case CEE_LDELEM_U1:
1325                 return mono_defaults.byte_class;
1326         case CEE_LDELEM_U2:
1327                 return mono_defaults.uint16_class;
1328         case CEE_LDELEM_I:
1329         case CEE_STELEM_I:
1330                 return mono_defaults.int_class;
1331         case CEE_LDELEM_I1:
1332         case CEE_STELEM_I1:
1333                 return mono_defaults.sbyte_class;
1334         case CEE_LDELEM_I2:
1335         case CEE_STELEM_I2:
1336                 return mono_defaults.int16_class;
1337         case CEE_LDELEM_I4:
1338         case CEE_STELEM_I4:
1339                 return mono_defaults.int32_class;
1340         case CEE_LDELEM_U4:
1341                 return mono_defaults.uint32_class;
1342         case CEE_LDELEM_I8:
1343         case CEE_STELEM_I8:
1344                 return mono_defaults.int64_class;
1345         case CEE_LDELEM_R4:
1346         case CEE_STELEM_R4:
1347                 return mono_defaults.single_class;
1348         case CEE_LDELEM_R8:
1349         case CEE_STELEM_R8:
1350                 return mono_defaults.double_class;
1351         case CEE_LDELEM_REF:
1352         case CEE_STELEM_REF:
1353                 return mono_defaults.object_class;
1354         default:
1355                 g_assert_not_reached ();
1356         }
1357         return NULL;
1358 }
1359
1360 /*
1361  * We try to share variables when possible
1362  */
1363 static MonoInst *
1364 mono_compile_get_interface_var (MonoCompile *cfg, int slot, MonoInst *ins)
1365 {
1366         MonoInst *res;
1367         int pos, vnum;
1368
1369         /* inlining can result in deeper stacks */ 
1370         if (slot >= cfg->header->max_stack)
1371                 return mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1372
1373         pos = ins->type - 1 + slot * STACK_MAX;
1374
1375         switch (ins->type) {
1376         case STACK_I4:
1377         case STACK_I8:
1378         case STACK_R8:
1379         case STACK_PTR:
1380         case STACK_MP:
1381         case STACK_OBJ:
1382                 if ((vnum = cfg->intvars [pos]))
1383                         return cfg->varinfo [vnum];
1384                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1385                 cfg->intvars [pos] = res->inst_c0;
1386                 break;
1387         default:
1388                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1389         }
1390         return res;
1391 }
1392
1393 static void
1394 mono_save_token_info (MonoCompile *cfg, MonoImage *image, guint32 token, gpointer key)
1395 {
1396         /* 
1397          * Don't use this if a generic_context is set, since that means AOT can't
1398          * look up the method using just the image+token.
1399          * table == 0 means this is a reference made from a wrapper.
1400          */
1401         if (cfg->compile_aot && !cfg->generic_context && (mono_metadata_token_table (token) > 0)) {
1402                 MonoJumpInfoToken *jump_info_token = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoToken));
1403                 jump_info_token->image = image;
1404                 jump_info_token->token = token;
1405                 g_hash_table_insert (cfg->token_info_hash, key, jump_info_token);
1406         }
1407 }
1408
1409 /*
1410  * This function is called to handle items that are left on the evaluation stack
1411  * at basic block boundaries. What happens is that we save the values to local variables
1412  * and we reload them later when first entering the target basic block (with the
1413  * handle_loaded_temps () function).
1414  * A single joint point will use the same variables (stored in the array bb->out_stack or
1415  * bb->in_stack, if the basic block is before or after the joint point).
1416  *
1417  * This function needs to be called _before_ emitting the last instruction of
1418  * the bb (i.e. before emitting a branch).
1419  * If the stack merge fails at a join point, cfg->unverifiable is set.
1420  */
1421 static void
1422 handle_stack_args (MonoCompile *cfg, MonoInst **sp, int count)
1423 {
1424         int i, bindex;
1425         MonoBasicBlock *bb = cfg->cbb;
1426         MonoBasicBlock *outb;
1427         MonoInst *inst, **locals;
1428         gboolean found;
1429
1430         if (!count)
1431                 return;
1432         if (cfg->verbose_level > 3)
1433                 printf ("%d item(s) on exit from B%d\n", count, bb->block_num);
1434         if (!bb->out_scount) {
1435                 bb->out_scount = count;
1436                 //printf ("bblock %d has out:", bb->block_num);
1437                 found = FALSE;
1438                 for (i = 0; i < bb->out_count; ++i) {
1439                         outb = bb->out_bb [i];
1440                         /* exception handlers are linked, but they should not be considered for stack args */
1441                         if (outb->flags & BB_EXCEPTION_HANDLER)
1442                                 continue;
1443                         //printf (" %d", outb->block_num);
1444                         if (outb->in_stack) {
1445                                 found = TRUE;
1446                                 bb->out_stack = outb->in_stack;
1447                                 break;
1448                         }
1449                 }
1450                 //printf ("\n");
1451                 if (!found) {
1452                         bb->out_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * count);
1453                         for (i = 0; i < count; ++i) {
1454                                 /* 
1455                                  * try to reuse temps already allocated for this purpouse, if they occupy the same
1456                                  * stack slot and if they are of the same type.
1457                                  * This won't cause conflicts since if 'local' is used to 
1458                                  * store one of the values in the in_stack of a bblock, then
1459                                  * the same variable will be used for the same outgoing stack 
1460                                  * slot as well. 
1461                                  * This doesn't work when inlining methods, since the bblocks
1462                                  * in the inlined methods do not inherit their in_stack from
1463                                  * the bblock they are inlined to. See bug #58863 for an
1464                                  * example.
1465                                  */
1466                                 if (cfg->inlined_method)
1467                                         bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
1468                                 else
1469                                         bb->out_stack [i] = mono_compile_get_interface_var (cfg, i, sp [i]);
1470                         }
1471                 }
1472         }
1473
1474         for (i = 0; i < bb->out_count; ++i) {
1475                 outb = bb->out_bb [i];
1476                 /* exception handlers are linked, but they should not be considered for stack args */
1477                 if (outb->flags & BB_EXCEPTION_HANDLER)
1478                         continue;
1479                 if (outb->in_scount) {
1480                         if (outb->in_scount != bb->out_scount) {
1481                                 cfg->unverifiable = TRUE;
1482                                 return;
1483                         }
1484                         continue; /* check they are the same locals */
1485                 }
1486                 outb->in_scount = count;
1487                 outb->in_stack = bb->out_stack;
1488         }
1489
1490         locals = bb->out_stack;
1491         cfg->cbb = bb;
1492         for (i = 0; i < count; ++i) {
1493                 EMIT_NEW_TEMPSTORE (cfg, inst, locals [i]->inst_c0, sp [i]);
1494                 inst->cil_code = sp [i]->cil_code;
1495                 sp [i] = locals [i];
1496                 if (cfg->verbose_level > 3)
1497                         printf ("storing %d to temp %d\n", i, (int)locals [i]->inst_c0);
1498         }
1499
1500         /*
1501          * It is possible that the out bblocks already have in_stack assigned, and
1502          * the in_stacks differ. In this case, we will store to all the different 
1503          * in_stacks.
1504          */
1505
1506         found = TRUE;
1507         bindex = 0;
1508         while (found) {
1509                 /* Find a bblock which has a different in_stack */
1510                 found = FALSE;
1511                 while (bindex < bb->out_count) {
1512                         outb = bb->out_bb [bindex];
1513                         /* exception handlers are linked, but they should not be considered for stack args */
1514                         if (outb->flags & BB_EXCEPTION_HANDLER) {
1515                                 bindex++;
1516                                 continue;
1517                         }
1518                         if (outb->in_stack != locals) {
1519                                 for (i = 0; i < count; ++i) {
1520                                         EMIT_NEW_TEMPSTORE (cfg, inst, outb->in_stack [i]->inst_c0, sp [i]);
1521                                         inst->cil_code = sp [i]->cil_code;
1522                                         sp [i] = locals [i];
1523                                         if (cfg->verbose_level > 3)
1524                                                 printf ("storing %d to temp %d\n", i, (int)outb->in_stack [i]->inst_c0);
1525                                 }
1526                                 locals = outb->in_stack;
1527                                 found = TRUE;
1528                                 break;
1529                         }
1530                         bindex ++;
1531                 }
1532         }
1533 }
1534
1535 static void
1536 mini_emit_interface_bitmap_check (MonoCompile *cfg, int intf_bit_reg, int base_reg, int offset, MonoClass *klass)
1537 {
1538         int ibitmap_reg = alloc_preg (cfg);
1539 #ifdef COMPRESSED_INTERFACE_BITMAP
1540         MonoInst *args [2];
1541         MonoInst *res, *ins;
1542         NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, ibitmap_reg, base_reg, offset);
1543         MONO_ADD_INS (cfg->cbb, ins);
1544         args [0] = ins;
1545         if (cfg->compile_aot)
1546                 EMIT_NEW_AOTCONST (cfg, args [1], MONO_PATCH_INFO_IID, klass);
1547         else
1548                 EMIT_NEW_ICONST (cfg, args [1], klass->interface_id);
1549         res = mono_emit_jit_icall (cfg, mono_class_interface_match, args);
1550         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, intf_bit_reg, res->dreg);
1551 #else
1552         int ibitmap_byte_reg = alloc_preg (cfg);
1553
1554         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, ibitmap_reg, base_reg, offset);
1555
1556         if (cfg->compile_aot) {
1557                 int iid_reg = alloc_preg (cfg);
1558                 int shifted_iid_reg = alloc_preg (cfg);
1559                 int ibitmap_byte_address_reg = alloc_preg (cfg);
1560                 int masked_iid_reg = alloc_preg (cfg);
1561                 int iid_one_bit_reg = alloc_preg (cfg);
1562                 int iid_bit_reg = alloc_preg (cfg);
1563                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1564                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, shifted_iid_reg, iid_reg, 3);
1565                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, ibitmap_byte_address_reg, ibitmap_reg, shifted_iid_reg);
1566                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, ibitmap_byte_reg, ibitmap_byte_address_reg, 0);
1567                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, masked_iid_reg, iid_reg, 7);
1568                 MONO_EMIT_NEW_ICONST (cfg, iid_one_bit_reg, 1);
1569                 MONO_EMIT_NEW_BIALU (cfg, OP_ISHL, iid_bit_reg, iid_one_bit_reg, masked_iid_reg);
1570                 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, intf_bit_reg, ibitmap_byte_reg, iid_bit_reg);
1571         } else {
1572                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, ibitmap_byte_reg, ibitmap_reg, klass->interface_id >> 3);
1573                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, intf_bit_reg, ibitmap_byte_reg, 1 << (klass->interface_id & 7));
1574         }
1575 #endif
1576 }
1577
1578 /* 
1579  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoClass
1580  * stored in "klass_reg" implements the interface "klass".
1581  */
1582 static void
1583 mini_emit_load_intf_bit_reg_class (MonoCompile *cfg, int intf_bit_reg, int klass_reg, MonoClass *klass)
1584 {
1585         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, interface_bitmap), klass);
1586 }
1587
1588 /* 
1589  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoVTable
1590  * stored in "vtable_reg" implements the interface "klass".
1591  */
1592 static void
1593 mini_emit_load_intf_bit_reg_vtable (MonoCompile *cfg, int intf_bit_reg, int vtable_reg, MonoClass *klass)
1594 {
1595         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, interface_bitmap), klass);
1596 }
1597
1598 /* 
1599  * Emit code which checks whenever the interface id of @klass is smaller than
1600  * than the value given by max_iid_reg.
1601 */
1602 static void
1603 mini_emit_max_iid_check (MonoCompile *cfg, int max_iid_reg, MonoClass *klass,
1604                                                  MonoBasicBlock *false_target)
1605 {
1606         if (cfg->compile_aot) {
1607                 int iid_reg = alloc_preg (cfg);
1608                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1609                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, max_iid_reg, iid_reg);
1610         }
1611         else
1612                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, max_iid_reg, klass->interface_id);
1613         if (false_target)
1614                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1615         else
1616                 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1617 }
1618
1619 /* Same as above, but obtains max_iid from a vtable */
1620 static void
1621 mini_emit_max_iid_check_vtable (MonoCompile *cfg, int vtable_reg, MonoClass *klass,
1622                                                                  MonoBasicBlock *false_target)
1623 {
1624         int max_iid_reg = alloc_preg (cfg);
1625                 
1626         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, max_interface_id));
1627         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1628 }
1629
1630 /* Same as above, but obtains max_iid from a klass */
1631 static void
1632 mini_emit_max_iid_check_class (MonoCompile *cfg, int klass_reg, MonoClass *klass,
1633                                                                  MonoBasicBlock *false_target)
1634 {
1635         int max_iid_reg = alloc_preg (cfg);
1636
1637         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, max_interface_id));
1638         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1639 }
1640
1641 static void
1642 mini_emit_isninst_cast_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_ins, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1643 {
1644         int idepth_reg = alloc_preg (cfg);
1645         int stypes_reg = alloc_preg (cfg);
1646         int stype = alloc_preg (cfg);
1647
1648         mono_class_setup_supertypes (klass);
1649
1650         if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1651                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth));
1652                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1653                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1654         }
1655         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes));
1656         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1657         if (klass_ins) {
1658                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, klass_ins->dreg);
1659         } else if (cfg->compile_aot) {
1660                 int const_reg = alloc_preg (cfg);
1661                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1662                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, const_reg);
1663         } else {
1664                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, stype, klass);
1665         }
1666         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, true_target);
1667 }
1668
1669 static void
1670 mini_emit_isninst_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1671 {
1672         mini_emit_isninst_cast_inst (cfg, klass_reg, klass, NULL, false_target, true_target);
1673 }
1674
1675 static void
1676 mini_emit_iface_cast (MonoCompile *cfg, int vtable_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1677 {
1678         int intf_reg = alloc_preg (cfg);
1679
1680         mini_emit_max_iid_check_vtable (cfg, vtable_reg, klass, false_target);
1681         mini_emit_load_intf_bit_reg_vtable (cfg, intf_reg, vtable_reg, klass);
1682         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_reg, 0);
1683         if (true_target)
1684                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1685         else
1686                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");               
1687 }
1688
1689 /*
1690  * Variant of the above that takes a register to the class, not the vtable.
1691  */
1692 static void
1693 mini_emit_iface_class_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1694 {
1695         int intf_bit_reg = alloc_preg (cfg);
1696
1697         mini_emit_max_iid_check_class (cfg, klass_reg, klass, false_target);
1698         mini_emit_load_intf_bit_reg_class (cfg, intf_bit_reg, klass_reg, klass);
1699         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_bit_reg, 0);
1700         if (true_target)
1701                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1702         else
1703                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
1704 }
1705
1706 static inline void
1707 mini_emit_class_check_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_inst)
1708 {
1709         if (klass_inst) {
1710                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_inst->dreg);
1711         } else if (cfg->compile_aot) {
1712                 int const_reg = alloc_preg (cfg);
1713                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1714                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, const_reg);
1715         } else {
1716                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
1717         }
1718         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1719 }
1720
1721 static inline void
1722 mini_emit_class_check (MonoCompile *cfg, int klass_reg, MonoClass *klass)
1723 {
1724         mini_emit_class_check_inst (cfg, klass_reg, klass, NULL);
1725 }
1726
1727 static inline void
1728 mini_emit_class_check_branch (MonoCompile *cfg, int klass_reg, MonoClass *klass, int branch_op, MonoBasicBlock *target)
1729 {
1730         if (cfg->compile_aot) {
1731                 int const_reg = alloc_preg (cfg);
1732                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1733                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, const_reg);
1734         } else {
1735                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
1736         }
1737         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, branch_op, target);
1738 }
1739
1740 static void
1741 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null);
1742         
1743 static void
1744 mini_emit_castclass_inst (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoInst *klass_inst, MonoBasicBlock *object_is_null)
1745 {
1746         if (klass->rank) {
1747                 int rank_reg = alloc_preg (cfg);
1748                 int eclass_reg = alloc_preg (cfg);
1749
1750                 g_assert (!klass_inst);
1751                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, rank));
1752                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
1753                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1754                 //              MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
1755                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
1756                 if (klass->cast_class == mono_defaults.object_class) {
1757                         int parent_reg = alloc_preg (cfg);
1758                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
1759                         mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, object_is_null);
1760                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1761                 } else if (klass->cast_class == mono_defaults.enum_class->parent) {
1762                         mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, object_is_null);
1763                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1764                 } else if (klass->cast_class == mono_defaults.enum_class) {
1765                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1766                 } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1767                         mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, NULL, NULL);
1768                 } else {
1769                         // Pass -1 as obj_reg to skip the check below for arrays of arrays
1770                         mini_emit_castclass (cfg, -1, eclass_reg, klass->cast_class, object_is_null);
1771                 }
1772
1773                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY) && (obj_reg != -1)) {
1774                         /* Check that the object is a vector too */
1775                         int bounds_reg = alloc_preg (cfg);
1776                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
1777                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
1778                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1779                 }
1780         } else {
1781                 int idepth_reg = alloc_preg (cfg);
1782                 int stypes_reg = alloc_preg (cfg);
1783                 int stype = alloc_preg (cfg);
1784
1785                 mono_class_setup_supertypes (klass);
1786
1787                 if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1788                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth));
1789                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1790                         MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1791                 }
1792                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes));
1793                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1794                 mini_emit_class_check_inst (cfg, stype, klass, klass_inst);
1795         }
1796 }
1797
1798 static void
1799 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null)
1800 {
1801         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, NULL, object_is_null);
1802 }
1803
1804 static void 
1805 mini_emit_memset (MonoCompile *cfg, int destreg, int offset, int size, int val, int align)
1806 {
1807         int val_reg;
1808
1809         g_assert (val == 0);
1810
1811         if (align == 0)
1812                 align = 4;
1813
1814         if ((size <= SIZEOF_REGISTER) && (size <= align)) {
1815                 switch (size) {
1816                 case 1:
1817                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, destreg, offset, val);
1818                         return;
1819                 case 2:
1820                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI2_MEMBASE_IMM, destreg, offset, val);
1821                         return;
1822                 case 4:
1823                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI4_MEMBASE_IMM, destreg, offset, val);
1824                         return;
1825 #if SIZEOF_REGISTER == 8
1826                 case 8:
1827                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI8_MEMBASE_IMM, destreg, offset, val);
1828                         return;
1829 #endif
1830                 }
1831         }
1832
1833         val_reg = alloc_preg (cfg);
1834
1835         if (SIZEOF_REGISTER == 8)
1836                 MONO_EMIT_NEW_I8CONST (cfg, val_reg, val);
1837         else
1838                 MONO_EMIT_NEW_ICONST (cfg, val_reg, val);
1839
1840         if (align < 4) {
1841                 /* This could be optimized further if neccesary */
1842                 while (size >= 1) {
1843                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1844                         offset += 1;
1845                         size -= 1;
1846                 }
1847                 return;
1848         }       
1849
1850 #if !NO_UNALIGNED_ACCESS
1851         if (SIZEOF_REGISTER == 8) {
1852                 if (offset % 8) {
1853                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1854                         offset += 4;
1855                         size -= 4;
1856                 }
1857                 while (size >= 8) {
1858                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, offset, val_reg);
1859                         offset += 8;
1860                         size -= 8;
1861                 }
1862         }       
1863 #endif
1864
1865         while (size >= 4) {
1866                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1867                 offset += 4;
1868                 size -= 4;
1869         }
1870         while (size >= 2) {
1871                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, val_reg);
1872                 offset += 2;
1873                 size -= 2;
1874         }
1875         while (size >= 1) {
1876                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1877                 offset += 1;
1878                 size -= 1;
1879         }
1880 }
1881
1882 void 
1883 mini_emit_memcpy (MonoCompile *cfg, int destreg, int doffset, int srcreg, int soffset, int size, int align)
1884 {
1885         int cur_reg;
1886
1887         if (align == 0)
1888                 align = 4;
1889
1890         /*FIXME arbitrary hack to avoid unbound code expansion.*/
1891         g_assert (size < 10000);
1892
1893         if (align < 4) {
1894                 /* This could be optimized further if neccesary */
1895                 while (size >= 1) {
1896                         cur_reg = alloc_preg (cfg);
1897                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1898                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1899                         doffset += 1;
1900                         soffset += 1;
1901                         size -= 1;
1902                 }
1903         }
1904
1905 #if !NO_UNALIGNED_ACCESS
1906         if (SIZEOF_REGISTER == 8) {
1907                 while (size >= 8) {
1908                         cur_reg = alloc_preg (cfg);
1909                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI8_MEMBASE, cur_reg, srcreg, soffset);
1910                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, doffset, cur_reg);
1911                         doffset += 8;
1912                         soffset += 8;
1913                         size -= 8;
1914                 }
1915         }       
1916 #endif
1917
1918         while (size >= 4) {
1919                 cur_reg = alloc_preg (cfg);
1920                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, cur_reg, srcreg, soffset);
1921                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, doffset, cur_reg);
1922                 doffset += 4;
1923                 soffset += 4;
1924                 size -= 4;
1925         }
1926         while (size >= 2) {
1927                 cur_reg = alloc_preg (cfg);
1928                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, cur_reg, srcreg, soffset);
1929                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, doffset, cur_reg);
1930                 doffset += 2;
1931                 soffset += 2;
1932                 size -= 2;
1933         }
1934         while (size >= 1) {
1935                 cur_reg = alloc_preg (cfg);
1936                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1937                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1938                 doffset += 1;
1939                 soffset += 1;
1940                 size -= 1;
1941         }
1942 }
1943
1944 static void
1945 emit_tls_set (MonoCompile *cfg, int sreg1, int tls_key)
1946 {
1947         MonoInst *ins, *c;
1948
1949         if (cfg->compile_aot) {
1950                 EMIT_NEW_TLS_OFFSETCONST (cfg, c, tls_key);
1951                 MONO_INST_NEW (cfg, ins, OP_TLS_SET_REG);
1952                 ins->sreg1 = sreg1;
1953                 ins->sreg2 = c->dreg;
1954                 MONO_ADD_INS (cfg->cbb, ins);
1955         } else {
1956                 MONO_INST_NEW (cfg, ins, OP_TLS_SET);
1957                 ins->sreg1 = sreg1;
1958                 ins->inst_offset = mini_get_tls_offset (tls_key);
1959                 MONO_ADD_INS (cfg->cbb, ins);
1960         }
1961 }
1962
1963 /*
1964  * emit_push_lmf:
1965  *
1966  *   Emit IR to push the current LMF onto the LMF stack.
1967  */
1968 static void
1969 emit_push_lmf (MonoCompile *cfg)
1970 {
1971         /*
1972          * Emit IR to push the LMF:
1973          * lmf_addr = <lmf_addr from tls>
1974          * lmf->lmf_addr = lmf_addr
1975          * lmf->prev_lmf = *lmf_addr
1976          * *lmf_addr = lmf
1977          */
1978         int lmf_reg, prev_lmf_reg;
1979         MonoInst *ins, *lmf_ins;
1980
1981         if (!cfg->lmf_ir)
1982                 return;
1983
1984         if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
1985                 /* Load current lmf */
1986                 lmf_ins = mono_get_lmf_intrinsic (cfg);
1987                 g_assert (lmf_ins);
1988                 MONO_ADD_INS (cfg->cbb, lmf_ins);
1989                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
1990                 lmf_reg = ins->dreg;
1991                 /* Save previous_lmf */
1992                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), lmf_ins->dreg);
1993                 /* Set new LMF */
1994                 emit_tls_set (cfg, lmf_reg, TLS_KEY_LMF);
1995         } else {
1996                 /*
1997                  * Store lmf_addr in a variable, so it can be allocated to a global register.
1998                  */
1999                 if (!cfg->lmf_addr_var)
2000                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2001
2002 #ifdef HOST_WIN32
2003                 ins = mono_get_jit_tls_intrinsic (cfg);
2004                 if (ins) {
2005                         int jit_tls_dreg = ins->dreg;
2006
2007                         MONO_ADD_INS (cfg->cbb, ins);
2008                         lmf_reg = alloc_preg (cfg);
2009                         EMIT_NEW_BIALU_IMM (cfg, lmf_ins, OP_PADD_IMM, lmf_reg, jit_tls_dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, lmf));
2010                 } else {
2011                         lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
2012                 }
2013 #else
2014                 lmf_ins = mono_get_lmf_addr_intrinsic (cfg);
2015                 if (lmf_ins) {
2016                         MONO_ADD_INS (cfg->cbb, lmf_ins);
2017                 } else {
2018 #ifdef TARGET_IOS
2019                         MonoInst *args [16], *jit_tls_ins, *ins;
2020
2021                         /* Inline mono_get_lmf_addr () */
2022                         /* jit_tls = pthread_getspecific (mono_jit_tls_id); lmf_addr = &jit_tls->lmf; */
2023
2024                         /* Load mono_jit_tls_id */
2025                         if (cfg->compile_aot)
2026                                 EMIT_NEW_AOTCONST (cfg, args [0], MONO_PATCH_INFO_JIT_TLS_ID, NULL);
2027                         else
2028                                 EMIT_NEW_ICONST (cfg, args [0], mono_jit_tls_id);
2029                         /* call pthread_getspecific () */
2030                         jit_tls_ins = mono_emit_jit_icall (cfg, pthread_getspecific, args);
2031                         /* lmf_addr = &jit_tls->lmf */
2032                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, cfg->lmf_addr_var->dreg, jit_tls_ins->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, lmf));
2033                         lmf_ins = ins;
2034 #else
2035                         lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
2036 #endif
2037                 }
2038 #endif
2039                 lmf_ins->dreg = cfg->lmf_addr_var->dreg;
2040
2041                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2042                 lmf_reg = ins->dreg;
2043
2044                 prev_lmf_reg = alloc_preg (cfg);
2045                 /* Save previous_lmf */
2046                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, cfg->lmf_addr_var->dreg, 0);
2047                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), prev_lmf_reg);
2048                 /* Set new lmf */
2049                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, cfg->lmf_addr_var->dreg, 0, lmf_reg);
2050         }
2051 }
2052
2053 /*
2054  * emit_pop_lmf:
2055  *
2056  *   Emit IR to pop the current LMF from the LMF stack.
2057  */
2058 static void
2059 emit_pop_lmf (MonoCompile *cfg)
2060 {
2061         int lmf_reg, lmf_addr_reg, prev_lmf_reg;
2062         MonoInst *ins;
2063
2064         if (!cfg->lmf_ir)
2065                 return;
2066
2067         EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2068         lmf_reg = ins->dreg;
2069
2070         if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
2071                 /* Load previous_lmf */
2072                 prev_lmf_reg = alloc_preg (cfg);
2073                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
2074                 /* Set new LMF */
2075                 emit_tls_set (cfg, prev_lmf_reg, TLS_KEY_LMF);
2076         } else {
2077                 /*
2078                  * Emit IR to pop the LMF:
2079                  * *(lmf->lmf_addr) = lmf->prev_lmf
2080                  */
2081                 /* This could be called before emit_push_lmf () */
2082                 if (!cfg->lmf_addr_var)
2083                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2084                 lmf_addr_reg = cfg->lmf_addr_var->dreg;
2085
2086                 prev_lmf_reg = alloc_preg (cfg);
2087                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
2088                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_addr_reg, 0, prev_lmf_reg);
2089         }
2090 }
2091
2092 static void
2093 emit_instrumentation_call (MonoCompile *cfg, void *func)
2094 {
2095         MonoInst *iargs [1];
2096
2097         /*
2098          * Avoid instrumenting inlined methods since it can
2099          * distort profiling results.
2100          */
2101         if (cfg->method != cfg->current_method)
2102                 return;
2103
2104         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE) {
2105                 EMIT_NEW_METHODCONST (cfg, iargs [0], cfg->method);
2106                 mono_emit_jit_icall (cfg, func, iargs);
2107         }
2108 }
2109
2110 static int
2111 ret_type_to_call_opcode (MonoCompile *cfg, MonoType *type, int calli, int virt)
2112 {
2113 handle_enum:
2114         type = mini_get_underlying_type (type);
2115         switch (type->type) {
2116         case MONO_TYPE_VOID:
2117                 return calli? OP_VOIDCALL_REG: virt? OP_VOIDCALL_MEMBASE: OP_VOIDCALL;
2118         case MONO_TYPE_I1:
2119         case MONO_TYPE_U1:
2120         case MONO_TYPE_I2:
2121         case MONO_TYPE_U2:
2122         case MONO_TYPE_I4:
2123         case MONO_TYPE_U4:
2124                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2125         case MONO_TYPE_I:
2126         case MONO_TYPE_U:
2127         case MONO_TYPE_PTR:
2128         case MONO_TYPE_FNPTR:
2129                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2130         case MONO_TYPE_CLASS:
2131         case MONO_TYPE_STRING:
2132         case MONO_TYPE_OBJECT:
2133         case MONO_TYPE_SZARRAY:
2134         case MONO_TYPE_ARRAY:    
2135                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2136         case MONO_TYPE_I8:
2137         case MONO_TYPE_U8:
2138                 return calli? OP_LCALL_REG: virt? OP_LCALL_MEMBASE: OP_LCALL;
2139         case MONO_TYPE_R4:
2140                 if (cfg->r4fp)
2141                         return calli? OP_RCALL_REG: virt? OP_RCALL_MEMBASE: OP_RCALL;
2142                 else
2143                         return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
2144         case MONO_TYPE_R8:
2145                 return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
2146         case MONO_TYPE_VALUETYPE:
2147                 if (type->data.klass->enumtype) {
2148                         type = mono_class_enum_basetype (type->data.klass);
2149                         goto handle_enum;
2150                 } else
2151                         return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2152         case MONO_TYPE_TYPEDBYREF:
2153                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2154         case MONO_TYPE_GENERICINST:
2155                 type = &type->data.generic_class->container_class->byval_arg;
2156                 goto handle_enum;
2157         case MONO_TYPE_VAR:
2158         case MONO_TYPE_MVAR:
2159                 /* gsharedvt */
2160                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2161         default:
2162                 g_error ("unknown type 0x%02x in ret_type_to_call_opcode", type->type);
2163         }
2164         return -1;
2165 }
2166
2167 /*
2168  * target_type_is_incompatible:
2169  * @cfg: MonoCompile context
2170  *
2171  * Check that the item @arg on the evaluation stack can be stored
2172  * in the target type (can be a local, or field, etc).
2173  * The cfg arg can be used to check if we need verification or just
2174  * validity checks.
2175  *
2176  * Returns: non-0 value if arg can't be stored on a target.
2177  */
2178 static int
2179 target_type_is_incompatible (MonoCompile *cfg, MonoType *target, MonoInst *arg)
2180 {
2181         MonoType *simple_type;
2182         MonoClass *klass;
2183
2184         if (target->byref) {
2185                 /* FIXME: check that the pointed to types match */
2186                 if (arg->type == STACK_MP)
2187                         return arg->klass != mono_class_from_mono_type (target);
2188                 if (arg->type == STACK_PTR)
2189                         return 0;
2190                 return 1;
2191         }
2192
2193         simple_type = mini_get_underlying_type (target);
2194         switch (simple_type->type) {
2195         case MONO_TYPE_VOID:
2196                 return 1;
2197         case MONO_TYPE_I1:
2198         case MONO_TYPE_U1:
2199         case MONO_TYPE_I2:
2200         case MONO_TYPE_U2:
2201         case MONO_TYPE_I4:
2202         case MONO_TYPE_U4:
2203                 if (arg->type != STACK_I4 && arg->type != STACK_PTR)
2204                         return 1;
2205                 return 0;
2206         case MONO_TYPE_PTR:
2207                 /* STACK_MP is needed when setting pinned locals */
2208                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2209                         return 1;
2210                 return 0;
2211         case MONO_TYPE_I:
2212         case MONO_TYPE_U:
2213         case MONO_TYPE_FNPTR:
2214                 /* 
2215                  * Some opcodes like ldloca returns 'transient pointers' which can be stored in
2216                  * in native int. (#688008).
2217                  */
2218                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2219                         return 1;
2220                 return 0;
2221         case MONO_TYPE_CLASS:
2222         case MONO_TYPE_STRING:
2223         case MONO_TYPE_OBJECT:
2224         case MONO_TYPE_SZARRAY:
2225         case MONO_TYPE_ARRAY:    
2226                 if (arg->type != STACK_OBJ)
2227                         return 1;
2228                 /* FIXME: check type compatibility */
2229                 return 0;
2230         case MONO_TYPE_I8:
2231         case MONO_TYPE_U8:
2232                 if (arg->type != STACK_I8)
2233                         return 1;
2234                 return 0;
2235         case MONO_TYPE_R4:
2236                 if (arg->type != cfg->r4_stack_type)
2237                         return 1;
2238                 return 0;
2239         case MONO_TYPE_R8:
2240                 if (arg->type != STACK_R8)
2241                         return 1;
2242                 return 0;
2243         case MONO_TYPE_VALUETYPE:
2244                 if (arg->type != STACK_VTYPE)
2245                         return 1;
2246                 klass = mono_class_from_mono_type (simple_type);
2247                 if (klass != arg->klass)
2248                         return 1;
2249                 return 0;
2250         case MONO_TYPE_TYPEDBYREF:
2251                 if (arg->type != STACK_VTYPE)
2252                         return 1;
2253                 klass = mono_class_from_mono_type (simple_type);
2254                 if (klass != arg->klass)
2255                         return 1;
2256                 return 0;
2257         case MONO_TYPE_GENERICINST:
2258                 if (mono_type_generic_inst_is_valuetype (simple_type)) {
2259                         if (arg->type != STACK_VTYPE)
2260                                 return 1;
2261                         klass = mono_class_from_mono_type (simple_type);
2262                         /* The second cases is needed when doing partial sharing */
2263                         if (klass != arg->klass && mono_class_from_mono_type (target) != arg->klass)
2264                                 return 1;
2265                         return 0;
2266                 } else {
2267                         if (arg->type != STACK_OBJ)
2268                                 return 1;
2269                         /* FIXME: check type compatibility */
2270                         return 0;
2271                 }
2272         case MONO_TYPE_VAR:
2273         case MONO_TYPE_MVAR:
2274                 g_assert (cfg->gshared);
2275                 if (mini_type_var_is_vt (simple_type)) {
2276                         if (arg->type != STACK_VTYPE)
2277                                 return 1;
2278                 } else {
2279                         if (arg->type != STACK_OBJ)
2280                                 return 1;
2281                 }
2282                 return 0;
2283         default:
2284                 g_error ("unknown type 0x%02x in target_type_is_incompatible", simple_type->type);
2285         }
2286         return 1;
2287 }
2288
2289 /*
2290  * Prepare arguments for passing to a function call.
2291  * Return a non-zero value if the arguments can't be passed to the given
2292  * signature.
2293  * The type checks are not yet complete and some conversions may need
2294  * casts on 32 or 64 bit architectures.
2295  *
2296  * FIXME: implement this using target_type_is_incompatible ()
2297  */
2298 static int
2299 check_call_signature (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args)
2300 {
2301         MonoType *simple_type;
2302         int i;
2303
2304         if (sig->hasthis) {
2305                 if (args [0]->type != STACK_OBJ && args [0]->type != STACK_MP && args [0]->type != STACK_PTR)
2306                         return 1;
2307                 args++;
2308         }
2309         for (i = 0; i < sig->param_count; ++i) {
2310                 if (sig->params [i]->byref) {
2311                         if (args [i]->type != STACK_MP && args [i]->type != STACK_PTR)
2312                                 return 1;
2313                         continue;
2314                 }
2315                 simple_type = mini_get_underlying_type (sig->params [i]);
2316 handle_enum:
2317                 switch (simple_type->type) {
2318                 case MONO_TYPE_VOID:
2319                         return 1;
2320                         continue;
2321                 case MONO_TYPE_I1:
2322                 case MONO_TYPE_U1:
2323                 case MONO_TYPE_I2:
2324                 case MONO_TYPE_U2:
2325                 case MONO_TYPE_I4:
2326                 case MONO_TYPE_U4:
2327                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR)
2328                                 return 1;
2329                         continue;
2330                 case MONO_TYPE_I:
2331                 case MONO_TYPE_U:
2332                 case MONO_TYPE_PTR:
2333                 case MONO_TYPE_FNPTR:
2334                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR && args [i]->type != STACK_MP && args [i]->type != STACK_OBJ)
2335                                 return 1;
2336                         continue;
2337                 case MONO_TYPE_CLASS:
2338                 case MONO_TYPE_STRING:
2339                 case MONO_TYPE_OBJECT:
2340                 case MONO_TYPE_SZARRAY:
2341                 case MONO_TYPE_ARRAY:    
2342                         if (args [i]->type != STACK_OBJ)
2343                                 return 1;
2344                         continue;
2345                 case MONO_TYPE_I8:
2346                 case MONO_TYPE_U8:
2347                         if (args [i]->type != STACK_I8)
2348                                 return 1;
2349                         continue;
2350                 case MONO_TYPE_R4:
2351                         if (args [i]->type != cfg->r4_stack_type)
2352                                 return 1;
2353                         continue;
2354                 case MONO_TYPE_R8:
2355                         if (args [i]->type != STACK_R8)
2356                                 return 1;
2357                         continue;
2358                 case MONO_TYPE_VALUETYPE:
2359                         if (simple_type->data.klass->enumtype) {
2360                                 simple_type = mono_class_enum_basetype (simple_type->data.klass);
2361                                 goto handle_enum;
2362                         }
2363                         if (args [i]->type != STACK_VTYPE)
2364                                 return 1;
2365                         continue;
2366                 case MONO_TYPE_TYPEDBYREF:
2367                         if (args [i]->type != STACK_VTYPE)
2368                                 return 1;
2369                         continue;
2370                 case MONO_TYPE_GENERICINST:
2371                         simple_type = &simple_type->data.generic_class->container_class->byval_arg;
2372                         goto handle_enum;
2373                 case MONO_TYPE_VAR:
2374                 case MONO_TYPE_MVAR:
2375                         /* gsharedvt */
2376                         if (args [i]->type != STACK_VTYPE)
2377                                 return 1;
2378                         continue;
2379                 default:
2380                         g_error ("unknown type 0x%02x in check_call_signature",
2381                                  simple_type->type);
2382                 }
2383         }
2384         return 0;
2385 }
2386
2387 static int
2388 callvirt_to_call (int opcode)
2389 {
2390         switch (opcode) {
2391         case OP_CALL_MEMBASE:
2392                 return OP_CALL;
2393         case OP_VOIDCALL_MEMBASE:
2394                 return OP_VOIDCALL;
2395         case OP_FCALL_MEMBASE:
2396                 return OP_FCALL;
2397         case OP_RCALL_MEMBASE:
2398                 return OP_RCALL;
2399         case OP_VCALL_MEMBASE:
2400                 return OP_VCALL;
2401         case OP_LCALL_MEMBASE:
2402                 return OP_LCALL;
2403         default:
2404                 g_assert_not_reached ();
2405         }
2406
2407         return -1;
2408 }
2409
2410 static int
2411 callvirt_to_call_reg (int opcode)
2412 {
2413         switch (opcode) {
2414         case OP_CALL_MEMBASE:
2415                 return OP_CALL_REG;
2416         case OP_VOIDCALL_MEMBASE:
2417                 return OP_VOIDCALL_REG;
2418         case OP_FCALL_MEMBASE:
2419                 return OP_FCALL_REG;
2420         case OP_RCALL_MEMBASE:
2421                 return OP_RCALL_REG;
2422         case OP_VCALL_MEMBASE:
2423                 return OP_VCALL_REG;
2424         case OP_LCALL_MEMBASE:
2425                 return OP_LCALL_REG;
2426         default:
2427                 g_assert_not_reached ();
2428         }
2429
2430         return -1;
2431 }
2432
2433 /* Either METHOD or IMT_ARG needs to be set */
2434 static void
2435 emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoMethod *method, MonoInst *imt_arg)
2436 {
2437         int method_reg;
2438
2439         if (COMPILE_LLVM (cfg)) {
2440                 method_reg = alloc_preg (cfg);
2441
2442                 if (imt_arg) {
2443                         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2444                 } else if (cfg->compile_aot) {
2445                         MONO_EMIT_NEW_AOTCONST (cfg, method_reg, method, MONO_PATCH_INFO_METHODCONST);
2446                 } else {
2447                         MonoInst *ins;
2448                         MONO_INST_NEW (cfg, ins, OP_PCONST);
2449                         ins->inst_p0 = method;
2450                         ins->dreg = method_reg;
2451                         MONO_ADD_INS (cfg->cbb, ins);
2452                 }
2453
2454 #ifdef ENABLE_LLVM
2455                 call->imt_arg_reg = method_reg;
2456 #endif
2457         mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2458                 return;
2459         }
2460
2461         method_reg = alloc_preg (cfg);
2462
2463         if (imt_arg) {
2464                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2465         } else if (cfg->compile_aot) {
2466                 MONO_EMIT_NEW_AOTCONST (cfg, method_reg, method, MONO_PATCH_INFO_METHODCONST);
2467         } else {
2468                 MonoInst *ins;
2469                 MONO_INST_NEW (cfg, ins, OP_PCONST);
2470                 ins->inst_p0 = method;
2471                 ins->dreg = method_reg;
2472                 MONO_ADD_INS (cfg->cbb, ins);
2473         }
2474
2475         mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2476 }
2477
2478 static MonoJumpInfo *
2479 mono_patch_info_new (MonoMemPool *mp, int ip, MonoJumpInfoType type, gconstpointer target)
2480 {
2481         MonoJumpInfo *ji = mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
2482
2483         ji->ip.i = ip;
2484         ji->type = type;
2485         ji->data.target = target;
2486
2487         return ji;
2488 }
2489
2490 static int
2491 mini_class_check_context_used (MonoCompile *cfg, MonoClass *klass)
2492 {
2493         if (cfg->gshared)
2494                 return mono_class_check_context_used (klass);
2495         else
2496                 return 0;
2497 }
2498
2499 static int
2500 mini_method_check_context_used (MonoCompile *cfg, MonoMethod *method)
2501 {
2502         if (cfg->gshared)
2503                 return mono_method_check_context_used (method);
2504         else
2505                 return 0;
2506 }
2507
2508 /*
2509  * check_method_sharing:
2510  *
2511  *   Check whenever the vtable or an mrgctx needs to be passed when calling CMETHOD.
2512  */
2513 static void
2514 check_method_sharing (MonoCompile *cfg, MonoMethod *cmethod, gboolean *out_pass_vtable, gboolean *out_pass_mrgctx)
2515 {
2516         gboolean pass_vtable = FALSE;
2517         gboolean pass_mrgctx = FALSE;
2518
2519         if (((cmethod->flags & METHOD_ATTRIBUTE_STATIC) || cmethod->klass->valuetype) &&
2520                 (cmethod->klass->generic_class || cmethod->klass->generic_container)) {
2521                 gboolean sharable = FALSE;
2522
2523                 if (mono_method_is_generic_sharable_full (cmethod, TRUE, TRUE, TRUE))
2524                         sharable = TRUE;
2525
2526                 /*
2527                  * Pass vtable iff target method might
2528                  * be shared, which means that sharing
2529                  * is enabled for its class and its
2530                  * context is sharable (and it's not a
2531                  * generic method).
2532                  */
2533                 if (sharable && !(mini_method_get_context (cmethod) && mini_method_get_context (cmethod)->method_inst))
2534                         pass_vtable = TRUE;
2535         }
2536
2537         if (mini_method_get_context (cmethod) &&
2538                 mini_method_get_context (cmethod)->method_inst) {
2539                 g_assert (!pass_vtable);
2540
2541                 if (mono_method_is_generic_sharable_full (cmethod, TRUE, TRUE, TRUE)) {
2542                         pass_mrgctx = TRUE;
2543                 } else {
2544                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (mono_method_signature (cmethod)))
2545                                 pass_mrgctx = TRUE;
2546                 }
2547         }
2548
2549         if (out_pass_vtable)
2550                 *out_pass_vtable = pass_vtable;
2551         if (out_pass_mrgctx)
2552                 *out_pass_mrgctx = pass_mrgctx;
2553 }
2554
2555 inline static MonoCallInst *
2556 mono_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig, 
2557                                          MonoInst **args, int calli, int virtual, int tail, int rgctx, int unbox_trampoline)
2558 {
2559         MonoType *sig_ret;
2560         MonoCallInst *call;
2561 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2562         int i;
2563 #endif
2564
2565         if (cfg->llvm_only)
2566                 tail = FALSE;
2567
2568         if (tail) {
2569                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
2570
2571                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
2572         } else
2573                 MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (cfg, sig->ret, calli, virtual));
2574
2575         call->args = args;
2576         call->signature = sig;
2577         call->rgctx_reg = rgctx;
2578         sig_ret = mini_get_underlying_type (sig->ret);
2579
2580         type_to_eval_stack_type ((cfg), sig_ret, &call->inst);
2581
2582         if (tail) {
2583                 if (mini_type_is_vtype (sig_ret)) {
2584                         call->vret_var = cfg->vret_addr;
2585                         //g_assert_not_reached ();
2586                 }
2587         } else if (mini_type_is_vtype (sig_ret)) {
2588                 MonoInst *temp = mono_compile_create_var (cfg, sig_ret, OP_LOCAL);
2589                 MonoInst *loada;
2590
2591                 temp->backend.is_pinvoke = sig->pinvoke;
2592
2593                 /*
2594                  * We use a new opcode OP_OUTARG_VTRETADDR instead of LDADDR for emitting the
2595                  * address of return value to increase optimization opportunities.
2596                  * Before vtype decomposition, the dreg of the call ins itself represents the
2597                  * fact the call modifies the return value. After decomposition, the call will
2598                  * be transformed into one of the OP_VOIDCALL opcodes, and the VTRETADDR opcode
2599                  * will be transformed into an LDADDR.
2600                  */
2601                 MONO_INST_NEW (cfg, loada, OP_OUTARG_VTRETADDR);
2602                 loada->dreg = alloc_preg (cfg);
2603                 loada->inst_p0 = temp;
2604                 /* We reference the call too since call->dreg could change during optimization */
2605                 loada->inst_p1 = call;
2606                 MONO_ADD_INS (cfg->cbb, loada);
2607
2608                 call->inst.dreg = temp->dreg;
2609
2610                 call->vret_var = loada;
2611         } else if (!MONO_TYPE_IS_VOID (sig_ret))
2612                 call->inst.dreg = alloc_dreg (cfg, call->inst.type);
2613
2614 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2615         if (COMPILE_SOFT_FLOAT (cfg)) {
2616                 /* 
2617                  * If the call has a float argument, we would need to do an r8->r4 conversion using 
2618                  * an icall, but that cannot be done during the call sequence since it would clobber
2619                  * the call registers + the stack. So we do it before emitting the call.
2620                  */
2621                 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2622                         MonoType *t;
2623                         MonoInst *in = call->args [i];
2624
2625                         if (i >= sig->hasthis)
2626                                 t = sig->params [i - sig->hasthis];
2627                         else
2628                                 t = &mono_defaults.int_class->byval_arg;
2629                         t = mono_type_get_underlying_type (t);
2630
2631                         if (!t->byref && t->type == MONO_TYPE_R4) {
2632                                 MonoInst *iargs [1];
2633                                 MonoInst *conv;
2634
2635                                 iargs [0] = in;
2636                                 conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
2637
2638                                 /* The result will be in an int vreg */
2639                                 call->args [i] = conv;
2640                         }
2641                 }
2642         }
2643 #endif
2644
2645         call->need_unbox_trampoline = unbox_trampoline;
2646
2647 #ifdef ENABLE_LLVM
2648         if (COMPILE_LLVM (cfg))
2649                 mono_llvm_emit_call (cfg, call);
2650         else
2651                 mono_arch_emit_call (cfg, call);
2652 #else
2653         mono_arch_emit_call (cfg, call);
2654 #endif
2655
2656         cfg->param_area = MAX (cfg->param_area, call->stack_usage);
2657         cfg->flags |= MONO_CFG_HAS_CALLS;
2658         
2659         return call;
2660 }
2661
2662 static void
2663 set_rgctx_arg (MonoCompile *cfg, MonoCallInst *call, int rgctx_reg, MonoInst *rgctx_arg)
2664 {
2665 #ifdef MONO_ARCH_RGCTX_REG
2666         mono_call_inst_add_outarg_reg (cfg, call, rgctx_reg, MONO_ARCH_RGCTX_REG, FALSE);
2667         cfg->uses_rgctx_reg = TRUE;
2668         call->rgctx_reg = TRUE;
2669 #ifdef ENABLE_LLVM
2670         call->rgctx_arg_reg = rgctx_reg;
2671 #endif
2672 #else
2673         NOT_IMPLEMENTED;
2674 #endif
2675 }       
2676
2677 inline static MonoInst*
2678 mono_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr, MonoInst *imt_arg, MonoInst *rgctx_arg)
2679 {
2680         MonoCallInst *call;
2681         MonoInst *ins;
2682         int rgctx_reg = -1;
2683         gboolean check_sp = FALSE;
2684
2685         if (cfg->check_pinvoke_callconv && cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
2686                 WrapperInfo *info = mono_marshal_get_wrapper_info (cfg->method);
2687
2688                 if (info && info->subtype == WRAPPER_SUBTYPE_PINVOKE)
2689                         check_sp = TRUE;
2690         }
2691
2692         if (rgctx_arg) {
2693                 rgctx_reg = mono_alloc_preg (cfg);
2694                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2695         }
2696
2697         if (check_sp) {
2698                 if (!cfg->stack_inbalance_var)
2699                         cfg->stack_inbalance_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2700
2701                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2702                 ins->dreg = cfg->stack_inbalance_var->dreg;
2703                 MONO_ADD_INS (cfg->cbb, ins);
2704         }
2705
2706         call = mono_emit_call_args (cfg, sig, args, TRUE, FALSE, FALSE, rgctx_arg ? TRUE : FALSE, FALSE);
2707
2708         call->inst.sreg1 = addr->dreg;
2709
2710         if (imt_arg)
2711                 emit_imt_argument (cfg, call, NULL, imt_arg);
2712
2713         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2714
2715         if (check_sp) {
2716                 int sp_reg;
2717
2718                 sp_reg = mono_alloc_preg (cfg);
2719
2720                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2721                 ins->dreg = sp_reg;
2722                 MONO_ADD_INS (cfg->cbb, ins);
2723
2724                 /* Restore the stack so we don't crash when throwing the exception */
2725                 MONO_INST_NEW (cfg, ins, OP_SET_SP);
2726                 ins->sreg1 = cfg->stack_inbalance_var->dreg;
2727                 MONO_ADD_INS (cfg->cbb, ins);
2728
2729                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, cfg->stack_inbalance_var->dreg, sp_reg);
2730                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ExecutionEngineException");
2731         }
2732
2733         if (rgctx_arg)
2734                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2735
2736         return (MonoInst*)call;
2737 }
2738
2739 static MonoInst*
2740 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2741
2742 static MonoInst*
2743 emit_get_rgctx_method (MonoCompile *cfg, int context_used, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type);
2744 static MonoInst*
2745 emit_get_rgctx_klass (MonoCompile *cfg, int context_used, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2746
2747 static MonoInst*
2748 mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSignature *sig, gboolean tail,
2749                                                         MonoInst **args, MonoInst *this_ins, MonoInst *imt_arg, MonoInst *rgctx_arg)
2750 {
2751 #ifndef DISABLE_REMOTING
2752         gboolean might_be_remote = FALSE;
2753 #endif
2754         gboolean virtual = this_ins != NULL;
2755         gboolean enable_for_aot = TRUE;
2756         int context_used;
2757         MonoCallInst *call;
2758         MonoInst *call_target = NULL;
2759         int rgctx_reg = 0;
2760         gboolean need_unbox_trampoline;
2761
2762         if (!sig)
2763                 sig = mono_method_signature (method);
2764
2765         if (cfg->llvm_only && (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2766                 MonoInst *icall_args [16];
2767                 MonoInst *ins;
2768
2769                 // FIXME: Optimize this
2770
2771                 guint32 imt_slot = mono_method_get_imt_slot (method);
2772
2773                 icall_args [0] = this_ins;
2774                 EMIT_NEW_ICONST (cfg, icall_args [1], imt_slot);
2775                 if (imt_arg) {
2776                         icall_args [2] = imt_arg;
2777                 } else {
2778                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_METHODCONST, method);
2779                         icall_args [2] = ins;
2780                 }
2781                 EMIT_NEW_PCONST (cfg, icall_args [3], NULL);
2782
2783                 call_target = mono_emit_jit_icall (cfg, mono_resolve_iface_call, icall_args);
2784         }
2785
2786         if (rgctx_arg) {
2787                 rgctx_reg = mono_alloc_preg (cfg);
2788                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2789         }
2790
2791         if (method->string_ctor) {
2792                 /* Create the real signature */
2793                 /* FIXME: Cache these */
2794                 MonoMethodSignature *ctor_sig = mono_metadata_signature_dup_mempool (cfg->mempool, sig);
2795                 ctor_sig->ret = &mono_defaults.string_class->byval_arg;
2796
2797                 sig = ctor_sig;
2798         }
2799
2800         context_used = mini_method_check_context_used (cfg, method);
2801
2802 #ifndef DISABLE_REMOTING
2803         might_be_remote = this_ins && sig->hasthis &&
2804                 (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) &&
2805                 !(method->flags & METHOD_ATTRIBUTE_VIRTUAL) && (!MONO_CHECK_THIS (this_ins) || context_used);
2806
2807         if (might_be_remote && context_used) {
2808                 MonoInst *addr;
2809
2810                 g_assert (cfg->gshared);
2811
2812                 addr = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK);
2813
2814                 return mono_emit_calli (cfg, sig, args, addr, NULL, NULL);
2815         }
2816 #endif
2817
2818         if (cfg->llvm_only && !call_target && virtual && (method->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
2819                 // FIXME: Vcall optimizations below
2820                 MonoInst *icall_args [16];
2821                 MonoInst *ins;
2822
2823                 if (sig->generic_param_count) {
2824                         /*
2825                          * Generic virtual call, pass the concrete method as the imt argument.
2826                          */
2827                         imt_arg = emit_get_rgctx_method (cfg, context_used,
2828                                                                                          method, MONO_RGCTX_INFO_METHOD);
2829                 }
2830
2831                 // FIXME: Optimize this
2832
2833                 int slot = mono_method_get_vtable_index (method);
2834
2835                 icall_args [0] = this_ins;
2836                 EMIT_NEW_ICONST (cfg, icall_args [1], slot);
2837                 if (imt_arg) {
2838                         icall_args [2] = imt_arg;
2839                 } else {
2840                         EMIT_NEW_PCONST (cfg, ins, NULL);
2841                         icall_args [2] = ins;
2842                 }
2843                 call_target = mono_emit_jit_icall (cfg, mono_resolve_vcall, icall_args);
2844         }
2845
2846         need_unbox_trampoline = method->klass == mono_defaults.object_class || (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE);
2847
2848         call = mono_emit_call_args (cfg, sig, args, FALSE, virtual, tail, rgctx_arg ? TRUE : FALSE, need_unbox_trampoline);
2849
2850 #ifndef DISABLE_REMOTING
2851         if (might_be_remote)
2852                 call->method = mono_marshal_get_remoting_invoke_with_check (method);
2853         else
2854 #endif
2855                 call->method = method;
2856         call->inst.flags |= MONO_INST_HAS_METHOD;
2857         call->inst.inst_left = this_ins;
2858         call->tail_call = tail;
2859
2860         if (virtual) {
2861                 int vtable_reg, slot_reg, this_reg;
2862                 int offset;
2863
2864                 this_reg = this_ins->dreg;
2865
2866                 if (!cfg->llvm_only && (method->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (method->name, "Invoke")) {
2867                         MonoInst *dummy_use;
2868
2869                         MONO_EMIT_NULL_CHECK (cfg, this_reg);
2870
2871                         /* Make a call to delegate->invoke_impl */
2872                         call->inst.inst_basereg = this_reg;
2873                         call->inst.inst_offset = MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl);
2874                         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2875
2876                         /* We must emit a dummy use here because the delegate trampoline will
2877                         replace the 'this' argument with the delegate target making this activation
2878                         no longer a root for the delegate.
2879                         This is an issue for delegates that target collectible code such as dynamic
2880                         methods of GC'able assemblies.
2881
2882                         For a test case look into #667921.
2883
2884                         FIXME: a dummy use is not the best way to do it as the local register allocator
2885                         will put it on a caller save register and spil it around the call. 
2886                         Ideally, we would either put it on a callee save register or only do the store part.  
2887                          */
2888                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, args [0]);
2889
2890                         return (MonoInst*)call;
2891                 }
2892
2893                 if ((!cfg->compile_aot || enable_for_aot) && 
2894                         (!(method->flags & METHOD_ATTRIBUTE_VIRTUAL) || 
2895                          (MONO_METHOD_IS_FINAL (method) &&
2896                           method->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)) &&
2897                         !(mono_class_is_marshalbyref (method->klass) && context_used)) {
2898                         /* 
2899                          * the method is not virtual, we just need to ensure this is not null
2900                          * and then we can call the method directly.
2901                          */
2902 #ifndef DISABLE_REMOTING
2903                         if (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) {
2904                                 /* 
2905                                  * The check above ensures method is not gshared, this is needed since
2906                                  * gshared methods can't have wrappers.
2907                                  */
2908                                 method = call->method = mono_marshal_get_remoting_invoke_with_check (method);
2909                         }
2910 #endif
2911
2912                         if (!method->string_ctor)
2913                                 MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2914
2915                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2916                 } else if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && MONO_METHOD_IS_FINAL (method)) {
2917                         /*
2918                          * the method is virtual, but we can statically dispatch since either
2919                          * it's class or the method itself are sealed.
2920                          * But first we need to ensure it's not a null reference.
2921                          */
2922                         MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2923
2924                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2925                 } else if (call_target) {
2926                         vtable_reg = alloc_preg (cfg);
2927                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
2928
2929                         call->inst.opcode = callvirt_to_call_reg (call->inst.opcode);
2930                         call->inst.sreg1 = call_target->dreg;
2931                         call->inst.flags &= !MONO_INST_HAS_METHOD;
2932                 } else {
2933                         vtable_reg = alloc_preg (cfg);
2934                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
2935                         if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2936                                 guint32 imt_slot = mono_method_get_imt_slot (method);
2937                                 emit_imt_argument (cfg, call, call->method, imt_arg);
2938                                 slot_reg = vtable_reg;
2939                                 offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
2940                         } else {
2941                                 slot_reg = vtable_reg;
2942                                 offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) +
2943                                         ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
2944                                 if (imt_arg) {
2945                                         g_assert (mono_method_signature (method)->generic_param_count);
2946                                         emit_imt_argument (cfg, call, call->method, imt_arg);
2947                                 }
2948                         }
2949
2950                         call->inst.sreg1 = slot_reg;
2951                         call->inst.inst_offset = offset;
2952                         call->is_virtual = TRUE;
2953                 }
2954         }
2955
2956         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2957
2958         if (rgctx_arg)
2959                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2960
2961         return (MonoInst*)call;
2962 }
2963
2964 MonoInst*
2965 mono_emit_method_call (MonoCompile *cfg, MonoMethod *method, MonoInst **args, MonoInst *this_ins)
2966 {
2967         return mono_emit_method_call_full (cfg, method, mono_method_signature (method), FALSE, args, this_ins, NULL, NULL);
2968 }
2969
2970 MonoInst*
2971 mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig,
2972                                            MonoInst **args)
2973 {
2974         MonoCallInst *call;
2975
2976         g_assert (sig);
2977
2978         call = mono_emit_call_args (cfg, sig, args, FALSE, FALSE, FALSE, FALSE, FALSE);
2979         call->fptr = func;
2980
2981         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2982
2983         return (MonoInst*)call;
2984 }
2985
2986 MonoInst*
2987 mono_emit_jit_icall (MonoCompile *cfg, gconstpointer func, MonoInst **args)
2988 {
2989         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (func);
2990
2991         g_assert (info);
2992
2993         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
2994 }
2995
2996 /*
2997  * mono_emit_abs_call:
2998  *
2999  *   Emit a call to the runtime function described by PATCH_TYPE and DATA.
3000  */
3001 inline static MonoInst*
3002 mono_emit_abs_call (MonoCompile *cfg, MonoJumpInfoType patch_type, gconstpointer data, 
3003                                         MonoMethodSignature *sig, MonoInst **args)
3004 {
3005         MonoJumpInfo *ji = mono_patch_info_new (cfg->mempool, 0, patch_type, data);
3006         MonoInst *ins;
3007
3008         /* 
3009          * We pass ji as the call address, the PATCH_INFO_ABS resolving code will
3010          * handle it.
3011          */
3012         if (cfg->abs_patches == NULL)
3013                 cfg->abs_patches = g_hash_table_new (NULL, NULL);
3014         g_hash_table_insert (cfg->abs_patches, ji, ji);
3015         ins = mono_emit_native_call (cfg, ji, sig, args);
3016         ((MonoCallInst*)ins)->fptr_is_patch = TRUE;
3017         return ins;
3018 }
3019
3020 static gboolean
3021 direct_icalls_enabled (MonoCompile *cfg)
3022 {
3023         /* LLVM on amd64 can't handle calls to non-32 bit addresses */
3024 #ifdef TARGET_AMD64
3025         if (cfg->compile_llvm)
3026                 return FALSE;
3027 #endif
3028         if (cfg->gen_sdb_seq_points || cfg->disable_direct_icalls)
3029                 return FALSE;
3030         return TRUE;
3031 }
3032
3033 MonoInst*
3034 mono_emit_jit_icall_by_info (MonoCompile *cfg, MonoJitICallInfo *info, MonoInst **args)
3035 {
3036         /*
3037          * Call the jit icall without a wrapper if possible.
3038          * The wrapper is needed for the following reasons:
3039          * - to handle exceptions thrown using mono_raise_exceptions () from the
3040          *   icall function. The EH code needs the lmf frame pushed by the
3041          *   wrapper to be able to unwind back to managed code.
3042          * - to be able to do stack walks for asynchronously suspended
3043          *   threads when debugging.
3044          */
3045         if (info->no_raise && direct_icalls_enabled (cfg)) {
3046                 char *name;
3047                 int costs;
3048
3049                 if (!info->wrapper_method) {
3050                         name = g_strdup_printf ("__icall_wrapper_%s", info->name);
3051                         info->wrapper_method = mono_marshal_get_icall_wrapper (info->sig, name, info->func, TRUE);
3052                         g_free (name);
3053                         mono_memory_barrier ();
3054                 }
3055
3056                 /*
3057                  * Inline the wrapper method, which is basically a call to the C icall, and
3058                  * an exception check.
3059                  */
3060                 costs = inline_method (cfg, info->wrapper_method, NULL,
3061                                                            args, NULL, cfg->real_offset, TRUE);
3062                 g_assert (costs > 0);
3063                 g_assert (!MONO_TYPE_IS_VOID (info->sig->ret));
3064
3065                 return args [0];
3066         } else {
3067                 return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
3068         }
3069 }
3070  
3071 static MonoInst*
3072 mono_emit_widen_call_res (MonoCompile *cfg, MonoInst *ins, MonoMethodSignature *fsig)
3073 {
3074         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
3075                 if ((fsig->pinvoke || LLVM_ENABLED) && !fsig->ret->byref) {
3076                         int widen_op = -1;
3077
3078                         /* 
3079                          * Native code might return non register sized integers 
3080                          * without initializing the upper bits.
3081                          */
3082                         switch (mono_type_to_load_membase (cfg, fsig->ret)) {
3083                         case OP_LOADI1_MEMBASE:
3084                                 widen_op = OP_ICONV_TO_I1;
3085                                 break;
3086                         case OP_LOADU1_MEMBASE:
3087                                 widen_op = OP_ICONV_TO_U1;
3088                                 break;
3089                         case OP_LOADI2_MEMBASE:
3090                                 widen_op = OP_ICONV_TO_I2;
3091                                 break;
3092                         case OP_LOADU2_MEMBASE:
3093                                 widen_op = OP_ICONV_TO_U2;
3094                                 break;
3095                         default:
3096                                 break;
3097                         }
3098
3099                         if (widen_op != -1) {
3100                                 int dreg = alloc_preg (cfg);
3101                                 MonoInst *widen;
3102
3103                                 EMIT_NEW_UNALU (cfg, widen, widen_op, dreg, ins->dreg);
3104                                 widen->type = ins->type;
3105                                 ins = widen;
3106                         }
3107                 }
3108         }
3109
3110         return ins;
3111 }
3112
3113 static MonoMethod*
3114 get_memcpy_method (void)
3115 {
3116         static MonoMethod *memcpy_method = NULL;
3117         if (!memcpy_method) {
3118                 memcpy_method = mono_class_get_method_from_name (mono_defaults.string_class, "memcpy", 3);
3119                 if (!memcpy_method)
3120                         g_error ("Old corlib found. Install a new one");
3121         }
3122         return memcpy_method;
3123 }
3124
3125 static void
3126 create_write_barrier_bitmap (MonoCompile *cfg, MonoClass *klass, unsigned *wb_bitmap, int offset)
3127 {
3128         MonoClassField *field;
3129         gpointer iter = NULL;
3130
3131         while ((field = mono_class_get_fields (klass, &iter))) {
3132                 int foffset;
3133
3134                 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
3135                         continue;
3136                 foffset = klass->valuetype ? field->offset - sizeof (MonoObject): field->offset;
3137                 if (mini_type_is_reference (mono_field_get_type (field))) {
3138                         g_assert ((foffset % SIZEOF_VOID_P) == 0);
3139                         *wb_bitmap |= 1 << ((offset + foffset) / SIZEOF_VOID_P);
3140                 } else {
3141                         MonoClass *field_class = mono_class_from_mono_type (field->type);
3142                         if (field_class->has_references)
3143                                 create_write_barrier_bitmap (cfg, field_class, wb_bitmap, offset + foffset);
3144                 }
3145         }
3146 }
3147
3148 static void
3149 emit_write_barrier (MonoCompile *cfg, MonoInst *ptr, MonoInst *value)
3150 {
3151         int card_table_shift_bits;
3152         gpointer card_table_mask;
3153         guint8 *card_table;
3154         MonoInst *dummy_use;
3155         int nursery_shift_bits;
3156         size_t nursery_size;
3157         gboolean has_card_table_wb = FALSE;
3158
3159         if (!cfg->gen_write_barriers)
3160                 return;
3161
3162         card_table = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
3163
3164         mono_gc_get_nursery (&nursery_shift_bits, &nursery_size);
3165
3166 #ifdef MONO_ARCH_HAVE_CARD_TABLE_WBARRIER
3167         has_card_table_wb = TRUE;
3168 #endif
3169
3170         if (has_card_table_wb && !cfg->compile_aot && card_table && nursery_shift_bits > 0 && !COMPILE_LLVM (cfg)) {
3171                 MonoInst *wbarrier;
3172
3173                 MONO_INST_NEW (cfg, wbarrier, OP_CARD_TABLE_WBARRIER);
3174                 wbarrier->sreg1 = ptr->dreg;
3175                 wbarrier->sreg2 = value->dreg;
3176                 MONO_ADD_INS (cfg->cbb, wbarrier);
3177         } else if (card_table && !cfg->compile_aot && !mono_gc_card_table_nursery_check ()) {
3178                 int offset_reg = alloc_preg (cfg);
3179                 int card_reg  = alloc_preg (cfg);
3180                 MonoInst *ins;
3181
3182                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, offset_reg, ptr->dreg, card_table_shift_bits);
3183                 if (card_table_mask)
3184                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, offset_reg, offset_reg, card_table_mask);
3185
3186                 /*We can't use PADD_IMM since the cardtable might end up in high addresses and amd64 doesn't support
3187                  * IMM's larger than 32bits.
3188                  */
3189                 if (cfg->compile_aot) {
3190                         MONO_EMIT_NEW_AOTCONST (cfg, card_reg, NULL, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR);
3191                 } else {
3192                         MONO_INST_NEW (cfg, ins, OP_PCONST);
3193                         ins->inst_p0 = card_table;
3194                         ins->dreg = card_reg;
3195                         MONO_ADD_INS (cfg->cbb, ins);
3196                 }
3197
3198                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, offset_reg, offset_reg, card_reg);
3199                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, offset_reg, 0, 1);
3200         } else {
3201                 MonoMethod *write_barrier = mono_gc_get_write_barrier ();
3202                 mono_emit_method_call (cfg, write_barrier, &ptr, NULL);
3203         }
3204
3205         EMIT_NEW_DUMMY_USE (cfg, dummy_use, value);
3206 }
3207
3208 static gboolean
3209 mono_emit_wb_aware_memcpy (MonoCompile *cfg, MonoClass *klass, MonoInst *iargs[4], int size, int align)
3210 {
3211         int dest_ptr_reg, tmp_reg, destreg, srcreg, offset;
3212         unsigned need_wb = 0;
3213
3214         if (align == 0)
3215                 align = 4;
3216
3217         /*types with references can't have alignment smaller than sizeof(void*) */
3218         if (align < SIZEOF_VOID_P)
3219                 return FALSE;
3220
3221         /*This value cannot be bigger than 32 due to the way we calculate the required wb bitmap.*/
3222         if (size > 32 * SIZEOF_VOID_P)
3223                 return FALSE;
3224
3225         create_write_barrier_bitmap (cfg, klass, &need_wb, 0);
3226
3227         /* We don't unroll more than 5 stores to avoid code bloat. */
3228         if (size > 5 * SIZEOF_VOID_P) {
3229                 /*This is harmless and simplify mono_gc_wbarrier_value_copy_bitmap */
3230                 size += (SIZEOF_VOID_P - 1);
3231                 size &= ~(SIZEOF_VOID_P - 1);
3232
3233                 EMIT_NEW_ICONST (cfg, iargs [2], size);
3234                 EMIT_NEW_ICONST (cfg, iargs [3], need_wb);
3235                 mono_emit_jit_icall (cfg, mono_gc_wbarrier_value_copy_bitmap, iargs);
3236                 return TRUE;
3237         }
3238
3239         destreg = iargs [0]->dreg;
3240         srcreg = iargs [1]->dreg;
3241         offset = 0;
3242
3243         dest_ptr_reg = alloc_preg (cfg);
3244         tmp_reg = alloc_preg (cfg);
3245
3246         /*tmp = dreg*/
3247         EMIT_NEW_UNALU (cfg, iargs [0], OP_MOVE, dest_ptr_reg, destreg);
3248
3249         while (size >= SIZEOF_VOID_P) {
3250                 MonoInst *load_inst;
3251                 MONO_INST_NEW (cfg, load_inst, OP_LOAD_MEMBASE);
3252                 load_inst->dreg = tmp_reg;
3253                 load_inst->inst_basereg = srcreg;
3254                 load_inst->inst_offset = offset;
3255                 MONO_ADD_INS (cfg->cbb, load_inst);
3256
3257                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, dest_ptr_reg, 0, tmp_reg);
3258
3259                 if (need_wb & 0x1)
3260                         emit_write_barrier (cfg, iargs [0], load_inst);
3261
3262                 offset += SIZEOF_VOID_P;
3263                 size -= SIZEOF_VOID_P;
3264                 need_wb >>= 1;
3265
3266                 /*tmp += sizeof (void*)*/
3267                 if (size >= SIZEOF_VOID_P) {
3268                         NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, dest_ptr_reg, dest_ptr_reg, SIZEOF_VOID_P);
3269                         MONO_ADD_INS (cfg->cbb, iargs [0]);
3270                 }
3271         }
3272
3273         /* Those cannot be references since size < sizeof (void*) */
3274         while (size >= 4) {
3275                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tmp_reg, srcreg, offset);
3276                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, tmp_reg);
3277                 offset += 4;
3278                 size -= 4;
3279         }
3280
3281         while (size >= 2) {
3282                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmp_reg, srcreg, offset);
3283                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, tmp_reg);
3284                 offset += 2;
3285                 size -= 2;
3286         }
3287
3288         while (size >= 1) {
3289                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmp_reg, srcreg, offset);
3290                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, tmp_reg);
3291                 offset += 1;
3292                 size -= 1;
3293         }
3294
3295         return TRUE;
3296 }
3297
3298 /*
3299  * Emit code to copy a valuetype of type @klass whose address is stored in
3300  * @src->dreg to memory whose address is stored at @dest->dreg.
3301  */
3302 void
3303 mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native)
3304 {
3305         MonoInst *iargs [4];
3306         int n;
3307         guint32 align = 0;
3308         MonoMethod *memcpy_method;
3309         MonoInst *size_ins = NULL;
3310         MonoInst *memcpy_ins = NULL;
3311
3312         g_assert (klass);
3313         if (cfg->gshared)
3314                 klass = mono_class_from_mono_type (mini_get_underlying_type (&klass->byval_arg));
3315
3316         /*
3317          * This check breaks with spilled vars... need to handle it during verification anyway.
3318          * g_assert (klass && klass == src->klass && klass == dest->klass);
3319          */
3320
3321         if (mini_is_gsharedvt_klass (klass)) {
3322                 g_assert (!native);
3323                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3324                 memcpy_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_MEMCPY);
3325         }
3326
3327         if (native)
3328                 n = mono_class_native_size (klass, &align);
3329         else
3330                 n = mono_class_value_size (klass, &align);
3331
3332         /* if native is true there should be no references in the struct */
3333         if (cfg->gen_write_barriers && (klass->has_references || size_ins) && !native) {
3334                 /* Avoid barriers when storing to the stack */
3335                 if (!((dest->opcode == OP_ADD_IMM && dest->sreg1 == cfg->frame_reg) ||
3336                           (dest->opcode == OP_LDADDR))) {
3337                         int context_used;
3338
3339                         iargs [0] = dest;
3340                         iargs [1] = src;
3341
3342                         context_used = mini_class_check_context_used (cfg, klass);
3343
3344                         /* It's ok to intrinsify under gsharing since shared code types are layout stable. */
3345                         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && mono_emit_wb_aware_memcpy (cfg, klass, iargs, n, align)) {
3346                                 return;
3347                         } else if (context_used) {
3348                                 iargs [2] = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3349                         }  else {
3350                                 if (cfg->compile_aot) {
3351                                         EMIT_NEW_CLASSCONST (cfg, iargs [2], klass);
3352                                 } else {
3353                                         EMIT_NEW_PCONST (cfg, iargs [2], klass);
3354                                         mono_class_compute_gc_descriptor (klass);
3355                                 }
3356                         }
3357
3358                         if (size_ins)
3359                                 mono_emit_jit_icall (cfg, mono_gsharedvt_value_copy, iargs);
3360                         else
3361                                 mono_emit_jit_icall (cfg, mono_value_copy, iargs);
3362                         return;
3363                 }
3364         }
3365
3366         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 8) {
3367                 /* FIXME: Optimize the case when src/dest is OP_LDADDR */
3368                 mini_emit_memcpy (cfg, dest->dreg, 0, src->dreg, 0, n, align);
3369         } else {
3370                 iargs [0] = dest;
3371                 iargs [1] = src;
3372                 if (size_ins)
3373                         iargs [2] = size_ins;
3374                 else
3375                         EMIT_NEW_ICONST (cfg, iargs [2], n);
3376                 
3377                 memcpy_method = get_memcpy_method ();
3378                 if (memcpy_ins)
3379                         mono_emit_calli (cfg, mono_method_signature (memcpy_method), iargs, memcpy_ins, NULL, NULL);
3380                 else
3381                         mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
3382         }
3383 }
3384
3385 static MonoMethod*
3386 get_memset_method (void)
3387 {
3388         static MonoMethod *memset_method = NULL;
3389         if (!memset_method) {
3390                 memset_method = mono_class_get_method_from_name (mono_defaults.string_class, "memset", 3);
3391                 if (!memset_method)
3392                         g_error ("Old corlib found. Install a new one");
3393         }
3394         return memset_method;
3395 }
3396
3397 void
3398 mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass)
3399 {
3400         MonoInst *iargs [3];
3401         int n;
3402         guint32 align;
3403         MonoMethod *memset_method;
3404         MonoInst *size_ins = NULL;
3405         MonoInst *bzero_ins = NULL;
3406         static MonoMethod *bzero_method;
3407
3408         /* FIXME: Optimize this for the case when dest is an LDADDR */
3409         mono_class_init (klass);
3410         if (mini_is_gsharedvt_klass (klass)) {
3411                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3412                 bzero_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_BZERO);
3413                 if (!bzero_method)
3414                         bzero_method = mono_class_get_method_from_name (mono_defaults.string_class, "bzero_aligned_1", 2);
3415                 g_assert (bzero_method);
3416                 iargs [0] = dest;
3417                 iargs [1] = size_ins;
3418                 mono_emit_calli (cfg, mono_method_signature (bzero_method), iargs, bzero_ins, NULL, NULL);
3419                 return;
3420         }
3421
3422         n = mono_class_value_size (klass, &align);
3423
3424         if (n <= sizeof (gpointer) * 8) {
3425                 mini_emit_memset (cfg, dest->dreg, 0, n, 0, align);
3426         }
3427         else {
3428                 memset_method = get_memset_method ();
3429                 iargs [0] = dest;
3430                 EMIT_NEW_ICONST (cfg, iargs [1], 0);
3431                 EMIT_NEW_ICONST (cfg, iargs [2], n);
3432                 mono_emit_method_call (cfg, memset_method, iargs, NULL);
3433         }
3434 }
3435
3436 /*
3437  * emit_get_rgctx:
3438  *
3439  *   Emit IR to return either the this pointer for instance method,
3440  * or the mrgctx for static methods.
3441  */
3442 static MonoInst*
3443 emit_get_rgctx (MonoCompile *cfg, MonoMethod *method, int context_used)
3444 {
3445         MonoInst *this_ins = NULL;
3446
3447         g_assert (cfg->gshared);
3448
3449         if (!(method->flags & METHOD_ATTRIBUTE_STATIC) &&
3450                         !(context_used & MONO_GENERIC_CONTEXT_USED_METHOD) &&
3451                         !method->klass->valuetype)
3452                 EMIT_NEW_ARGLOAD (cfg, this_ins, 0);
3453
3454         if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD) {
3455                 MonoInst *mrgctx_loc, *mrgctx_var;
3456
3457                 g_assert (!this_ins);
3458                 g_assert (method->is_inflated && mono_method_get_context (method)->method_inst);
3459
3460                 mrgctx_loc = mono_get_vtable_var (cfg);
3461                 EMIT_NEW_TEMPLOAD (cfg, mrgctx_var, mrgctx_loc->inst_c0);
3462
3463                 return mrgctx_var;
3464         } else if (method->flags & METHOD_ATTRIBUTE_STATIC || method->klass->valuetype) {
3465                 MonoInst *vtable_loc, *vtable_var;
3466
3467                 g_assert (!this_ins);
3468
3469                 vtable_loc = mono_get_vtable_var (cfg);
3470                 EMIT_NEW_TEMPLOAD (cfg, vtable_var, vtable_loc->inst_c0);
3471
3472                 if (method->is_inflated && mono_method_get_context (method)->method_inst) {
3473                         MonoInst *mrgctx_var = vtable_var;
3474                         int vtable_reg;
3475
3476                         vtable_reg = alloc_preg (cfg);
3477                         EMIT_NEW_LOAD_MEMBASE (cfg, vtable_var, OP_LOAD_MEMBASE, vtable_reg, mrgctx_var->dreg, MONO_STRUCT_OFFSET (MonoMethodRuntimeGenericContext, class_vtable));
3478                         vtable_var->type = STACK_PTR;
3479                 }
3480
3481                 return vtable_var;
3482         } else {
3483                 MonoInst *ins;
3484                 int vtable_reg;
3485         
3486                 vtable_reg = alloc_preg (cfg);
3487                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, vtable_reg, this_ins->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3488                 return ins;
3489         }
3490 }
3491
3492 static MonoJumpInfoRgctxEntry *
3493 mono_patch_info_rgctx_entry_new (MonoMemPool *mp, MonoMethod *method, gboolean in_mrgctx, MonoJumpInfoType patch_type, gconstpointer patch_data, MonoRgctxInfoType info_type)
3494 {
3495         MonoJumpInfoRgctxEntry *res = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoRgctxEntry));
3496         res->method = method;
3497         res->in_mrgctx = in_mrgctx;
3498         res->data = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo));
3499         res->data->type = patch_type;
3500         res->data->data.target = patch_data;
3501         res->info_type = info_type;
3502
3503         return res;
3504 }
3505
3506 static inline MonoInst*
3507 emit_rgctx_fetch_inline (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
3508 {
3509         MonoInst *args [16];
3510         MonoInst *call;
3511
3512         // FIXME: No fastpath since the slot is not a compile time constant
3513         args [0] = rgctx;
3514         EMIT_NEW_AOTCONST (cfg, args [1], MONO_PATCH_INFO_RGCTX_SLOT_INDEX, entry);
3515         if (entry->in_mrgctx)
3516                 call = mono_emit_jit_icall (cfg, mono_fill_method_rgctx, args);
3517         else
3518                 call = mono_emit_jit_icall (cfg, mono_fill_class_rgctx, args);
3519         return call;
3520 #if 0
3521         /*
3522          * FIXME: This can be called during decompose, which is a problem since it creates
3523          * new bblocks.
3524          * Also, the fastpath doesn't work since the slot number is dynamically allocated.
3525          */
3526         int i, slot, depth, index, rgctx_reg, val_reg, res_reg;
3527         gboolean mrgctx;
3528         MonoBasicBlock *is_null_bb, *end_bb;
3529         MonoInst *res, *ins, *call;
3530         MonoInst *args[16];
3531
3532         slot = mini_get_rgctx_entry_slot (entry);
3533
3534         mrgctx = MONO_RGCTX_SLOT_IS_MRGCTX (slot);
3535         index = MONO_RGCTX_SLOT_INDEX (slot);
3536         if (mrgctx)
3537                 index += MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
3538         for (depth = 0; ; ++depth) {
3539                 int size = mono_class_rgctx_get_array_size (depth, mrgctx);
3540
3541                 if (index < size - 1)
3542                         break;
3543                 index -= size - 1;
3544         }
3545
3546         NEW_BBLOCK (cfg, end_bb);
3547         NEW_BBLOCK (cfg, is_null_bb);
3548
3549         if (mrgctx) {
3550                 rgctx_reg = rgctx->dreg;
3551         } else {
3552                 rgctx_reg = alloc_preg (cfg);
3553
3554                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, rgctx_reg, rgctx->dreg, MONO_STRUCT_OFFSET (MonoVTable, runtime_generic_context));
3555                 // FIXME: Avoid this check by allocating the table when the vtable is created etc.
3556                 NEW_BBLOCK (cfg, is_null_bb);
3557
3558                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rgctx_reg, 0);
3559                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3560         }
3561
3562         for (i = 0; i < depth; ++i) {
3563                 int array_reg = alloc_preg (cfg);
3564
3565                 /* load ptr to next array */
3566                 if (mrgctx && i == 0)
3567                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, rgctx_reg, MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT);
3568                 else
3569                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, rgctx_reg, 0);
3570                 rgctx_reg = array_reg;
3571                 /* is the ptr null? */
3572                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rgctx_reg, 0);
3573                 /* if yes, jump to actual trampoline */
3574                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3575         }
3576
3577         /* fetch slot */
3578         val_reg = alloc_preg (cfg);
3579         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, val_reg, rgctx_reg, (index + 1) * sizeof (gpointer));
3580         /* is the slot null? */
3581         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, val_reg, 0);
3582         /* if yes, jump to actual trampoline */
3583         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3584
3585         /* Fastpath */
3586         res_reg = alloc_preg (cfg);
3587         MONO_INST_NEW (cfg, ins, OP_MOVE);
3588         ins->dreg = res_reg;
3589         ins->sreg1 = val_reg;
3590         MONO_ADD_INS (cfg->cbb, ins);
3591         res = ins;
3592         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3593
3594         /* Slowpath */
3595         MONO_START_BB (cfg, is_null_bb);
3596         args [0] = rgctx;
3597         EMIT_NEW_ICONST (cfg, args [1], index);
3598         if (mrgctx)
3599                 call = mono_emit_jit_icall (cfg, mono_fill_method_rgctx, args);
3600         else
3601                 call = mono_emit_jit_icall (cfg, mono_fill_class_rgctx, args);
3602         MONO_INST_NEW (cfg, ins, OP_MOVE);
3603         ins->dreg = res_reg;
3604         ins->sreg1 = call->dreg;
3605         MONO_ADD_INS (cfg->cbb, ins);
3606         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3607
3608         MONO_START_BB (cfg, end_bb);
3609
3610         return res;
3611 #endif
3612 }
3613
3614 /*
3615  * emit_rgctx_fetch:
3616  *
3617  *   Emit IR to load the value of the rgctx entry ENTRY from the rgctx
3618  * given by RGCTX.
3619  */
3620 static inline MonoInst*
3621 emit_rgctx_fetch (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
3622 {
3623         if (cfg->llvm_only)
3624                 return emit_rgctx_fetch_inline (cfg, rgctx, entry);
3625         else
3626                 return mono_emit_abs_call (cfg, MONO_PATCH_INFO_RGCTX_FETCH, entry, helper_sig_rgctx_lazy_fetch_trampoline, &rgctx);
3627 }
3628
3629 static MonoInst*
3630 emit_get_rgctx_klass (MonoCompile *cfg, int context_used,
3631                                           MonoClass *klass, MonoRgctxInfoType rgctx_type)
3632 {
3633         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);
3634         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3635
3636         return emit_rgctx_fetch (cfg, rgctx, entry);
3637 }
3638
3639 static MonoInst*
3640 emit_get_rgctx_sig (MonoCompile *cfg, int context_used,
3641                                         MonoMethodSignature *sig, MonoRgctxInfoType rgctx_type)
3642 {
3643         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);
3644         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3645
3646         return emit_rgctx_fetch (cfg, rgctx, entry);
3647 }
3648
3649 static MonoInst*
3650 emit_get_rgctx_gsharedvt_call (MonoCompile *cfg, int context_used,
3651                                                            MonoMethodSignature *sig, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3652 {
3653         MonoJumpInfoGSharedVtCall *call_info;
3654         MonoJumpInfoRgctxEntry *entry;
3655         MonoInst *rgctx;
3656
3657         call_info = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoGSharedVtCall));
3658         call_info->sig = sig;
3659         call_info->method = cmethod;
3660
3661         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);
3662         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3663
3664         return emit_rgctx_fetch (cfg, rgctx, entry);
3665 }
3666
3667 /*
3668  * emit_get_rgctx_virt_method:
3669  *
3670  *   Return data for method VIRT_METHOD for a receiver of type KLASS.
3671  */
3672 static MonoInst*
3673 emit_get_rgctx_virt_method (MonoCompile *cfg, int context_used,
3674                                                         MonoClass *klass, MonoMethod *virt_method, MonoRgctxInfoType rgctx_type)
3675 {
3676         MonoJumpInfoVirtMethod *info;
3677         MonoJumpInfoRgctxEntry *entry;
3678         MonoInst *rgctx;
3679
3680         info = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoVirtMethod));
3681         info->klass = klass;
3682         info->method = virt_method;
3683
3684         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);
3685         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3686
3687         return emit_rgctx_fetch (cfg, rgctx, entry);
3688 }
3689
3690 static MonoInst*
3691 emit_get_rgctx_gsharedvt_method (MonoCompile *cfg, int context_used,
3692                                                                  MonoMethod *cmethod, MonoGSharedVtMethodInfo *info)
3693 {
3694         MonoJumpInfoRgctxEntry *entry;
3695         MonoInst *rgctx;
3696
3697         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);
3698         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3699
3700         return emit_rgctx_fetch (cfg, rgctx, entry);
3701 }
3702
3703 /*
3704  * emit_get_rgctx_method:
3705  *
3706  *   Emit IR to load the property RGCTX_TYPE of CMETHOD. If context_used is 0, emit
3707  * normal constants, else emit a load from the rgctx.
3708  */
3709 static MonoInst*
3710 emit_get_rgctx_method (MonoCompile *cfg, int context_used,
3711                                            MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3712 {
3713         if (!context_used) {
3714                 MonoInst *ins;
3715
3716                 switch (rgctx_type) {
3717                 case MONO_RGCTX_INFO_METHOD:
3718                         EMIT_NEW_METHODCONST (cfg, ins, cmethod);
3719                         return ins;
3720                 case MONO_RGCTX_INFO_METHOD_RGCTX:
3721                         EMIT_NEW_METHOD_RGCTX_CONST (cfg, ins, cmethod);
3722                         return ins;
3723                 default:
3724                         g_assert_not_reached ();
3725                 }
3726         } else {
3727                 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);
3728                 MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3729
3730                 return emit_rgctx_fetch (cfg, rgctx, entry);
3731         }
3732 }
3733
3734 static MonoInst*
3735 emit_get_rgctx_field (MonoCompile *cfg, int context_used,
3736                                           MonoClassField *field, MonoRgctxInfoType rgctx_type)
3737 {
3738         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);
3739         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3740
3741         return emit_rgctx_fetch (cfg, rgctx, entry);
3742 }
3743
3744 static int
3745 get_gsharedvt_info_slot (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3746 {
3747         MonoGSharedVtMethodInfo *info = cfg->gsharedvt_info;
3748         MonoRuntimeGenericContextInfoTemplate *template;
3749         int i, idx;
3750
3751         g_assert (info);
3752
3753         for (i = 0; i < info->num_entries; ++i) {
3754                 MonoRuntimeGenericContextInfoTemplate *otemplate = &info->entries [i];
3755
3756                 if (otemplate->info_type == rgctx_type && otemplate->data == data && rgctx_type != MONO_RGCTX_INFO_LOCAL_OFFSET)
3757                         return i;
3758         }
3759
3760         if (info->num_entries == info->count_entries) {
3761                 MonoRuntimeGenericContextInfoTemplate *new_entries;
3762                 int new_count_entries = info->count_entries ? info->count_entries * 2 : 16;
3763
3764                 new_entries = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * new_count_entries);
3765
3766                 memcpy (new_entries, info->entries, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
3767                 info->entries = new_entries;
3768                 info->count_entries = new_count_entries;
3769         }
3770
3771         idx = info->num_entries;
3772         template = &info->entries [idx];
3773         template->info_type = rgctx_type;
3774         template->data = data;
3775
3776         info->num_entries ++;
3777
3778         return idx;
3779 }
3780
3781 /*
3782  * emit_get_gsharedvt_info:
3783  *
3784  *   This is similar to emit_get_rgctx_.., but loads the data from the gsharedvt info var instead of calling an rgctx fetch trampoline.
3785  */
3786 static MonoInst*
3787 emit_get_gsharedvt_info (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3788 {
3789         MonoInst *ins;
3790         int idx, dreg;
3791
3792         idx = get_gsharedvt_info_slot (cfg, data, rgctx_type);
3793         /* Load info->entries [idx] */
3794         dreg = alloc_preg (cfg);
3795         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, cfg->gsharedvt_info_var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
3796
3797         return ins;
3798 }
3799
3800 static MonoInst*
3801 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type)
3802 {
3803         return emit_get_gsharedvt_info (cfg, &klass->byval_arg, rgctx_type);
3804 }
3805
3806 /*
3807  * On return the caller must check @klass for load errors.
3808  */
3809 static void
3810 emit_class_init (MonoCompile *cfg, MonoClass *klass)
3811 {
3812         MonoInst *vtable_arg;
3813         int context_used;
3814         gboolean use_op_generic_class_init = FALSE;
3815
3816         context_used = mini_class_check_context_used (cfg, klass);
3817
3818         if (context_used) {
3819                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
3820                                                                                    klass, MONO_RGCTX_INFO_VTABLE);
3821         } else {
3822                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
3823
3824                 if (!vtable)
3825                         return;
3826                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
3827         }
3828
3829 #ifdef MONO_ARCH_HAVE_OP_GENERIC_CLASS_INIT
3830         if (!COMPILE_LLVM (cfg))
3831                 use_op_generic_class_init = TRUE;
3832 #endif
3833
3834         if (use_op_generic_class_init) {
3835                 MonoInst *ins;
3836
3837                 /*
3838                  * Using an opcode instead of emitting IR here allows the hiding of the call inside the opcode,
3839                  * so this doesn't have to clobber any regs and it doesn't break basic blocks.
3840                  */
3841                 MONO_INST_NEW (cfg, ins, OP_GENERIC_CLASS_INIT);
3842                 ins->sreg1 = vtable_arg->dreg;
3843                 MONO_ADD_INS (cfg->cbb, ins);
3844         } else {
3845                 static int byte_offset = -1;
3846                 static guint8 bitmask;
3847                 int bits_reg, inited_reg;
3848                 MonoBasicBlock *inited_bb;
3849                 MonoInst *args [16];
3850
3851                 if (byte_offset < 0)
3852                         mono_marshal_find_bitfield_offset (MonoVTable, initialized, &byte_offset, &bitmask);
3853
3854                 bits_reg = alloc_ireg (cfg);
3855                 inited_reg = alloc_ireg (cfg);
3856
3857                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, bits_reg, vtable_arg->dreg, byte_offset);
3858                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, inited_reg, bits_reg, bitmask);
3859
3860                 NEW_BBLOCK (cfg, inited_bb);
3861
3862                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, inited_reg, 0);
3863                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, inited_bb);
3864
3865                 args [0] = vtable_arg;
3866                 mono_emit_jit_icall (cfg, mono_generic_class_init, args);
3867
3868                 MONO_START_BB (cfg, inited_bb);
3869         }
3870 }
3871
3872 static void
3873 emit_seq_point (MonoCompile *cfg, MonoMethod *method, guint8* ip, gboolean intr_loc, gboolean nonempty_stack)
3874 {
3875         MonoInst *ins;
3876
3877         if (cfg->gen_seq_points && cfg->method == method) {
3878                 NEW_SEQ_POINT (cfg, ins, ip - cfg->header->code, intr_loc);
3879                 if (nonempty_stack)
3880                         ins->flags |= MONO_INST_NONEMPTY_STACK;
3881                 MONO_ADD_INS (cfg->cbb, ins);
3882         }
3883 }
3884
3885 static void
3886 save_cast_details (MonoCompile *cfg, MonoClass *klass, int obj_reg, gboolean null_check)
3887 {
3888         if (mini_get_debug_options ()->better_cast_details) {
3889                 int vtable_reg = alloc_preg (cfg);
3890                 int klass_reg = alloc_preg (cfg);
3891                 MonoBasicBlock *is_null_bb = NULL;
3892                 MonoInst *tls_get;
3893                 int to_klass_reg, context_used;
3894
3895                 if (null_check) {
3896                         NEW_BBLOCK (cfg, is_null_bb);
3897
3898                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
3899                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3900                 }
3901
3902                 tls_get = mono_get_jit_tls_intrinsic (cfg);
3903                 if (!tls_get) {
3904                         fprintf (stderr, "error: --debug=casts not supported on this platform.\n.");
3905                         exit (1);
3906                 }
3907
3908                 MONO_ADD_INS (cfg->cbb, tls_get);
3909                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3910                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3911
3912                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), klass_reg);
3913
3914                 context_used = mini_class_check_context_used (cfg, klass);
3915                 if (context_used) {
3916                         MonoInst *class_ins;
3917
3918                         class_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3919                         to_klass_reg = class_ins->dreg;
3920                 } else {
3921                         to_klass_reg = alloc_preg (cfg);
3922                         MONO_EMIT_NEW_CLASSCONST (cfg, to_klass_reg, klass);
3923                 }
3924                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_to), to_klass_reg);
3925
3926                 if (null_check)
3927                         MONO_START_BB (cfg, is_null_bb);
3928         }
3929 }
3930
3931 static void
3932 reset_cast_details (MonoCompile *cfg)
3933 {
3934         /* Reset the variables holding the cast details */
3935         if (mini_get_debug_options ()->better_cast_details) {
3936                 MonoInst *tls_get = mono_get_jit_tls_intrinsic (cfg);
3937
3938                 MONO_ADD_INS (cfg->cbb, tls_get);
3939                 /* It is enough to reset the from field */
3940                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), 0);
3941         }
3942 }
3943
3944 /*
3945  * On return the caller must check @array_class for load errors
3946  */
3947 static void
3948 mini_emit_check_array_type (MonoCompile *cfg, MonoInst *obj, MonoClass *array_class)
3949 {
3950         int vtable_reg = alloc_preg (cfg);
3951         int context_used;
3952
3953         context_used = mini_class_check_context_used (cfg, array_class);
3954
3955         save_cast_details (cfg, array_class, obj->dreg, FALSE);
3956
3957         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3958
3959         if (cfg->opt & MONO_OPT_SHARED) {
3960                 int class_reg = alloc_preg (cfg);
3961                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, class_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3962                 if (cfg->compile_aot) {
3963                         int klass_reg = alloc_preg (cfg);
3964                         MONO_EMIT_NEW_CLASSCONST (cfg, klass_reg, array_class);
3965                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, class_reg, klass_reg);
3966                 } else {
3967                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, class_reg, array_class);
3968                 }
3969         } else if (context_used) {
3970                 MonoInst *vtable_ins;
3971
3972                 vtable_ins = emit_get_rgctx_klass (cfg, context_used, array_class, MONO_RGCTX_INFO_VTABLE);
3973                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vtable_ins->dreg);
3974         } else {
3975                 if (cfg->compile_aot) {
3976                         int vt_reg;
3977                         MonoVTable *vtable;
3978
3979                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3980                                 return;
3981                         vt_reg = alloc_preg (cfg);
3982                         MONO_EMIT_NEW_VTABLECONST (cfg, vt_reg, vtable);
3983                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vt_reg);
3984                 } else {
3985                         MonoVTable *vtable;
3986                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3987                                 return;
3988                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vtable);
3989                 }
3990         }
3991         
3992         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ArrayTypeMismatchException");
3993
3994         reset_cast_details (cfg);
3995 }
3996
3997 /**
3998  * Handles unbox of a Nullable<T>. If context_used is non zero, then shared 
3999  * generic code is generated.
4000  */
4001 static MonoInst*
4002 handle_unbox_nullable (MonoCompile* cfg, MonoInst* val, MonoClass* klass, int context_used)
4003 {
4004         MonoMethod* method = mono_class_get_method_from_name (klass, "Unbox", 1);
4005
4006         if (context_used) {
4007                 MonoInst *rgctx, *addr;
4008
4009                 /* FIXME: What if the class is shared?  We might not
4010                    have to get the address of the method from the
4011                    RGCTX. */
4012                 addr = emit_get_rgctx_method (cfg, context_used, method,
4013                                                                           MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
4014
4015                 rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
4016
4017                 return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
4018         } else {
4019                 gboolean pass_vtable, pass_mrgctx;
4020                 MonoInst *rgctx_arg = NULL;
4021
4022                 check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
4023                 g_assert (!pass_mrgctx);
4024
4025                 if (pass_vtable) {
4026                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
4027
4028                         g_assert (vtable);
4029                         EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
4030                 }
4031
4032                 return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
4033         }
4034 }
4035
4036 static MonoInst*
4037 handle_unbox (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, int context_used)
4038 {
4039         MonoInst *add;
4040         int obj_reg;
4041         int vtable_reg = alloc_dreg (cfg ,STACK_PTR);
4042         int klass_reg = alloc_dreg (cfg ,STACK_PTR);
4043         int eclass_reg = alloc_dreg (cfg ,STACK_PTR);
4044         int rank_reg = alloc_dreg (cfg ,STACK_I4);
4045
4046         obj_reg = sp [0]->dreg;
4047         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4048         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
4049
4050         /* FIXME: generics */
4051         g_assert (klass->rank == 0);
4052                         
4053         // Check rank == 0
4054         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, 0);
4055         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4056
4057         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4058         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, element_class));
4059
4060         if (context_used) {
4061                 MonoInst *element_class;
4062
4063                 /* This assertion is from the unboxcast insn */
4064                 g_assert (klass->rank == 0);
4065
4066                 element_class = emit_get_rgctx_klass (cfg, context_used,
4067                                 klass, MONO_RGCTX_INFO_ELEMENT_KLASS);
4068
4069                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, eclass_reg, element_class->dreg);
4070                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4071         } else {
4072                 save_cast_details (cfg, klass->element_class, obj_reg, FALSE);
4073                 mini_emit_class_check (cfg, eclass_reg, klass->element_class);
4074                 reset_cast_details (cfg);
4075         }
4076
4077         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), obj_reg, sizeof (MonoObject));
4078         MONO_ADD_INS (cfg->cbb, add);
4079         add->type = STACK_MP;
4080         add->klass = klass;
4081
4082         return add;
4083 }
4084
4085 static MonoInst*
4086 handle_unbox_gsharedvt (MonoCompile *cfg, MonoClass *klass, MonoInst *obj)
4087 {
4088         MonoInst *addr, *klass_inst, *is_ref, *args[16];
4089         MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
4090         MonoInst *ins;
4091         int dreg, addr_reg;
4092
4093         klass_inst = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_KLASS);
4094
4095         /* obj */
4096         args [0] = obj;
4097
4098         /* klass */
4099         args [1] = klass_inst;
4100
4101         /* CASTCLASS */
4102         obj = mono_emit_jit_icall (cfg, mono_object_castclass_unbox, args);
4103
4104         NEW_BBLOCK (cfg, is_ref_bb);
4105         NEW_BBLOCK (cfg, is_nullable_bb);
4106         NEW_BBLOCK (cfg, end_bb);
4107         is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
4108         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 1);
4109         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
4110
4111         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 2);
4112         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
4113
4114         /* This will contain either the address of the unboxed vtype, or an address of the temporary where the ref is stored */
4115         addr_reg = alloc_dreg (cfg, STACK_MP);
4116
4117         /* Non-ref case */
4118         /* UNBOX */
4119         NEW_BIALU_IMM (cfg, addr, OP_ADD_IMM, addr_reg, obj->dreg, sizeof (MonoObject));
4120         MONO_ADD_INS (cfg->cbb, addr);
4121
4122         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4123
4124         /* Ref case */
4125         MONO_START_BB (cfg, is_ref_bb);
4126
4127         /* Save the ref to a temporary */
4128         dreg = alloc_ireg (cfg);
4129         EMIT_NEW_VARLOADA_VREG (cfg, addr, dreg, &klass->byval_arg);
4130         addr->dreg = addr_reg;
4131         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, obj->dreg);
4132         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4133
4134         /* Nullable case */
4135         MONO_START_BB (cfg, is_nullable_bb);
4136
4137         {
4138                 MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX);
4139                 MonoInst *unbox_call;
4140                 MonoMethodSignature *unbox_sig;
4141
4142                 unbox_sig = mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
4143                 unbox_sig->ret = &klass->byval_arg;
4144                 unbox_sig->param_count = 1;
4145                 unbox_sig->params [0] = &mono_defaults.object_class->byval_arg;
4146                 unbox_call = mono_emit_calli (cfg, unbox_sig, &obj, addr, NULL, NULL);
4147
4148                 EMIT_NEW_VARLOADA_VREG (cfg, addr, unbox_call->dreg, &klass->byval_arg);
4149                 addr->dreg = addr_reg;
4150         }
4151
4152         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4153
4154         /* End */
4155         MONO_START_BB (cfg, end_bb);
4156
4157         /* LDOBJ */
4158         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr_reg, 0);
4159
4160         return ins;
4161 }
4162
4163 /*
4164  * Returns NULL and set the cfg exception on error.
4165  */
4166 static MonoInst*
4167 handle_alloc (MonoCompile *cfg, MonoClass *klass, gboolean for_box, int context_used)
4168 {
4169         MonoInst *iargs [2];
4170         void *alloc_ftn;
4171
4172         if (context_used) {
4173                 MonoInst *data;
4174                 int rgctx_info;
4175                 MonoInst *iargs [2];
4176                 gboolean known_instance_size = !mini_is_gsharedvt_klass (klass);
4177
4178                 MonoMethod *managed_alloc = mono_gc_get_managed_allocator (klass, for_box, known_instance_size);
4179
4180                 if (cfg->opt & MONO_OPT_SHARED)
4181                         rgctx_info = MONO_RGCTX_INFO_KLASS;
4182                 else
4183                         rgctx_info = MONO_RGCTX_INFO_VTABLE;
4184                 data = emit_get_rgctx_klass (cfg, context_used, klass, rgctx_info);
4185
4186                 if (cfg->opt & MONO_OPT_SHARED) {
4187                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
4188                         iargs [1] = data;
4189                         alloc_ftn = mono_object_new;
4190                 } else {
4191                         iargs [0] = data;
4192                         alloc_ftn = mono_object_new_specific;
4193                 }
4194
4195                 if (managed_alloc && !(cfg->opt & MONO_OPT_SHARED)) {
4196                         if (known_instance_size) {
4197                                 int size = mono_class_instance_size (klass);
4198                                 if (size < sizeof (MonoObject))
4199                                         g_error ("Invalid size %d for class %s", size, mono_type_get_full_name (klass));
4200
4201                                 EMIT_NEW_ICONST (cfg, iargs [1], mono_gc_get_aligned_size_for_allocator (size));
4202                         }
4203                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
4204                 }
4205
4206                 return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
4207         }
4208
4209         if (cfg->opt & MONO_OPT_SHARED) {
4210                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
4211                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
4212
4213                 alloc_ftn = mono_object_new;
4214         } else if (cfg->compile_aot && cfg->cbb->out_of_line && klass->type_token && klass->image == mono_defaults.corlib && !klass->generic_class) {
4215                 /* This happens often in argument checking code, eg. throw new FooException... */
4216                 /* Avoid relocations and save some space by calling a helper function specialized to mscorlib */
4217                 EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (klass->type_token));
4218                 return mono_emit_jit_icall (cfg, mono_helper_newobj_mscorlib, iargs);
4219         } else {
4220                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
4221                 MonoMethod *managed_alloc = NULL;
4222                 gboolean pass_lw;
4223
4224                 if (!vtable) {
4225                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4226                         cfg->exception_ptr = klass;
4227                         return NULL;
4228                 }
4229
4230                 managed_alloc = mono_gc_get_managed_allocator (klass, for_box, TRUE);
4231
4232                 if (managed_alloc) {
4233                         int size = mono_class_instance_size (klass);
4234                         if (size < sizeof (MonoObject))
4235                                 g_error ("Invalid size %d for class %s", size, mono_type_get_full_name (klass));
4236
4237                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
4238                         EMIT_NEW_ICONST (cfg, iargs [1], mono_gc_get_aligned_size_for_allocator (size));
4239                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
4240                 }
4241                 alloc_ftn = mono_class_get_allocation_ftn (vtable, for_box, &pass_lw);
4242                 if (pass_lw) {
4243                         guint32 lw = vtable->klass->instance_size;
4244                         lw = ((lw + (sizeof (gpointer) - 1)) & ~(sizeof (gpointer) - 1)) / sizeof (gpointer);
4245                         EMIT_NEW_ICONST (cfg, iargs [0], lw);
4246                         EMIT_NEW_VTABLECONST (cfg, iargs [1], vtable);
4247                 }
4248                 else {
4249                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
4250                 }
4251         }
4252
4253         return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
4254 }
4255         
4256 /*
4257  * Returns NULL and set the cfg exception on error.
4258  */     
4259 static MonoInst*
4260 handle_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_used)
4261 {
4262         MonoInst *alloc, *ins;
4263
4264         if (mono_class_is_nullable (klass)) {
4265                 MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
4266
4267                 if (context_used) {
4268                         /* FIXME: What if the class is shared?  We might not
4269                            have to get the method address from the RGCTX. */
4270                         MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
4271                                                                                                         MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
4272                         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
4273
4274                         return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
4275                 } else {
4276                         gboolean pass_vtable, pass_mrgctx;
4277                         MonoInst *rgctx_arg = NULL;
4278
4279                         check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
4280                         g_assert (!pass_mrgctx);
4281
4282                         if (pass_vtable) {
4283                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
4284
4285                                 g_assert (vtable);
4286                                 EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
4287                         }
4288
4289                         return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
4290                 }
4291         }
4292
4293         if (mini_is_gsharedvt_klass (klass)) {
4294                 MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
4295                 MonoInst *res, *is_ref, *src_var, *addr;
4296                 int dreg;
4297
4298                 dreg = alloc_ireg (cfg);
4299
4300                 NEW_BBLOCK (cfg, is_ref_bb);
4301                 NEW_BBLOCK (cfg, is_nullable_bb);
4302                 NEW_BBLOCK (cfg, end_bb);
4303                 is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
4304                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 1);
4305                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
4306
4307                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 2);
4308                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
4309
4310                 /* Non-ref case */
4311                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4312                 if (!alloc)
4313                         return NULL;
4314                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4315                 ins->opcode = OP_STOREV_MEMBASE;
4316
4317                 EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, alloc->dreg);
4318                 res->type = STACK_OBJ;
4319                 res->klass = klass;
4320                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4321                 
4322                 /* Ref case */
4323                 MONO_START_BB (cfg, is_ref_bb);
4324
4325                 /* val is a vtype, so has to load the value manually */
4326                 src_var = get_vreg_to_inst (cfg, val->dreg);
4327                 if (!src_var)
4328                         src_var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, val->dreg);
4329                 EMIT_NEW_VARLOADA (cfg, addr, src_var, src_var->inst_vtype);
4330                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, addr->dreg, 0);
4331                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4332
4333                 /* Nullable case */
4334                 MONO_START_BB (cfg, is_nullable_bb);
4335
4336                 {
4337                         MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass,
4338                                                                                                         MONO_RGCTX_INFO_NULLABLE_CLASS_BOX);
4339                         MonoInst *box_call;
4340                         MonoMethodSignature *box_sig;
4341
4342                         /*
4343                          * klass is Nullable<T>, need to call Nullable<T>.Box () using a gsharedvt signature, but we cannot
4344                          * construct that method at JIT time, so have to do things by hand.
4345                          */
4346                         box_sig = mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
4347                         box_sig->ret = &mono_defaults.object_class->byval_arg;
4348                         box_sig->param_count = 1;
4349                         box_sig->params [0] = &klass->byval_arg;
4350                         box_call = mono_emit_calli (cfg, box_sig, &val, addr, NULL, NULL);
4351                         EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, box_call->dreg);
4352                         res->type = STACK_OBJ;
4353                         res->klass = klass;
4354                 }
4355
4356                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4357
4358                 MONO_START_BB (cfg, end_bb);
4359
4360                 return res;
4361         } else {
4362                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4363                 if (!alloc)
4364                         return NULL;
4365
4366                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4367                 return alloc;
4368         }
4369 }
4370
4371 static gboolean
4372 mini_class_has_reference_variant_generic_argument (MonoCompile *cfg, MonoClass *klass, int context_used)
4373 {
4374         int i;
4375         MonoGenericContainer *container;
4376         MonoGenericInst *ginst;
4377
4378         if (klass->generic_class) {
4379                 container = klass->generic_class->container_class->generic_container;
4380                 ginst = klass->generic_class->context.class_inst;
4381         } else if (klass->generic_container && context_used) {
4382                 container = klass->generic_container;
4383                 ginst = container->context.class_inst;
4384         } else {
4385                 return FALSE;
4386         }
4387
4388         for (i = 0; i < container->type_argc; ++i) {
4389                 MonoType *type;
4390                 if (!(mono_generic_container_get_param_info (container, i)->flags & (MONO_GEN_PARAM_VARIANT|MONO_GEN_PARAM_COVARIANT)))
4391                         continue;
4392                 type = ginst->type_argv [i];
4393                 if (mini_type_is_reference (type))
4394                         return TRUE;
4395         }
4396         return FALSE;
4397 }
4398
4399 static GHashTable* direct_icall_type_hash;
4400
4401 static gboolean
4402 icall_is_direct_callable (MonoCompile *cfg, MonoMethod *cmethod)
4403 {
4404         /* LLVM on amd64 can't handle calls to non-32 bit addresses */
4405         if (!direct_icalls_enabled (cfg))
4406                 return FALSE;
4407
4408         /*
4409          * An icall is directly callable if it doesn't directly or indirectly call mono_raise_exception ().
4410          * Whitelist a few icalls for now.
4411          */
4412         if (!direct_icall_type_hash) {
4413                 GHashTable *h = g_hash_table_new (g_str_hash, g_str_equal);
4414
4415                 g_hash_table_insert (h, (char*)"Decimal", GUINT_TO_POINTER (1));
4416                 g_hash_table_insert (h, (char*)"Number", GUINT_TO_POINTER (1));
4417                 g_hash_table_insert (h, (char*)"Buffer", GUINT_TO_POINTER (1));
4418                 g_hash_table_insert (h, (char*)"Monitor", GUINT_TO_POINTER (1));
4419                 mono_memory_barrier ();
4420                 direct_icall_type_hash = h;
4421         }
4422
4423         if (cmethod->klass == mono_defaults.math_class)
4424                 return TRUE;
4425         /* No locking needed */
4426         if (cmethod->klass->image == mono_defaults.corlib && g_hash_table_lookup (direct_icall_type_hash, cmethod->klass->name))
4427                 return TRUE;
4428         return FALSE;
4429 }
4430
4431 #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)
4432
4433 static MonoInst*
4434 emit_castclass_with_cache (MonoCompile *cfg, MonoClass *klass, MonoInst **args)
4435 {
4436         MonoMethod *mono_castclass;
4437         MonoInst *res;
4438
4439         mono_castclass = mono_marshal_get_castclass_with_cache ();
4440
4441         save_cast_details (cfg, klass, args [0]->dreg, TRUE);
4442         res = mono_emit_method_call (cfg, mono_castclass, args, NULL);
4443         reset_cast_details (cfg);
4444
4445         return res;
4446 }
4447
4448 static int
4449 get_castclass_cache_idx (MonoCompile *cfg)
4450 {
4451         /* Each CASTCLASS_CACHE patch needs a unique index which identifies the call site */
4452         cfg->castclass_cache_index ++;
4453         return (cfg->method_index << 16) | cfg->castclass_cache_index;
4454 }
4455
4456 static MonoInst*
4457 emit_castclass_with_cache_nonshared (MonoCompile *cfg, MonoInst *obj, MonoClass *klass)
4458 {
4459         MonoInst *args [3];
4460         int idx;
4461
4462         /* obj */
4463         args [0] = obj;
4464
4465         /* klass */
4466         EMIT_NEW_CLASSCONST (cfg, args [1], klass);
4467
4468         /* inline cache*/
4469         if (cfg->compile_aot) {
4470                 idx = get_castclass_cache_idx (cfg);
4471                 EMIT_NEW_AOTCONST (cfg, args [2], MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
4472         } else {
4473                 EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));
4474         }
4475
4476         /*The wrapper doesn't inline well so the bloat of inlining doesn't pay off.*/
4477         return emit_castclass_with_cache (cfg, klass, args);
4478 }
4479
4480 /*
4481  * Returns NULL and set the cfg exception on error.
4482  */
4483 static MonoInst*
4484 handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, guint8 *ip, int *inline_costs)
4485 {
4486         MonoBasicBlock *is_null_bb;
4487         int obj_reg = src->dreg;
4488         int vtable_reg = alloc_preg (cfg);
4489         int context_used;
4490         MonoInst *klass_inst = NULL, *res;
4491
4492         context_used = mini_class_check_context_used (cfg, klass);
4493
4494         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
4495                 res = emit_castclass_with_cache_nonshared (cfg, src, klass);
4496                 (*inline_costs) += 2;
4497                 return res;
4498         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
4499                 MonoMethod *mono_castclass;
4500                 MonoInst *iargs [1];
4501                 int costs;
4502
4503                 mono_castclass = mono_marshal_get_castclass (klass); 
4504                 iargs [0] = src;
4505                                 
4506                 save_cast_details (cfg, klass, src->dreg, TRUE);
4507                 costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), 
4508                                                            iargs, ip, cfg->real_offset, TRUE);
4509                 reset_cast_details (cfg);
4510                 CHECK_CFG_EXCEPTION;
4511                 g_assert (costs > 0);
4512                                 
4513                 cfg->real_offset += 5;
4514
4515                 (*inline_costs) += costs;
4516
4517                 return src;
4518         }
4519
4520         if (context_used) {
4521                 MonoInst *args [3];
4522
4523                 if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
4524                         MonoInst *cache_ins;
4525
4526                         cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
4527
4528                         /* obj */
4529                         args [0] = src;
4530
4531                         /* klass - it's the second element of the cache entry*/
4532                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
4533
4534                         /* cache */
4535                         args [2] = cache_ins;
4536
4537                         return emit_castclass_with_cache (cfg, klass, args);
4538                 }
4539
4540                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
4541         }
4542
4543         NEW_BBLOCK (cfg, is_null_bb);
4544
4545         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4546         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
4547
4548         save_cast_details (cfg, klass, obj_reg, FALSE);
4549
4550         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4551                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4552                 mini_emit_iface_cast (cfg, vtable_reg, klass, NULL, NULL);
4553         } else {
4554                 int klass_reg = alloc_preg (cfg);
4555
4556                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4557
4558                 if (!klass->rank && !cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
4559                         /* the remoting code is broken, access the class for now */
4560                         if (0) { /*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4561                                 MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4562                                 if (!vt) {
4563                                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4564                                         cfg->exception_ptr = klass;
4565                                         return NULL;
4566                                 }
4567                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4568                         } else {
4569                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4570                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4571                         }
4572                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4573                 } else {
4574                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4575                         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, klass_inst, is_null_bb);
4576                 }
4577         }
4578
4579         MONO_START_BB (cfg, is_null_bb);
4580
4581         reset_cast_details (cfg);
4582
4583         return src;
4584
4585 exception_exit:
4586         return NULL;
4587 }
4588
4589 /*
4590  * Returns NULL and set the cfg exception on error.
4591  */
4592 static MonoInst*
4593 handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
4594 {
4595         MonoInst *ins;
4596         MonoBasicBlock *is_null_bb, *false_bb, *end_bb;
4597         int obj_reg = src->dreg;
4598         int vtable_reg = alloc_preg (cfg);
4599         int res_reg = alloc_ireg_ref (cfg);
4600         MonoInst *klass_inst = NULL;
4601
4602         if (context_used) {
4603                 MonoInst *args [3];
4604
4605                 if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
4606                         MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
4607                         MonoInst *cache_ins;
4608
4609                         cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
4610
4611                         /* obj */
4612                         args [0] = src;
4613
4614                         /* klass - it's the second element of the cache entry*/
4615                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
4616
4617                         /* cache */
4618                         args [2] = cache_ins;
4619
4620                         return mono_emit_method_call (cfg, mono_isinst, args, NULL);
4621                 }
4622
4623                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
4624         }
4625
4626         NEW_BBLOCK (cfg, is_null_bb);
4627         NEW_BBLOCK (cfg, false_bb);
4628         NEW_BBLOCK (cfg, end_bb);
4629
4630         /* Do the assignment at the beginning, so the other assignment can be if converted */
4631         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, res_reg, obj_reg);
4632         ins->type = STACK_OBJ;
4633         ins->klass = klass;
4634
4635         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4636         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_null_bb);
4637
4638         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4639
4640         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4641                 g_assert (!context_used);
4642                 /* the is_null_bb target simply copies the input register to the output */
4643                 mini_emit_iface_cast (cfg, vtable_reg, klass, false_bb, is_null_bb);
4644         } else {
4645                 int klass_reg = alloc_preg (cfg);
4646
4647                 if (klass->rank) {
4648                         int rank_reg = alloc_preg (cfg);
4649                         int eclass_reg = alloc_preg (cfg);
4650
4651                         g_assert (!context_used);
4652                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
4653                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
4654                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4655                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4656                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
4657                         if (klass->cast_class == mono_defaults.object_class) {
4658                                 int parent_reg = alloc_preg (cfg);
4659                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
4660                                 mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, is_null_bb);
4661                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4662                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4663                         } else if (klass->cast_class == mono_defaults.enum_class->parent) {
4664                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, is_null_bb);
4665                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);                          
4666                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4667                         } else if (klass->cast_class == mono_defaults.enum_class) {
4668                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4669                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4670                         } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
4671                                 mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4672                         } else {
4673                                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY)) {
4674                                         /* Check that the object is a vector too */
4675                                         int bounds_reg = alloc_preg (cfg);
4676                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
4677                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
4678                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4679                                 }
4680
4681                                 /* the is_null_bb target simply copies the input register to the output */
4682                                 mini_emit_isninst_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4683                         }
4684                 } else if (mono_class_is_nullable (klass)) {
4685                         g_assert (!context_used);
4686                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4687                         /* the is_null_bb target simply copies the input register to the output */
4688                         mini_emit_isninst_cast (cfg, klass_reg, klass->cast_class, false_bb, is_null_bb);
4689                 } else {
4690                         if (!cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
4691                                 g_assert (!context_used);
4692                                 /* the remoting code is broken, access the class for now */
4693                                 if (0) {/*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4694                                         MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4695                                         if (!vt) {
4696                                                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4697                                                 cfg->exception_ptr = klass;
4698                                                 return NULL;
4699                                         }
4700                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4701                                 } else {
4702                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4703                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4704                                 }
4705                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4706                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, is_null_bb);
4707                         } else {
4708                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4709                                 /* the is_null_bb target simply copies the input register to the output */
4710                                 mini_emit_isninst_cast_inst (cfg, klass_reg, klass, klass_inst, false_bb, is_null_bb);
4711                         }
4712                 }
4713         }
4714
4715         MONO_START_BB (cfg, false_bb);
4716
4717         MONO_EMIT_NEW_PCONST (cfg, res_reg, 0);
4718         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4719
4720         MONO_START_BB (cfg, is_null_bb);
4721
4722         MONO_START_BB (cfg, end_bb);
4723
4724         return ins;
4725 }
4726
4727 static MonoInst*
4728 handle_cisinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4729 {
4730         /* This opcode takes as input an object reference and a class, and returns:
4731         0) if the object is an instance of the class,
4732         1) if the object is not instance of the class,
4733         2) if the object is a proxy whose type cannot be determined */
4734
4735         MonoInst *ins;
4736 #ifndef DISABLE_REMOTING
4737         MonoBasicBlock *true_bb, *false_bb, *false2_bb, *end_bb, *no_proxy_bb, *interface_fail_bb;
4738 #else
4739         MonoBasicBlock *true_bb, *false_bb, *end_bb;
4740 #endif
4741         int obj_reg = src->dreg;
4742         int dreg = alloc_ireg (cfg);
4743         int tmp_reg;
4744 #ifndef DISABLE_REMOTING
4745         int klass_reg = alloc_preg (cfg);
4746 #endif
4747
4748         NEW_BBLOCK (cfg, true_bb);
4749         NEW_BBLOCK (cfg, false_bb);
4750         NEW_BBLOCK (cfg, end_bb);
4751 #ifndef DISABLE_REMOTING
4752         NEW_BBLOCK (cfg, false2_bb);
4753         NEW_BBLOCK (cfg, no_proxy_bb);
4754 #endif
4755
4756         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4757         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, false_bb);
4758
4759         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4760 #ifndef DISABLE_REMOTING
4761                 NEW_BBLOCK (cfg, interface_fail_bb);
4762 #endif
4763
4764                 tmp_reg = alloc_preg (cfg);
4765                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4766 #ifndef DISABLE_REMOTING
4767                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, true_bb);
4768                 MONO_START_BB (cfg, interface_fail_bb);
4769                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4770                 
4771                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, false_bb);
4772
4773                 tmp_reg = alloc_preg (cfg);
4774                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4775                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4776                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false2_bb);                
4777 #else
4778                 mini_emit_iface_cast (cfg, tmp_reg, klass, false_bb, true_bb);
4779 #endif
4780         } else {
4781 #ifndef DISABLE_REMOTING
4782                 tmp_reg = alloc_preg (cfg);
4783                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4784                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4785
4786                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4787                 tmp_reg = alloc_preg (cfg);
4788                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4789                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4790
4791                 tmp_reg = alloc_preg (cfg);             
4792                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4793                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4794                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4795                 
4796                 mini_emit_isninst_cast (cfg, klass_reg, klass, false2_bb, true_bb);
4797                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false2_bb);
4798
4799                 MONO_START_BB (cfg, no_proxy_bb);
4800
4801                 mini_emit_isninst_cast (cfg, klass_reg, klass, false_bb, true_bb);
4802 #else
4803                 g_error ("transparent proxy support is disabled while trying to JIT code that uses it");
4804 #endif
4805         }
4806
4807         MONO_START_BB (cfg, false_bb);
4808
4809         MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4810         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4811
4812 #ifndef DISABLE_REMOTING
4813         MONO_START_BB (cfg, false2_bb);
4814
4815         MONO_EMIT_NEW_ICONST (cfg, dreg, 2);
4816         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4817 #endif
4818
4819         MONO_START_BB (cfg, true_bb);
4820
4821         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4822
4823         MONO_START_BB (cfg, end_bb);
4824
4825         /* FIXME: */
4826         MONO_INST_NEW (cfg, ins, OP_ICONST);
4827         ins->dreg = dreg;
4828         ins->type = STACK_I4;
4829
4830         return ins;
4831 }
4832
4833 static MonoInst*
4834 handle_ccastclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4835 {
4836         /* This opcode takes as input an object reference and a class, and returns:
4837         0) if the object is an instance of the class,
4838         1) if the object is a proxy whose type cannot be determined
4839         an InvalidCastException exception is thrown otherwhise*/
4840         
4841         MonoInst *ins;
4842 #ifndef DISABLE_REMOTING
4843         MonoBasicBlock *end_bb, *ok_result_bb, *no_proxy_bb, *interface_fail_bb, *fail_1_bb;
4844 #else
4845         MonoBasicBlock *ok_result_bb;
4846 #endif
4847         int obj_reg = src->dreg;
4848         int dreg = alloc_ireg (cfg);
4849         int tmp_reg = alloc_preg (cfg);
4850
4851 #ifndef DISABLE_REMOTING
4852         int klass_reg = alloc_preg (cfg);
4853         NEW_BBLOCK (cfg, end_bb);
4854 #endif
4855
4856         NEW_BBLOCK (cfg, ok_result_bb);
4857
4858         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4859         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, ok_result_bb);
4860
4861         save_cast_details (cfg, klass, obj_reg, FALSE);
4862
4863         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4864 #ifndef DISABLE_REMOTING
4865                 NEW_BBLOCK (cfg, interface_fail_bb);
4866         
4867                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4868                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, ok_result_bb);
4869                 MONO_START_BB (cfg, interface_fail_bb);
4870                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4871
4872                 mini_emit_class_check (cfg, klass_reg, mono_defaults.transparent_proxy_class);
4873
4874                 tmp_reg = alloc_preg (cfg);             
4875                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4876                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4877                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
4878                 
4879                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4880                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4881 #else
4882                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4883                 mini_emit_iface_cast (cfg, tmp_reg, klass, NULL, NULL);
4884                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, ok_result_bb);
4885 #endif
4886         } else {
4887 #ifndef DISABLE_REMOTING
4888                 NEW_BBLOCK (cfg, no_proxy_bb);
4889
4890                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4891                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4892                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4893
4894                 tmp_reg = alloc_preg (cfg);
4895                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4896                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4897
4898                 tmp_reg = alloc_preg (cfg);
4899                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4900                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4901                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4902
4903                 NEW_BBLOCK (cfg, fail_1_bb);
4904                 
4905                 mini_emit_isninst_cast (cfg, klass_reg, klass, fail_1_bb, ok_result_bb);
4906
4907                 MONO_START_BB (cfg, fail_1_bb);
4908
4909                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4910                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4911
4912                 MONO_START_BB (cfg, no_proxy_bb);
4913
4914                 mini_emit_castclass (cfg, obj_reg, klass_reg, klass, ok_result_bb);
4915 #else
4916                 g_error ("Transparent proxy support is disabled while trying to JIT code that uses it");
4917 #endif
4918         }
4919
4920         MONO_START_BB (cfg, ok_result_bb);
4921
4922         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4923
4924 #ifndef DISABLE_REMOTING
4925         MONO_START_BB (cfg, end_bb);
4926 #endif
4927
4928         /* FIXME: */
4929         MONO_INST_NEW (cfg, ins, OP_ICONST);
4930         ins->dreg = dreg;
4931         ins->type = STACK_I4;
4932
4933         return ins;
4934 }
4935
4936 static G_GNUC_UNUSED MonoInst*
4937 handle_enum_has_flag (MonoCompile *cfg, MonoClass *klass, MonoInst *enum_this, MonoInst *enum_flag)
4938 {
4939         MonoType *enum_type = mono_type_get_underlying_type (&klass->byval_arg);
4940         guint32 load_opc = mono_type_to_load_membase (cfg, enum_type);
4941         gboolean is_i4;
4942
4943         switch (enum_type->type) {
4944         case MONO_TYPE_I8:
4945         case MONO_TYPE_U8:
4946 #if SIZEOF_REGISTER == 8
4947         case MONO_TYPE_I:
4948         case MONO_TYPE_U:
4949 #endif
4950                 is_i4 = FALSE;
4951                 break;
4952         default:
4953                 is_i4 = TRUE;
4954                 break;
4955         }
4956
4957         {
4958                 MonoInst *load, *and, *cmp, *ceq;
4959                 int enum_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
4960                 int and_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
4961                 int dest_reg = alloc_ireg (cfg);
4962
4963                 EMIT_NEW_LOAD_MEMBASE (cfg, load, load_opc, enum_reg, enum_this->dreg, 0);
4964                 EMIT_NEW_BIALU (cfg, and, is_i4 ? OP_IAND : OP_LAND, and_reg, enum_reg, enum_flag->dreg);
4965                 EMIT_NEW_BIALU (cfg, cmp, is_i4 ? OP_ICOMPARE : OP_LCOMPARE, -1, and_reg, enum_flag->dreg);
4966                 EMIT_NEW_UNALU (cfg, ceq, is_i4 ? OP_ICEQ : OP_LCEQ, dest_reg, -1);
4967
4968                 ceq->type = STACK_I4;
4969
4970                 if (!is_i4) {
4971                         load = mono_decompose_opcode (cfg, load);
4972                         and = mono_decompose_opcode (cfg, and);
4973                         cmp = mono_decompose_opcode (cfg, cmp);
4974                         ceq = mono_decompose_opcode (cfg, ceq);
4975                 }
4976
4977                 return ceq;
4978         }
4979 }
4980
4981 /*
4982  * Returns NULL and set the cfg exception on error.
4983  */
4984 static G_GNUC_UNUSED MonoInst*
4985 handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, MonoMethod *method, int context_used, gboolean virtual)
4986 {
4987         MonoInst *ptr;
4988         int dreg;
4989         gpointer trampoline;
4990         MonoInst *obj, *method_ins, *tramp_ins;
4991         MonoDomain *domain;
4992         guint8 **code_slot;
4993
4994         if (virtual && !cfg->llvm_only) {
4995                 MonoMethod *invoke = mono_get_delegate_invoke (klass);
4996                 g_assert (invoke);
4997
4998                 if (!mono_get_delegate_virtual_invoke_impl (mono_method_signature (invoke), context_used ? NULL : method))
4999                         return NULL;
5000         }
5001
5002         obj = handle_alloc (cfg, klass, FALSE, mono_class_check_context_used (klass));
5003         if (!obj)
5004                 return NULL;
5005
5006         if (cfg->llvm_only) {
5007                 MonoInst *args [16];
5008
5009                 /*
5010                  * If the method to be called needs an rgctx, we can't fall back to mono_delegate_ctor (), since it might receive
5011                  * the address of a gshared method. So use a JIT icall.
5012                  * FIXME: Optimize this.
5013                  */
5014                 args [0] = obj;
5015                 args [1] = target;
5016                 args [2] = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
5017                 mono_emit_jit_icall (cfg, virtual ? mono_init_delegate_virtual : mono_init_delegate, args);
5018
5019                 return obj;
5020         }
5021
5022         /* Inline the contents of mono_delegate_ctor */
5023
5024         /* Set target field */
5025         /* Optimize away setting of NULL target */
5026         if (!(target->opcode == OP_PCONST && target->inst_p0 == 0)) {
5027                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target), target->dreg);
5028                 if (cfg->gen_write_barriers) {
5029                         dreg = alloc_preg (cfg);
5030                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target));
5031                         emit_write_barrier (cfg, ptr, target);
5032                 }
5033         }
5034
5035         /* Set method field */
5036         method_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
5037         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method), method_ins->dreg);
5038
5039         /* 
5040          * To avoid looking up the compiled code belonging to the target method
5041          * in mono_delegate_trampoline (), we allocate a per-domain memory slot to
5042          * store it, and we fill it after the method has been compiled.
5043          */
5044         if (!method->dynamic && !(cfg->opt & MONO_OPT_SHARED)) {
5045                 MonoInst *code_slot_ins;
5046
5047                 if (context_used) {
5048                         code_slot_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD_DELEGATE_CODE);
5049                 } else {
5050                         domain = mono_domain_get ();
5051                         mono_domain_lock (domain);
5052                         if (!domain_jit_info (domain)->method_code_hash)
5053                                 domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
5054                         code_slot = g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, method);
5055                         if (!code_slot) {
5056                                 code_slot = mono_domain_alloc0 (domain, sizeof (gpointer));
5057                                 g_hash_table_insert (domain_jit_info (domain)->method_code_hash, method, code_slot);
5058                         }
5059                         mono_domain_unlock (domain);
5060
5061                         if (cfg->compile_aot)
5062                                 EMIT_NEW_AOTCONST (cfg, code_slot_ins, MONO_PATCH_INFO_METHOD_CODE_SLOT, method);
5063                         else
5064                                 EMIT_NEW_PCONST (cfg, code_slot_ins, code_slot);
5065                 }
5066                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_code), code_slot_ins->dreg);                
5067         }
5068
5069         if (cfg->compile_aot) {
5070                 MonoDelegateClassMethodPair *del_tramp;
5071
5072                 del_tramp = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoDelegateClassMethodPair));
5073                 del_tramp->klass = klass;
5074                 del_tramp->method = context_used ? NULL : method;
5075                 del_tramp->is_virtual = virtual;
5076                 EMIT_NEW_AOTCONST (cfg, tramp_ins, MONO_PATCH_INFO_DELEGATE_TRAMPOLINE, del_tramp);
5077         } else {
5078                 if (virtual)
5079                         trampoline = mono_create_delegate_virtual_trampoline (cfg->domain, klass, context_used ? NULL : method);
5080                 else
5081                         trampoline = mono_create_delegate_trampoline_info (cfg->domain, klass, context_used ? NULL : method);
5082                 EMIT_NEW_PCONST (cfg, tramp_ins, trampoline);
5083         }
5084
5085         /* Set invoke_impl field */
5086         if (virtual) {
5087                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), tramp_ins->dreg);
5088         } else {
5089                 dreg = alloc_preg (cfg);
5090                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, invoke_impl));
5091                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), dreg);
5092
5093                 dreg = alloc_preg (cfg);
5094                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, method_ptr));
5095                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr), dreg);
5096         }
5097
5098         dreg = alloc_preg (cfg);
5099         MONO_EMIT_NEW_ICONST (cfg, dreg, virtual ? 1 : 0);
5100         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_is_virtual), dreg);
5101
5102         /* All the checks which are in mono_delegate_ctor () are done by the delegate trampoline */
5103
5104         return obj;
5105 }
5106
5107 static MonoInst*
5108 handle_array_new (MonoCompile *cfg, int rank, MonoInst **sp, unsigned char *ip)
5109 {
5110         MonoJitICallInfo *info;
5111
5112         /* Need to register the icall so it gets an icall wrapper */
5113         info = mono_get_array_new_va_icall (rank);
5114
5115         cfg->flags |= MONO_CFG_HAS_VARARGS;
5116
5117         /* mono_array_new_va () needs a vararg calling convention */
5118         cfg->disable_llvm = TRUE;
5119
5120         /* FIXME: This uses info->sig, but it should use the signature of the wrapper */
5121         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, sp);
5122 }
5123
5124 /*
5125  * handle_constrained_gsharedvt_call:
5126  *
5127  *   Handle constrained calls where the receiver is a gsharedvt type.
5128  * Return the instruction representing the call. Set the cfg exception on failure.
5129  */
5130 static MonoInst*
5131 handle_constrained_gsharedvt_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp, MonoClass *constrained_class,
5132                                                                    gboolean *ref_emit_widen)
5133 {
5134         MonoInst *ins = NULL;
5135         gboolean emit_widen = *ref_emit_widen;
5136
5137         /*
5138          * Constrained calls need to behave differently at runtime dependending on whenever the receiver is instantiated as ref type or as a vtype.
5139          * 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
5140          * pack the arguments into an array, and do the rest of the work in in an icall.
5141          */
5142         if (((cmethod->klass == mono_defaults.object_class) || (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) || (!cmethod->klass->valuetype && cmethod->klass->image != mono_defaults.corlib)) &&
5143                 (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)) &&
5144                 (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]))))) {
5145                 MonoInst *args [16];
5146
5147                 /*
5148                  * This case handles calls to
5149                  * - object:ToString()/Equals()/GetHashCode(),
5150                  * - System.IComparable<T>:CompareTo()
5151                  * - System.IEquatable<T>:Equals ()
5152                  * plus some simple interface calls enough to support AsyncTaskMethodBuilder.
5153                  */
5154
5155                 args [0] = sp [0];
5156                 if (mono_method_check_context_used (cmethod))
5157                         args [1] = emit_get_rgctx_method (cfg, mono_method_check_context_used (cmethod), cmethod, MONO_RGCTX_INFO_METHOD);
5158                 else
5159                         EMIT_NEW_METHODCONST (cfg, args [1], cmethod);
5160                 args [2] = emit_get_rgctx_klass (cfg, mono_class_check_context_used (constrained_class), constrained_class, MONO_RGCTX_INFO_KLASS);
5161
5162                 /* !fsig->hasthis is for the wrapper for the Object.GetType () icall */
5163                 if (fsig->hasthis && fsig->param_count) {
5164                         /* Pass the arguments using a localloc-ed array using the format expected by runtime_invoke () */
5165                         MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
5166                         ins->dreg = alloc_preg (cfg);
5167                         ins->inst_imm = fsig->param_count * sizeof (mgreg_t);
5168                         MONO_ADD_INS (cfg->cbb, ins);
5169                         args [4] = ins;
5170
5171                         if (mini_is_gsharedvt_type (fsig->params [0])) {
5172                                 int addr_reg;
5173
5174                                 args [3] = emit_get_gsharedvt_info_klass (cfg, mono_class_from_mono_type (fsig->params [0]), MONO_RGCTX_INFO_CLASS_BOX_TYPE);
5175
5176                                 EMIT_NEW_VARLOADA_VREG (cfg, ins, sp [1]->dreg, fsig->params [0]);
5177                                 addr_reg = ins->dreg;
5178                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, addr_reg);
5179                         } else {
5180                                 EMIT_NEW_ICONST (cfg, args [3], 0);
5181                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, sp [1]->dreg);
5182                         }
5183                 } else {
5184                         EMIT_NEW_ICONST (cfg, args [3], 0);
5185                         EMIT_NEW_ICONST (cfg, args [4], 0);
5186                 }
5187                 ins = mono_emit_jit_icall (cfg, mono_gsharedvt_constrained_call, args);
5188                 emit_widen = FALSE;
5189
5190                 if (mini_is_gsharedvt_type (fsig->ret)) {
5191                         ins = handle_unbox_gsharedvt (cfg, mono_class_from_mono_type (fsig->ret), ins);
5192                 } else if (MONO_TYPE_IS_PRIMITIVE (fsig->ret) || MONO_TYPE_ISSTRUCT (fsig->ret)) {
5193                         MonoInst *add;
5194
5195                         /* Unbox */
5196                         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), ins->dreg, sizeof (MonoObject));
5197                         MONO_ADD_INS (cfg->cbb, add);
5198                         /* Load value */
5199                         NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, add->dreg, 0);
5200                         MONO_ADD_INS (cfg->cbb, ins);
5201                         /* ins represents the call result */
5202                 }
5203         } else {
5204                 GSHAREDVT_FAILURE (CEE_CALLVIRT);
5205         }
5206
5207         *ref_emit_widen = emit_widen;
5208
5209         return ins;
5210
5211  exception_exit:
5212         return NULL;
5213 }
5214
5215 static void
5216 mono_emit_load_got_addr (MonoCompile *cfg)
5217 {
5218         MonoInst *getaddr, *dummy_use;
5219
5220         if (!cfg->got_var || cfg->got_var_allocated)
5221                 return;
5222
5223         MONO_INST_NEW (cfg, getaddr, OP_LOAD_GOTADDR);
5224         getaddr->cil_code = cfg->header->code;
5225         getaddr->dreg = cfg->got_var->dreg;
5226
5227         /* Add it to the start of the first bblock */
5228         if (cfg->bb_entry->code) {
5229                 getaddr->next = cfg->bb_entry->code;
5230                 cfg->bb_entry->code = getaddr;
5231         }
5232         else
5233                 MONO_ADD_INS (cfg->bb_entry, getaddr);
5234
5235         cfg->got_var_allocated = TRUE;
5236
5237         /* 
5238          * Add a dummy use to keep the got_var alive, since real uses might
5239          * only be generated by the back ends.
5240          * Add it to end_bblock, so the variable's lifetime covers the whole
5241          * method.
5242          * It would be better to make the usage of the got var explicit in all
5243          * cases when the backend needs it (i.e. calls, throw etc.), so this
5244          * wouldn't be needed.
5245          */
5246         NEW_DUMMY_USE (cfg, dummy_use, cfg->got_var);
5247         MONO_ADD_INS (cfg->bb_exit, dummy_use);
5248 }
5249
5250 static int inline_limit;
5251 static gboolean inline_limit_inited;
5252
5253 static gboolean
5254 mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
5255 {
5256         MonoMethodHeaderSummary header;
5257         MonoVTable *vtable;
5258 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
5259         MonoMethodSignature *sig = mono_method_signature (method);
5260         int i;
5261 #endif
5262
5263         if (cfg->disable_inline)
5264                 return FALSE;
5265         if (cfg->gshared)
5266                 return FALSE;
5267
5268         if (cfg->inline_depth > 10)
5269                 return FALSE;
5270
5271         if (!mono_method_get_header_summary (method, &header))
5272                 return FALSE;
5273
5274         /*runtime, icall and pinvoke are checked by summary call*/
5275         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
5276             (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
5277             (mono_class_is_marshalbyref (method->klass)) ||
5278             header.has_clauses)
5279                 return FALSE;
5280
5281         /* also consider num_locals? */
5282         /* Do the size check early to avoid creating vtables */
5283         if (!inline_limit_inited) {
5284                 if (g_getenv ("MONO_INLINELIMIT"))
5285                         inline_limit = atoi (g_getenv ("MONO_INLINELIMIT"));
5286                 else
5287                         inline_limit = INLINE_LENGTH_LIMIT;
5288                 inline_limit_inited = TRUE;
5289         }
5290         if (header.code_size >= inline_limit && !(method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))
5291                 return FALSE;
5292
5293         /*
5294          * if we can initialize the class of the method right away, we do,
5295          * otherwise we don't allow inlining if the class needs initialization,
5296          * since it would mean inserting a call to mono_runtime_class_init()
5297          * inside the inlined code
5298          */
5299         if (!(cfg->opt & MONO_OPT_SHARED)) {
5300                 /* The AggressiveInlining hint is a good excuse to force that cctor to run. */
5301                 if (method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING) {
5302                         vtable = mono_class_vtable (cfg->domain, method->klass);
5303                         if (!vtable)
5304                                 return FALSE;
5305                         if (!cfg->compile_aot)
5306                                 mono_runtime_class_init (vtable);
5307                 } else if (method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
5308                         if (cfg->run_cctors && method->klass->has_cctor) {
5309                                 /*FIXME it would easier and lazier to just use mono_class_try_get_vtable */
5310                                 if (!method->klass->runtime_info)
5311                                         /* No vtable created yet */
5312                                         return FALSE;
5313                                 vtable = mono_class_vtable (cfg->domain, method->klass);
5314                                 if (!vtable)
5315                                         return FALSE;
5316                                 /* This makes so that inline cannot trigger */
5317                                 /* .cctors: too many apps depend on them */
5318                                 /* running with a specific order... */
5319                                 if (! vtable->initialized)
5320                                         return FALSE;
5321                                 mono_runtime_class_init (vtable);
5322                         }
5323                 } else if (mono_class_needs_cctor_run (method->klass, NULL)) {
5324                         if (!method->klass->runtime_info)
5325                                 /* No vtable created yet */
5326                                 return FALSE;
5327                         vtable = mono_class_vtable (cfg->domain, method->klass);
5328                         if (!vtable)
5329                                 return FALSE;
5330                         if (!vtable->initialized)
5331                                 return FALSE;
5332                 }
5333         } else {
5334                 /* 
5335                  * If we're compiling for shared code
5336                  * the cctor will need to be run at aot method load time, for example,
5337                  * or at the end of the compilation of the inlining method.
5338                  */
5339                 if (mono_class_needs_cctor_run (method->klass, NULL) && !((method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)))
5340                         return FALSE;
5341         }
5342
5343 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
5344         if (mono_arch_is_soft_float ()) {
5345                 /* FIXME: */
5346                 if (sig->ret && sig->ret->type == MONO_TYPE_R4)
5347                         return FALSE;
5348                 for (i = 0; i < sig->param_count; ++i)
5349                         if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_R4)
5350                                 return FALSE;
5351         }
5352 #endif
5353
5354         if (g_list_find (cfg->dont_inline, method))
5355                 return FALSE;
5356
5357         return TRUE;
5358 }
5359
5360 static gboolean
5361 mini_field_access_needs_cctor_run (MonoCompile *cfg, MonoMethod *method, MonoClass *klass, MonoVTable *vtable)
5362 {
5363         if (!cfg->compile_aot) {
5364                 g_assert (vtable);
5365                 if (vtable->initialized)
5366                         return FALSE;
5367         }
5368
5369         if (klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
5370                 if (cfg->method == method)
5371                         return FALSE;
5372         }
5373
5374         if (!mono_class_needs_cctor_run (klass, method))
5375                 return FALSE;
5376
5377         if (! (method->flags & METHOD_ATTRIBUTE_STATIC) && (klass == method->klass))
5378                 /* The initialization is already done before the method is called */
5379                 return FALSE;
5380
5381         return TRUE;
5382 }
5383
5384 static MonoInst*
5385 mini_emit_ldelema_1_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index, gboolean bcheck)
5386 {
5387         MonoInst *ins;
5388         guint32 size;
5389         int mult_reg, add_reg, array_reg, index_reg, index2_reg;
5390         int context_used;
5391
5392         if (mini_is_gsharedvt_variable_klass (klass)) {
5393                 size = -1;
5394         } else {
5395                 mono_class_init (klass);
5396                 size = mono_class_array_element_size (klass);
5397         }
5398
5399         mult_reg = alloc_preg (cfg);
5400         array_reg = arr->dreg;
5401         index_reg = index->dreg;
5402
5403 #if SIZEOF_REGISTER == 8
5404         /* The array reg is 64 bits but the index reg is only 32 */
5405         if (COMPILE_LLVM (cfg)) {
5406                 /* Not needed */
5407                 index2_reg = index_reg;
5408         } else {
5409                 index2_reg = alloc_preg (cfg);
5410                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index2_reg, index_reg);
5411         }
5412 #else
5413         if (index->type == STACK_I8) {
5414                 index2_reg = alloc_preg (cfg);
5415                 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I4, index2_reg, index_reg);
5416         } else {
5417                 index2_reg = index_reg;
5418         }
5419 #endif
5420
5421         if (bcheck)
5422                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index2_reg);
5423
5424 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5425         if (size == 1 || size == 2 || size == 4 || size == 8) {
5426                 static const int fast_log2 [] = { 1, 0, 1, -1, 2, -1, -1, -1, 3 };
5427
5428                 EMIT_NEW_X86_LEA (cfg, ins, array_reg, index2_reg, fast_log2 [size], MONO_STRUCT_OFFSET (MonoArray, vector));
5429                 ins->klass = mono_class_get_element_class (klass);
5430                 ins->type = STACK_MP;
5431
5432                 return ins;
5433         }
5434 #endif          
5435
5436         add_reg = alloc_ireg_mp (cfg);
5437
5438         if (size == -1) {
5439                 MonoInst *rgctx_ins;
5440
5441                 /* gsharedvt */
5442                 g_assert (cfg->gshared);
5443                 context_used = mini_class_check_context_used (cfg, klass);
5444                 g_assert (context_used);
5445                 rgctx_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE);
5446                 MONO_EMIT_NEW_BIALU (cfg, OP_IMUL, mult_reg, index2_reg, rgctx_ins->dreg);
5447         } else {
5448                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MUL_IMM, mult_reg, index2_reg, size);
5449         }
5450         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, array_reg, mult_reg);
5451         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
5452         ins->klass = mono_class_get_element_class (klass);
5453         ins->type = STACK_MP;
5454         MONO_ADD_INS (cfg->cbb, ins);
5455
5456         return ins;
5457 }
5458
5459 #ifndef MONO_ARCH_EMULATE_MUL_DIV
5460 static MonoInst*
5461 mini_emit_ldelema_2_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index_ins1, MonoInst *index_ins2)
5462 {
5463         int bounds_reg = alloc_preg (cfg);
5464         int add_reg = alloc_ireg_mp (cfg);
5465         int mult_reg = alloc_preg (cfg);
5466         int mult2_reg = alloc_preg (cfg);
5467         int low1_reg = alloc_preg (cfg);
5468         int low2_reg = alloc_preg (cfg);
5469         int high1_reg = alloc_preg (cfg);
5470         int high2_reg = alloc_preg (cfg);
5471         int realidx1_reg = alloc_preg (cfg);
5472         int realidx2_reg = alloc_preg (cfg);
5473         int sum_reg = alloc_preg (cfg);
5474         int index1, index2, tmpreg;
5475         MonoInst *ins;
5476         guint32 size;
5477
5478         mono_class_init (klass);
5479         size = mono_class_array_element_size (klass);
5480
5481         index1 = index_ins1->dreg;
5482         index2 = index_ins2->dreg;
5483
5484 #if SIZEOF_REGISTER == 8
5485         /* The array reg is 64 bits but the index reg is only 32 */
5486         if (COMPILE_LLVM (cfg)) {
5487                 /* Not needed */
5488         } else {
5489                 tmpreg = alloc_preg (cfg);
5490                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index1);
5491                 index1 = tmpreg;
5492                 tmpreg = alloc_preg (cfg);
5493                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index2);
5494                 index2 = tmpreg;
5495         }
5496 #else
5497         // FIXME: Do we need to do something here for i8 indexes, like in ldelema_1_ins ?
5498         tmpreg = -1;
5499 #endif
5500
5501         /* range checking */
5502         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, 
5503                                        arr->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
5504
5505         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low1_reg, 
5506                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5507         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx1_reg, index1, low1_reg);
5508         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high1_reg, 
5509                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5510         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high1_reg, realidx1_reg);
5511         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
5512
5513         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low2_reg, 
5514                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5515         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx2_reg, index2, low2_reg);
5516         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high2_reg, 
5517                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5518         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high2_reg, realidx2_reg);
5519         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
5520
5521         MONO_EMIT_NEW_BIALU (cfg, OP_PMUL, mult_reg, high2_reg, realidx1_reg);
5522         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, mult_reg, realidx2_reg);
5523         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PMUL_IMM, mult2_reg, sum_reg, size);
5524         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult2_reg, arr->dreg);
5525         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
5526
5527         ins->type = STACK_MP;
5528         ins->klass = klass;
5529         MONO_ADD_INS (cfg->cbb, ins);
5530
5531         return ins;
5532 }
5533 #endif
5534
5535 static MonoInst*
5536 mini_emit_ldelema_ins (MonoCompile *cfg, MonoMethod *cmethod, MonoInst **sp, unsigned char *ip, gboolean is_set)
5537 {
5538         int rank;
5539         MonoInst *addr;
5540         MonoMethod *addr_method;
5541         int element_size;
5542         MonoClass *eclass = cmethod->klass->element_class;
5543
5544         rank = mono_method_signature (cmethod)->param_count - (is_set? 1: 0);
5545
5546         if (rank == 1)
5547                 return mini_emit_ldelema_1_ins (cfg, eclass, sp [0], sp [1], TRUE);
5548
5549 #ifndef MONO_ARCH_EMULATE_MUL_DIV
5550         /* emit_ldelema_2 depends on OP_LMUL */
5551         if (rank == 2 && (cfg->opt & MONO_OPT_INTRINS) && !mini_is_gsharedvt_variable_klass (eclass)) {
5552                 return mini_emit_ldelema_2_ins (cfg, eclass, sp [0], sp [1], sp [2]);
5553         }
5554 #endif
5555
5556         if (mini_is_gsharedvt_variable_klass (eclass))
5557                 element_size = 0;
5558         else
5559                 element_size = mono_class_array_element_size (eclass);
5560         addr_method = mono_marshal_get_array_address (rank, element_size);
5561         addr = mono_emit_method_call (cfg, addr_method, sp, NULL);
5562
5563         return addr;
5564 }
5565
5566 static MonoBreakPolicy
5567 always_insert_breakpoint (MonoMethod *method)
5568 {
5569         return MONO_BREAK_POLICY_ALWAYS;
5570 }
5571
5572 static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
5573
5574 /**
5575  * mono_set_break_policy:
5576  * policy_callback: the new callback function
5577  *
5578  * Allow embedders to decide wherther to actually obey breakpoint instructions
5579  * (both break IL instructions and Debugger.Break () method calls), for example
5580  * to not allow an app to be aborted by a perfectly valid IL opcode when executing
5581  * untrusted or semi-trusted code.
5582  *
5583  * @policy_callback will be called every time a break point instruction needs to
5584  * be inserted with the method argument being the method that calls Debugger.Break()
5585  * or has the IL break instruction. The callback should return #MONO_BREAK_POLICY_NEVER
5586  * if it wants the breakpoint to not be effective in the given method.
5587  * #MONO_BREAK_POLICY_ALWAYS is the default.
5588  */
5589 void
5590 mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
5591 {
5592         if (policy_callback)
5593                 break_policy_func = policy_callback;
5594         else
5595                 break_policy_func = always_insert_breakpoint;
5596 }
5597
5598 static gboolean
5599 should_insert_brekpoint (MonoMethod *method) {
5600         switch (break_policy_func (method)) {
5601         case MONO_BREAK_POLICY_ALWAYS:
5602                 return TRUE;
5603         case MONO_BREAK_POLICY_NEVER:
5604                 return FALSE;
5605         case MONO_BREAK_POLICY_ON_DBG:
5606                 g_warning ("mdb no longer supported");
5607                 return FALSE;
5608         default:
5609                 g_warning ("Incorrect value returned from break policy callback");
5610                 return FALSE;
5611         }
5612 }
5613
5614 /* optimize the simple GetGenericValueImpl/SetGenericValueImpl generic icalls */
5615 static MonoInst*
5616 emit_array_generic_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
5617 {
5618         MonoInst *addr, *store, *load;
5619         MonoClass *eklass = mono_class_from_mono_type (fsig->params [2]);
5620
5621         /* the bounds check is already done by the callers */
5622         addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
5623         if (is_set) {
5624                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, args [2]->dreg, 0);
5625                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, addr->dreg, 0, load->dreg);
5626                 if (mini_type_is_reference (fsig->params [2]))
5627                         emit_write_barrier (cfg, addr, load);
5628         } else {
5629                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, addr->dreg, 0);
5630                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, args [2]->dreg, 0, load->dreg);
5631         }
5632         return store;
5633 }
5634
5635
5636 static gboolean
5637 generic_class_is_reference_type (MonoCompile *cfg, MonoClass *klass)
5638 {
5639         return mini_type_is_reference (&klass->byval_arg);
5640 }
5641
5642 static MonoInst*
5643 emit_array_store (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, gboolean safety_checks)
5644 {
5645         if (safety_checks && generic_class_is_reference_type (cfg, klass) &&
5646                 !(sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL)) {
5647                 MonoClass *obj_array = mono_array_class_get_cached (mono_defaults.object_class, 1);
5648                 MonoMethod *helper = mono_marshal_get_virtual_stelemref (obj_array);
5649                 MonoInst *iargs [3];
5650
5651                 if (!helper->slot)
5652                         mono_class_setup_vtable (obj_array);
5653                 g_assert (helper->slot);
5654
5655                 if (sp [0]->type != STACK_OBJ)
5656                         return NULL;
5657                 if (sp [2]->type != STACK_OBJ)
5658                         return NULL;
5659
5660                 iargs [2] = sp [2];
5661                 iargs [1] = sp [1];
5662                 iargs [0] = sp [0];
5663
5664                 return mono_emit_method_call (cfg, helper, iargs, sp [0]);
5665         } else {
5666                 MonoInst *ins;
5667
5668                 if (mini_is_gsharedvt_variable_klass (klass)) {
5669                         MonoInst *addr;
5670
5671                         // FIXME-VT: OP_ICONST optimization
5672                         addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
5673                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5674                         ins->opcode = OP_STOREV_MEMBASE;
5675                 } else if (sp [1]->opcode == OP_ICONST) {
5676                         int array_reg = sp [0]->dreg;
5677                         int index_reg = sp [1]->dreg;
5678                         int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
5679
5680                         if (safety_checks)
5681                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
5682                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset, sp [2]->dreg);
5683                 } else {
5684                         MonoInst *addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], safety_checks);
5685                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5686                         if (generic_class_is_reference_type (cfg, klass))
5687                                 emit_write_barrier (cfg, addr, sp [2]);
5688                 }
5689                 return ins;
5690         }
5691 }
5692
5693 static MonoInst*
5694 emit_array_unsafe_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
5695 {
5696         MonoClass *eklass;
5697         
5698         if (is_set)
5699                 eklass = mono_class_from_mono_type (fsig->params [2]);
5700         else
5701                 eklass = mono_class_from_mono_type (fsig->ret);
5702
5703         if (is_set) {
5704                 return emit_array_store (cfg, eklass, args, FALSE);
5705         } else {
5706                 MonoInst *ins, *addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
5707                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &eklass->byval_arg, addr->dreg, 0);
5708                 return ins;
5709         }
5710 }
5711
5712 static gboolean
5713 is_unsafe_mov_compatible (MonoCompile *cfg, MonoClass *param_klass, MonoClass *return_klass)
5714 {
5715         uint32_t align;
5716
5717         param_klass = mono_class_from_mono_type (mini_get_underlying_type (&param_klass->byval_arg));
5718
5719         //Only allow for valuetypes
5720         if (!param_klass->valuetype || !return_klass->valuetype)
5721                 return FALSE;
5722
5723         //That are blitable
5724         if (param_klass->has_references || return_klass->has_references)
5725                 return FALSE;
5726
5727         /* Avoid mixing structs and primitive types/enums, they need to be handled differently in the JIT */
5728         if ((MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && !MONO_TYPE_ISSTRUCT (&return_klass->byval_arg)) ||
5729                 (!MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && MONO_TYPE_ISSTRUCT (&return_klass->byval_arg)))
5730                 return FALSE;
5731
5732         if (param_klass->byval_arg.type == MONO_TYPE_R4 || param_klass->byval_arg.type == MONO_TYPE_R8 ||
5733                 return_klass->byval_arg.type == MONO_TYPE_R4 || return_klass->byval_arg.type == MONO_TYPE_R8)
5734                 return FALSE;
5735
5736         //And have the same size
5737         if (mono_class_value_size (param_klass, &align) != mono_class_value_size (return_klass, &align))
5738                 return FALSE;
5739         return TRUE;
5740 }
5741
5742 static MonoInst*
5743 emit_array_unsafe_mov (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args)
5744 {
5745         MonoClass *param_klass = mono_class_from_mono_type (fsig->params [0]);
5746         MonoClass *return_klass = mono_class_from_mono_type (fsig->ret);
5747
5748         //Valuetypes that are semantically equivalent
5749         if (is_unsafe_mov_compatible (cfg, param_klass, return_klass))
5750                 return args [0];
5751
5752         //Arrays of valuetypes that are semantically equivalent
5753         if (param_klass->rank == 1 && return_klass->rank == 1 && is_unsafe_mov_compatible (cfg, param_klass->element_class, return_klass->element_class))
5754                 return args [0];
5755
5756         return NULL;
5757 }
5758
5759 static MonoInst*
5760 mini_emit_inst_for_ctor (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5761 {
5762 #ifdef MONO_ARCH_SIMD_INTRINSICS
5763         MonoInst *ins = NULL;
5764
5765         if (cfg->opt & MONO_OPT_SIMD) {
5766                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
5767                 if (ins)
5768                         return ins;
5769         }
5770 #endif
5771
5772         return mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
5773 }
5774
5775 static MonoInst*
5776 emit_memory_barrier (MonoCompile *cfg, int kind)
5777 {
5778         MonoInst *ins = NULL;
5779         MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
5780         MONO_ADD_INS (cfg->cbb, ins);
5781         ins->backend.memory_barrier_kind = kind;
5782
5783         return ins;
5784 }
5785
5786 static MonoInst*
5787 llvm_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5788 {
5789         MonoInst *ins = NULL;
5790         int opcode = 0;
5791
5792         /* The LLVM backend supports these intrinsics */
5793         if (cmethod->klass == mono_defaults.math_class) {
5794                 if (strcmp (cmethod->name, "Sin") == 0) {
5795                         opcode = OP_SIN;
5796                 } else if (strcmp (cmethod->name, "Cos") == 0) {
5797                         opcode = OP_COS;
5798                 } else if (strcmp (cmethod->name, "Sqrt") == 0) {
5799                         opcode = OP_SQRT;
5800                 } else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8) {
5801                         opcode = OP_ABS;
5802                 }
5803
5804                 if (opcode && fsig->param_count == 1) {
5805                         MONO_INST_NEW (cfg, ins, opcode);
5806                         ins->type = STACK_R8;
5807                         ins->dreg = mono_alloc_freg (cfg);
5808                         ins->sreg1 = args [0]->dreg;
5809                         MONO_ADD_INS (cfg->cbb, ins);
5810                 }
5811
5812                 opcode = 0;
5813                 if (cfg->opt & MONO_OPT_CMOV) {
5814                         if (strcmp (cmethod->name, "Min") == 0) {
5815                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5816                                         opcode = OP_IMIN;
5817                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5818                                         opcode = OP_IMIN_UN;
5819                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5820                                         opcode = OP_LMIN;
5821                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5822                                         opcode = OP_LMIN_UN;
5823                         } else if (strcmp (cmethod->name, "Max") == 0) {
5824                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5825                                         opcode = OP_IMAX;
5826                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5827                                         opcode = OP_IMAX_UN;
5828                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5829                                         opcode = OP_LMAX;
5830                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5831                                         opcode = OP_LMAX_UN;
5832                         }
5833                 }
5834
5835                 if (opcode && fsig->param_count == 2) {
5836                         MONO_INST_NEW (cfg, ins, opcode);
5837                         ins->type = fsig->params [0]->type == MONO_TYPE_I4 ? STACK_I4 : STACK_I8;
5838                         ins->dreg = mono_alloc_ireg (cfg);
5839                         ins->sreg1 = args [0]->dreg;
5840                         ins->sreg2 = args [1]->dreg;
5841                         MONO_ADD_INS (cfg->cbb, ins);
5842                 }
5843         }
5844
5845         return ins;
5846 }
5847
5848 static MonoInst*
5849 mini_emit_inst_for_sharable_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5850 {
5851         if (cmethod->klass == mono_defaults.array_class) {
5852                 if (strcmp (cmethod->name, "UnsafeStore") == 0)
5853                         return emit_array_unsafe_access (cfg, fsig, args, TRUE);
5854                 else if (strcmp (cmethod->name, "UnsafeLoad") == 0)
5855                         return emit_array_unsafe_access (cfg, fsig, args, FALSE);
5856                 else if (strcmp (cmethod->name, "UnsafeMov") == 0)
5857                         return emit_array_unsafe_mov (cfg, fsig, args);
5858         }
5859
5860         return NULL;
5861 }
5862
5863 static MonoInst*
5864 mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5865 {
5866         MonoInst *ins = NULL;
5867
5868         static MonoClass *runtime_helpers_class = NULL;
5869         if (! runtime_helpers_class)
5870                 runtime_helpers_class = mono_class_from_name (mono_defaults.corlib,
5871                         "System.Runtime.CompilerServices", "RuntimeHelpers");
5872
5873         if (cmethod->klass == mono_defaults.string_class) {
5874                 if (strcmp (cmethod->name, "get_Chars") == 0 && fsig->param_count + fsig->hasthis == 2) {
5875                         int dreg = alloc_ireg (cfg);
5876                         int index_reg = alloc_preg (cfg);
5877                         int add_reg = alloc_preg (cfg);
5878
5879 #if SIZEOF_REGISTER == 8
5880                         /* The array reg is 64 bits but the index reg is only 32 */
5881                         MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index_reg, args [1]->dreg);
5882 #else
5883                         index_reg = args [1]->dreg;
5884 #endif  
5885                         MONO_EMIT_BOUNDS_CHECK (cfg, args [0]->dreg, MonoString, length, index_reg);
5886
5887 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5888                         EMIT_NEW_X86_LEA (cfg, ins, args [0]->dreg, index_reg, 1, MONO_STRUCT_OFFSET (MonoString, chars));
5889                         add_reg = ins->dreg;
5890                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5891                                                                    add_reg, 0);
5892 #else
5893                         int mult_reg = alloc_preg (cfg);
5894                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, index_reg, 1);
5895                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
5896                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5897                                                                    add_reg, MONO_STRUCT_OFFSET (MonoString, chars));
5898 #endif
5899                         type_from_op (cfg, ins, NULL, NULL);
5900                         return ins;
5901                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count + fsig->hasthis == 1) {
5902                         int dreg = alloc_ireg (cfg);
5903                         /* Decompose later to allow more optimizations */
5904                         EMIT_NEW_UNALU (cfg, ins, OP_STRLEN, dreg, args [0]->dreg);
5905                         ins->type = STACK_I4;
5906                         ins->flags |= MONO_INST_FAULT;
5907                         cfg->cbb->has_array_access = TRUE;
5908                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
5909
5910                         return ins;
5911                 } else 
5912                         return NULL;
5913         } else if (cmethod->klass == mono_defaults.object_class) {
5914
5915                 if (strcmp (cmethod->name, "GetType") == 0 && fsig->param_count + fsig->hasthis == 1) {
5916                         int dreg = alloc_ireg_ref (cfg);
5917                         int vt_reg = alloc_preg (cfg);
5918                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vt_reg, args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
5919                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, vt_reg, MONO_STRUCT_OFFSET (MonoVTable, type));
5920                         type_from_op (cfg, ins, NULL, NULL);
5921
5922                         return ins;
5923 #if !defined(MONO_ARCH_EMULATE_MUL_DIV)
5924                 } else if (strcmp (cmethod->name, "InternalGetHashCode") == 0 && fsig->param_count == 1 && !mono_gc_is_moving ()) {
5925                         int dreg = alloc_ireg (cfg);
5926                         int t1 = alloc_ireg (cfg);
5927         
5928                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, t1, args [0]->dreg, 3);
5929                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_MUL_IMM, dreg, t1, 2654435761u);
5930                         ins->type = STACK_I4;
5931
5932                         return ins;
5933 #endif
5934                 } else if (strcmp (cmethod->name, ".ctor") == 0 && fsig->param_count == 0) {
5935                         MONO_INST_NEW (cfg, ins, OP_NOP);
5936                         MONO_ADD_INS (cfg->cbb, ins);
5937                         return ins;
5938                 } else
5939                         return NULL;
5940         } else if (cmethod->klass == mono_defaults.array_class) {
5941                 if (strcmp (cmethod->name, "GetGenericValueImpl") == 0 && fsig->param_count + fsig->hasthis == 3 && !cfg->gsharedvt)
5942                         return emit_array_generic_access (cfg, fsig, args, FALSE);
5943                 else if (strcmp (cmethod->name, "SetGenericValueImpl") == 0 && fsig->param_count + fsig->hasthis == 3 && !cfg->gsharedvt)
5944                         return emit_array_generic_access (cfg, fsig, args, TRUE);
5945
5946 #ifndef MONO_BIG_ARRAYS
5947                 /*
5948                  * This is an inline version of GetLength/GetLowerBound(0) used frequently in
5949                  * Array methods.
5950                  */
5951                 else if (((strcmp (cmethod->name, "GetLength") == 0 && fsig->param_count + fsig->hasthis == 2) ||
5952                          (strcmp (cmethod->name, "GetLowerBound") == 0 && fsig->param_count + fsig->hasthis == 2)) &&
5953                          args [1]->opcode == OP_ICONST && args [1]->inst_c0 == 0) {
5954                         int dreg = alloc_ireg (cfg);
5955                         int bounds_reg = alloc_ireg_mp (cfg);
5956                         MonoBasicBlock *end_bb, *szarray_bb;
5957                         gboolean get_length = strcmp (cmethod->name, "GetLength") == 0;
5958
5959                         NEW_BBLOCK (cfg, end_bb);
5960                         NEW_BBLOCK (cfg, szarray_bb);
5961
5962                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOAD_MEMBASE, bounds_reg,
5963                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
5964                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
5965                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, szarray_bb);
5966                         /* Non-szarray case */
5967                         if (get_length)
5968                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5969                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5970                         else
5971                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5972                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5973                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
5974                         MONO_START_BB (cfg, szarray_bb);
5975                         /* Szarray case */
5976                         if (get_length)
5977                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5978                                                                            args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
5979                         else
5980                                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
5981                         MONO_START_BB (cfg, end_bb);
5982
5983                         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, dreg, dreg);
5984                         ins->type = STACK_I4;
5985                         
5986                         return ins;
5987                 }
5988 #endif
5989
5990                 if (cmethod->name [0] != 'g')
5991                         return NULL;
5992
5993                 if (strcmp (cmethod->name, "get_Rank") == 0 && fsig->param_count + fsig->hasthis == 1) {
5994                         int dreg = alloc_ireg (cfg);
5995                         int vtable_reg = alloc_preg (cfg);
5996                         MONO_EMIT_NEW_LOAD_MEMBASE_OP_FAULT (cfg, OP_LOAD_MEMBASE, vtable_reg, 
5997                                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
5998                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU1_MEMBASE, dreg,
5999                                                                    vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
6000                         type_from_op (cfg, ins, NULL, NULL);
6001
6002                         return ins;
6003                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count + fsig->hasthis == 1) {
6004                         int dreg = alloc_ireg (cfg);
6005
6006                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOADI4_MEMBASE, dreg, 
6007                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
6008                         type_from_op (cfg, ins, NULL, NULL);
6009
6010                         return ins;
6011                 } else
6012                         return NULL;
6013         } else if (cmethod->klass == runtime_helpers_class) {
6014
6015                 if (strcmp (cmethod->name, "get_OffsetToStringData") == 0 && fsig->param_count == 0) {
6016                         EMIT_NEW_ICONST (cfg, ins, MONO_STRUCT_OFFSET (MonoString, chars));
6017                         return ins;
6018                 } else
6019                         return NULL;
6020         } else if (cmethod->klass == mono_defaults.thread_class) {
6021                 if (strcmp (cmethod->name, "SpinWait_nop") == 0 && fsig->param_count == 0) {
6022                         MONO_INST_NEW (cfg, ins, OP_RELAXED_NOP);
6023                         MONO_ADD_INS (cfg->cbb, ins);
6024                         return ins;
6025                 } else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0) {
6026                         return emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6027                 } else if (!strcmp (cmethod->name, "VolatileRead") && fsig->param_count == 1) {
6028                         guint32 opcode = 0;
6029                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6030
6031                         if (fsig->params [0]->type == MONO_TYPE_I1)
6032                                 opcode = OP_LOADI1_MEMBASE;
6033                         else if (fsig->params [0]->type == MONO_TYPE_U1)
6034                                 opcode = OP_LOADU1_MEMBASE;
6035                         else if (fsig->params [0]->type == MONO_TYPE_I2)
6036                                 opcode = OP_LOADI2_MEMBASE;
6037                         else if (fsig->params [0]->type == MONO_TYPE_U2)
6038                                 opcode = OP_LOADU2_MEMBASE;
6039                         else if (fsig->params [0]->type == MONO_TYPE_I4)
6040                                 opcode = OP_LOADI4_MEMBASE;
6041                         else if (fsig->params [0]->type == MONO_TYPE_U4)
6042                                 opcode = OP_LOADU4_MEMBASE;
6043                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
6044                                 opcode = OP_LOADI8_MEMBASE;
6045                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6046                                 opcode = OP_LOADR4_MEMBASE;
6047                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6048                                 opcode = OP_LOADR8_MEMBASE;
6049                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
6050                                 opcode = OP_LOAD_MEMBASE;
6051
6052                         if (opcode) {
6053                                 MONO_INST_NEW (cfg, ins, opcode);
6054                                 ins->inst_basereg = args [0]->dreg;
6055                                 ins->inst_offset = 0;
6056                                 MONO_ADD_INS (cfg->cbb, ins);
6057
6058                                 switch (fsig->params [0]->type) {
6059                                 case MONO_TYPE_I1:
6060                                 case MONO_TYPE_U1:
6061                                 case MONO_TYPE_I2:
6062                                 case MONO_TYPE_U2:
6063                                 case MONO_TYPE_I4:
6064                                 case MONO_TYPE_U4:
6065                                         ins->dreg = mono_alloc_ireg (cfg);
6066                                         ins->type = STACK_I4;
6067                                         break;
6068                                 case MONO_TYPE_I8:
6069                                 case MONO_TYPE_U8:
6070                                         ins->dreg = mono_alloc_lreg (cfg);
6071                                         ins->type = STACK_I8;
6072                                         break;
6073                                 case MONO_TYPE_I:
6074                                 case MONO_TYPE_U:
6075                                         ins->dreg = mono_alloc_ireg (cfg);
6076 #if SIZEOF_REGISTER == 8
6077                                         ins->type = STACK_I8;
6078 #else
6079                                         ins->type = STACK_I4;
6080 #endif
6081                                         break;
6082                                 case MONO_TYPE_R4:
6083                                 case MONO_TYPE_R8:
6084                                         ins->dreg = mono_alloc_freg (cfg);
6085                                         ins->type = STACK_R8;
6086                                         break;
6087                                 default:
6088                                         g_assert (mini_type_is_reference (fsig->params [0]));
6089                                         ins->dreg = mono_alloc_ireg_ref (cfg);
6090                                         ins->type = STACK_OBJ;
6091                                         break;
6092                                 }
6093
6094                                 if (opcode == OP_LOADI8_MEMBASE)
6095                                         ins = mono_decompose_opcode (cfg, ins);
6096
6097                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
6098
6099                                 return ins;
6100                         }
6101                 } else if (!strcmp (cmethod->name, "VolatileWrite") && fsig->param_count == 2) {
6102                         guint32 opcode = 0;
6103                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6104
6105                         if (fsig->params [0]->type == MONO_TYPE_I1 || fsig->params [0]->type == MONO_TYPE_U1)
6106                                 opcode = OP_STOREI1_MEMBASE_REG;
6107                         else if (fsig->params [0]->type == MONO_TYPE_I2 || fsig->params [0]->type == MONO_TYPE_U2)
6108                                 opcode = OP_STOREI2_MEMBASE_REG;
6109                         else if (fsig->params [0]->type == MONO_TYPE_I4 || fsig->params [0]->type == MONO_TYPE_U4)
6110                                 opcode = OP_STOREI4_MEMBASE_REG;
6111                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
6112                                 opcode = OP_STOREI8_MEMBASE_REG;
6113                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6114                                 opcode = OP_STORER4_MEMBASE_REG;
6115                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6116                                 opcode = OP_STORER8_MEMBASE_REG;
6117                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
6118                                 opcode = OP_STORE_MEMBASE_REG;
6119
6120                         if (opcode) {
6121                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
6122
6123                                 MONO_INST_NEW (cfg, ins, opcode);
6124                                 ins->sreg1 = args [1]->dreg;
6125                                 ins->inst_destbasereg = args [0]->dreg;
6126                                 ins->inst_offset = 0;
6127                                 MONO_ADD_INS (cfg->cbb, ins);
6128
6129                                 if (opcode == OP_STOREI8_MEMBASE_REG)
6130                                         ins = mono_decompose_opcode (cfg, ins);
6131
6132                                 return ins;
6133                         }
6134                 }
6135         } else if (cmethod->klass->image == mono_defaults.corlib &&
6136                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
6137                            (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
6138                 ins = NULL;
6139
6140 #if SIZEOF_REGISTER == 8
6141                 if (!cfg->llvm_only && strcmp (cmethod->name, "Read") == 0 && fsig->param_count == 1 && (fsig->params [0]->type == MONO_TYPE_I8)) {
6142                         if (!cfg->llvm_only && mono_arch_opcode_supported (OP_ATOMIC_LOAD_I8)) {
6143                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_LOAD_I8);
6144                                 ins->dreg = mono_alloc_preg (cfg);
6145                                 ins->sreg1 = args [0]->dreg;
6146                                 ins->type = STACK_I8;
6147                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_SEQ;
6148                                 MONO_ADD_INS (cfg->cbb, ins);
6149                         } else {
6150                                 MonoInst *load_ins;
6151
6152                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6153
6154                                 /* 64 bit reads are already atomic */
6155                                 MONO_INST_NEW (cfg, load_ins, OP_LOADI8_MEMBASE);
6156                                 load_ins->dreg = mono_alloc_preg (cfg);
6157                                 load_ins->inst_basereg = args [0]->dreg;
6158                                 load_ins->inst_offset = 0;
6159                                 load_ins->type = STACK_I8;
6160                                 MONO_ADD_INS (cfg->cbb, load_ins);
6161
6162                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6163
6164                                 ins = load_ins;
6165                         }
6166                 }
6167 #endif
6168
6169                 if (strcmp (cmethod->name, "Increment") == 0 && fsig->param_count == 1) {
6170                         MonoInst *ins_iconst;
6171                         guint32 opcode = 0;
6172
6173                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6174                                 opcode = OP_ATOMIC_ADD_I4;
6175                                 cfg->has_atomic_add_i4 = TRUE;
6176                         }
6177 #if SIZEOF_REGISTER == 8
6178                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6179                                 opcode = OP_ATOMIC_ADD_I8;
6180 #endif
6181                         if (opcode) {
6182                                 if (!mono_arch_opcode_supported (opcode))
6183                                         return NULL;
6184                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
6185                                 ins_iconst->inst_c0 = 1;
6186                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
6187                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
6188
6189                                 MONO_INST_NEW (cfg, ins, opcode);
6190                                 ins->dreg = mono_alloc_ireg (cfg);
6191                                 ins->inst_basereg = args [0]->dreg;
6192                                 ins->inst_offset = 0;
6193                                 ins->sreg2 = ins_iconst->dreg;
6194                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6195                                 MONO_ADD_INS (cfg->cbb, ins);
6196                         }
6197                 } else if (strcmp (cmethod->name, "Decrement") == 0 && fsig->param_count == 1) {
6198                         MonoInst *ins_iconst;
6199                         guint32 opcode = 0;
6200
6201                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6202                                 opcode = OP_ATOMIC_ADD_I4;
6203                                 cfg->has_atomic_add_i4 = TRUE;
6204                         }
6205 #if SIZEOF_REGISTER == 8
6206                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6207                                 opcode = OP_ATOMIC_ADD_I8;
6208 #endif
6209                         if (opcode) {
6210                                 if (!mono_arch_opcode_supported (opcode))
6211                                         return NULL;
6212                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
6213                                 ins_iconst->inst_c0 = -1;
6214                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
6215                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
6216
6217                                 MONO_INST_NEW (cfg, ins, opcode);
6218                                 ins->dreg = mono_alloc_ireg (cfg);
6219                                 ins->inst_basereg = args [0]->dreg;
6220                                 ins->inst_offset = 0;
6221                                 ins->sreg2 = ins_iconst->dreg;
6222                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6223                                 MONO_ADD_INS (cfg->cbb, ins);
6224                         }
6225                 } else if (strcmp (cmethod->name, "Add") == 0 && fsig->param_count == 2) {
6226                         guint32 opcode = 0;
6227
6228                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6229                                 opcode = OP_ATOMIC_ADD_I4;
6230                                 cfg->has_atomic_add_i4 = TRUE;
6231                         }
6232 #if SIZEOF_REGISTER == 8
6233                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6234                                 opcode = OP_ATOMIC_ADD_I8;
6235 #endif
6236                         if (opcode) {
6237                                 if (!mono_arch_opcode_supported (opcode))
6238                                         return NULL;
6239                                 MONO_INST_NEW (cfg, ins, opcode);
6240                                 ins->dreg = mono_alloc_ireg (cfg);
6241                                 ins->inst_basereg = args [0]->dreg;
6242                                 ins->inst_offset = 0;
6243                                 ins->sreg2 = args [1]->dreg;
6244                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6245                                 MONO_ADD_INS (cfg->cbb, ins);
6246                         }
6247                 }
6248                 else if (strcmp (cmethod->name, "Exchange") == 0 && fsig->param_count == 2) {
6249                         MonoInst *f2i = NULL, *i2f;
6250                         guint32 opcode, f2i_opcode, i2f_opcode;
6251                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6252                         gboolean is_float = fsig->params [0]->type == MONO_TYPE_R4 || fsig->params [0]->type == MONO_TYPE_R8;
6253
6254                         if (fsig->params [0]->type == MONO_TYPE_I4 ||
6255                             fsig->params [0]->type == MONO_TYPE_R4) {
6256                                 opcode = OP_ATOMIC_EXCHANGE_I4;
6257                                 f2i_opcode = OP_MOVE_F_TO_I4;
6258                                 i2f_opcode = OP_MOVE_I4_TO_F;
6259                                 cfg->has_atomic_exchange_i4 = TRUE;
6260                         }
6261 #if SIZEOF_REGISTER == 8
6262                         else if (is_ref ||
6263                                  fsig->params [0]->type == MONO_TYPE_I8 ||
6264                                  fsig->params [0]->type == MONO_TYPE_R8 ||
6265                                  fsig->params [0]->type == MONO_TYPE_I) {
6266                                 opcode = OP_ATOMIC_EXCHANGE_I8;
6267                                 f2i_opcode = OP_MOVE_F_TO_I8;
6268                                 i2f_opcode = OP_MOVE_I8_TO_F;
6269                         }
6270 #else
6271                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I) {
6272                                 opcode = OP_ATOMIC_EXCHANGE_I4;
6273                                 cfg->has_atomic_exchange_i4 = TRUE;
6274                         }
6275 #endif
6276                         else
6277                                 return NULL;
6278
6279                         if (!mono_arch_opcode_supported (opcode))
6280                                 return NULL;
6281
6282                         if (is_float) {
6283                                 /* TODO: Decompose these opcodes instead of bailing here. */
6284                                 if (COMPILE_SOFT_FLOAT (cfg))
6285                                         return NULL;
6286
6287                                 MONO_INST_NEW (cfg, f2i, f2i_opcode);
6288                                 f2i->dreg = mono_alloc_ireg (cfg);
6289                                 f2i->sreg1 = args [1]->dreg;
6290                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6291                                         f2i->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6292                                 MONO_ADD_INS (cfg->cbb, f2i);
6293                         }
6294
6295                         MONO_INST_NEW (cfg, ins, opcode);
6296                         ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : mono_alloc_ireg (cfg);
6297                         ins->inst_basereg = args [0]->dreg;
6298                         ins->inst_offset = 0;
6299                         ins->sreg2 = is_float ? f2i->dreg : args [1]->dreg;
6300                         MONO_ADD_INS (cfg->cbb, ins);
6301
6302                         switch (fsig->params [0]->type) {
6303                         case MONO_TYPE_I4:
6304                                 ins->type = STACK_I4;
6305                                 break;
6306                         case MONO_TYPE_I8:
6307                                 ins->type = STACK_I8;
6308                                 break;
6309                         case MONO_TYPE_I:
6310 #if SIZEOF_REGISTER == 8
6311                                 ins->type = STACK_I8;
6312 #else
6313                                 ins->type = STACK_I4;
6314 #endif
6315                                 break;
6316                         case MONO_TYPE_R4:
6317                         case MONO_TYPE_R8:
6318                                 ins->type = STACK_R8;
6319                                 break;
6320                         default:
6321                                 g_assert (mini_type_is_reference (fsig->params [0]));
6322                                 ins->type = STACK_OBJ;
6323                                 break;
6324                         }
6325
6326                         if (is_float) {
6327                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
6328                                 i2f->dreg = mono_alloc_freg (cfg);
6329                                 i2f->sreg1 = ins->dreg;
6330                                 i2f->type = STACK_R8;
6331                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
6332                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6333                                 MONO_ADD_INS (cfg->cbb, i2f);
6334
6335                                 ins = i2f;
6336                         }
6337
6338                         if (cfg->gen_write_barriers && is_ref)
6339                                 emit_write_barrier (cfg, args [0], args [1]);
6340                 }
6341                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 3) {
6342                         MonoInst *f2i_new = NULL, *f2i_cmp = NULL, *i2f;
6343                         guint32 opcode, f2i_opcode, i2f_opcode;
6344                         gboolean is_ref = mini_type_is_reference (fsig->params [1]);
6345                         gboolean is_float = fsig->params [1]->type == MONO_TYPE_R4 || fsig->params [1]->type == MONO_TYPE_R8;
6346
6347                         if (fsig->params [1]->type == MONO_TYPE_I4 ||
6348                             fsig->params [1]->type == MONO_TYPE_R4) {
6349                                 opcode = OP_ATOMIC_CAS_I4;
6350                                 f2i_opcode = OP_MOVE_F_TO_I4;
6351                                 i2f_opcode = OP_MOVE_I4_TO_F;
6352                                 cfg->has_atomic_cas_i4 = TRUE;
6353                         }
6354 #if SIZEOF_REGISTER == 8
6355                         else if (is_ref ||
6356                                  fsig->params [1]->type == MONO_TYPE_I8 ||
6357                                  fsig->params [1]->type == MONO_TYPE_R8 ||
6358                                  fsig->params [1]->type == MONO_TYPE_I) {
6359                                 opcode = OP_ATOMIC_CAS_I8;
6360                                 f2i_opcode = OP_MOVE_F_TO_I8;
6361                                 i2f_opcode = OP_MOVE_I8_TO_F;
6362                         }
6363 #else
6364                         else if (is_ref || fsig->params [1]->type == MONO_TYPE_I) {
6365                                 opcode = OP_ATOMIC_CAS_I4;
6366                                 cfg->has_atomic_cas_i4 = TRUE;
6367                         }
6368 #endif
6369                         else
6370                                 return NULL;
6371
6372                         if (!mono_arch_opcode_supported (opcode))
6373                                 return NULL;
6374
6375                         if (is_float) {
6376                                 /* TODO: Decompose these opcodes instead of bailing here. */
6377                                 if (COMPILE_SOFT_FLOAT (cfg))
6378                                         return NULL;
6379
6380                                 MONO_INST_NEW (cfg, f2i_new, f2i_opcode);
6381                                 f2i_new->dreg = mono_alloc_ireg (cfg);
6382                                 f2i_new->sreg1 = args [1]->dreg;
6383                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6384                                         f2i_new->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6385                                 MONO_ADD_INS (cfg->cbb, f2i_new);
6386
6387                                 MONO_INST_NEW (cfg, f2i_cmp, f2i_opcode);
6388                                 f2i_cmp->dreg = mono_alloc_ireg (cfg);
6389                                 f2i_cmp->sreg1 = args [2]->dreg;
6390                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6391                                         f2i_cmp->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6392                                 MONO_ADD_INS (cfg->cbb, f2i_cmp);
6393                         }
6394
6395                         MONO_INST_NEW (cfg, ins, opcode);
6396                         ins->dreg = is_ref ? alloc_ireg_ref (cfg) : alloc_ireg (cfg);
6397                         ins->sreg1 = args [0]->dreg;
6398                         ins->sreg2 = is_float ? f2i_new->dreg : args [1]->dreg;
6399                         ins->sreg3 = is_float ? f2i_cmp->dreg : args [2]->dreg;
6400                         MONO_ADD_INS (cfg->cbb, ins);
6401
6402                         switch (fsig->params [1]->type) {
6403                         case MONO_TYPE_I4:
6404                                 ins->type = STACK_I4;
6405                                 break;
6406                         case MONO_TYPE_I8:
6407                                 ins->type = STACK_I8;
6408                                 break;
6409                         case MONO_TYPE_I:
6410 #if SIZEOF_REGISTER == 8
6411                                 ins->type = STACK_I8;
6412 #else
6413                                 ins->type = STACK_I4;
6414 #endif
6415                                 break;
6416                         case MONO_TYPE_R4:
6417                                 ins->type = cfg->r4_stack_type;
6418                                 break;
6419                         case MONO_TYPE_R8:
6420                                 ins->type = STACK_R8;
6421                                 break;
6422                         default:
6423                                 g_assert (mini_type_is_reference (fsig->params [1]));
6424                                 ins->type = STACK_OBJ;
6425                                 break;
6426                         }
6427
6428                         if (is_float) {
6429                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
6430                                 i2f->dreg = mono_alloc_freg (cfg);
6431                                 i2f->sreg1 = ins->dreg;
6432                                 i2f->type = STACK_R8;
6433                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
6434                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6435                                 MONO_ADD_INS (cfg->cbb, i2f);
6436
6437                                 ins = i2f;
6438                         }
6439
6440                         if (cfg->gen_write_barriers && is_ref)
6441                                 emit_write_barrier (cfg, args [0], args [1]);
6442                 }
6443                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 4 &&
6444                          fsig->params [1]->type == MONO_TYPE_I4) {
6445                         MonoInst *cmp, *ceq;
6446
6447                         if (!mono_arch_opcode_supported (OP_ATOMIC_CAS_I4))
6448                                 return NULL;
6449
6450                         /* int32 r = CAS (location, value, comparand); */
6451                         MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I4);
6452                         ins->dreg = alloc_ireg (cfg);
6453                         ins->sreg1 = args [0]->dreg;
6454                         ins->sreg2 = args [1]->dreg;
6455                         ins->sreg3 = args [2]->dreg;
6456                         ins->type = STACK_I4;
6457                         MONO_ADD_INS (cfg->cbb, ins);
6458
6459                         /* bool result = r == comparand; */
6460                         MONO_INST_NEW (cfg, cmp, OP_ICOMPARE);
6461                         cmp->sreg1 = ins->dreg;
6462                         cmp->sreg2 = args [2]->dreg;
6463                         cmp->type = STACK_I4;
6464                         MONO_ADD_INS (cfg->cbb, cmp);
6465
6466                         MONO_INST_NEW (cfg, ceq, OP_ICEQ);
6467                         ceq->dreg = alloc_ireg (cfg);
6468                         ceq->type = STACK_I4;
6469                         MONO_ADD_INS (cfg->cbb, ceq);
6470
6471                         /* *success = result; */
6472                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, args [3]->dreg, 0, ceq->dreg);
6473
6474                         cfg->has_atomic_cas_i4 = TRUE;
6475                 }
6476                 else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0)
6477                         ins = emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6478
6479                 if (ins)
6480                         return ins;
6481         } else if (cmethod->klass->image == mono_defaults.corlib &&
6482                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
6483                            (strcmp (cmethod->klass->name, "Volatile") == 0)) {
6484                 ins = NULL;
6485
6486                 if (!cfg->llvm_only && !strcmp (cmethod->name, "Read") && fsig->param_count == 1) {
6487                         guint32 opcode = 0;
6488                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6489                         gboolean is_float = fsig->params [0]->type == MONO_TYPE_R4 || fsig->params [0]->type == MONO_TYPE_R8;
6490
6491                         if (fsig->params [0]->type == MONO_TYPE_I1)
6492                                 opcode = OP_ATOMIC_LOAD_I1;
6493                         else if (fsig->params [0]->type == MONO_TYPE_U1 || fsig->params [0]->type == MONO_TYPE_BOOLEAN)
6494                                 opcode = OP_ATOMIC_LOAD_U1;
6495                         else if (fsig->params [0]->type == MONO_TYPE_I2)
6496                                 opcode = OP_ATOMIC_LOAD_I2;
6497                         else if (fsig->params [0]->type == MONO_TYPE_U2)
6498                                 opcode = OP_ATOMIC_LOAD_U2;
6499                         else if (fsig->params [0]->type == MONO_TYPE_I4)
6500                                 opcode = OP_ATOMIC_LOAD_I4;
6501                         else if (fsig->params [0]->type == MONO_TYPE_U4)
6502                                 opcode = OP_ATOMIC_LOAD_U4;
6503                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6504                                 opcode = OP_ATOMIC_LOAD_R4;
6505                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6506                                 opcode = OP_ATOMIC_LOAD_R8;
6507 #if SIZEOF_REGISTER == 8
6508                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_I)
6509                                 opcode = OP_ATOMIC_LOAD_I8;
6510                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_U8 || fsig->params [0]->type == MONO_TYPE_U)
6511                                 opcode = OP_ATOMIC_LOAD_U8;
6512 #else
6513                         else if (fsig->params [0]->type == MONO_TYPE_I)
6514                                 opcode = OP_ATOMIC_LOAD_I4;
6515                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_U)
6516                                 opcode = OP_ATOMIC_LOAD_U4;
6517 #endif
6518
6519                         if (opcode) {
6520                                 if (!mono_arch_opcode_supported (opcode))
6521                                         return NULL;
6522
6523                                 MONO_INST_NEW (cfg, ins, opcode);
6524                                 ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : (is_float ? mono_alloc_freg (cfg) : mono_alloc_ireg (cfg));
6525                                 ins->sreg1 = args [0]->dreg;
6526                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_ACQ;
6527                                 MONO_ADD_INS (cfg->cbb, ins);
6528
6529                                 switch (fsig->params [0]->type) {
6530                                 case MONO_TYPE_BOOLEAN:
6531                                 case MONO_TYPE_I1:
6532                                 case MONO_TYPE_U1:
6533                                 case MONO_TYPE_I2:
6534                                 case MONO_TYPE_U2:
6535                                 case MONO_TYPE_I4:
6536                                 case MONO_TYPE_U4:
6537                                         ins->type = STACK_I4;
6538                                         break;
6539                                 case MONO_TYPE_I8:
6540                                 case MONO_TYPE_U8:
6541                                         ins->type = STACK_I8;
6542                                         break;
6543                                 case MONO_TYPE_I:
6544                                 case MONO_TYPE_U:
6545 #if SIZEOF_REGISTER == 8
6546                                         ins->type = STACK_I8;
6547 #else
6548                                         ins->type = STACK_I4;
6549 #endif
6550                                         break;
6551                                 case MONO_TYPE_R4:
6552                                         ins->type = cfg->r4_stack_type;
6553                                         break;
6554                                 case MONO_TYPE_R8:
6555                                         ins->type = STACK_R8;
6556                                         break;
6557                                 default:
6558                                         g_assert (mini_type_is_reference (fsig->params [0]));
6559                                         ins->type = STACK_OBJ;
6560                                         break;
6561                                 }
6562                         }
6563                 }
6564
6565                 if (!cfg->llvm_only && !strcmp (cmethod->name, "Write") && fsig->param_count == 2) {
6566                         guint32 opcode = 0;
6567                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6568
6569                         if (fsig->params [0]->type == MONO_TYPE_I1)
6570                                 opcode = OP_ATOMIC_STORE_I1;
6571                         else if (fsig->params [0]->type == MONO_TYPE_U1 || fsig->params [0]->type == MONO_TYPE_BOOLEAN)
6572                                 opcode = OP_ATOMIC_STORE_U1;
6573                         else if (fsig->params [0]->type == MONO_TYPE_I2)
6574                                 opcode = OP_ATOMIC_STORE_I2;
6575                         else if (fsig->params [0]->type == MONO_TYPE_U2)
6576                                 opcode = OP_ATOMIC_STORE_U2;
6577                         else if (fsig->params [0]->type == MONO_TYPE_I4)
6578                                 opcode = OP_ATOMIC_STORE_I4;
6579                         else if (fsig->params [0]->type == MONO_TYPE_U4)
6580                                 opcode = OP_ATOMIC_STORE_U4;
6581                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6582                                 opcode = OP_ATOMIC_STORE_R4;
6583                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6584                                 opcode = OP_ATOMIC_STORE_R8;
6585 #if SIZEOF_REGISTER == 8
6586                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_I)
6587                                 opcode = OP_ATOMIC_STORE_I8;
6588                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_U8 || fsig->params [0]->type == MONO_TYPE_U)
6589                                 opcode = OP_ATOMIC_STORE_U8;
6590 #else
6591                         else if (fsig->params [0]->type == MONO_TYPE_I)
6592                                 opcode = OP_ATOMIC_STORE_I4;
6593                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_U)
6594                                 opcode = OP_ATOMIC_STORE_U4;
6595 #endif
6596
6597                         if (opcode) {
6598                                 if (!mono_arch_opcode_supported (opcode))
6599                                         return NULL;
6600
6601                                 MONO_INST_NEW (cfg, ins, opcode);
6602                                 ins->dreg = args [0]->dreg;
6603                                 ins->sreg1 = args [1]->dreg;
6604                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_REL;
6605                                 MONO_ADD_INS (cfg->cbb, ins);
6606
6607                                 if (cfg->gen_write_barriers && is_ref)
6608                                         emit_write_barrier (cfg, args [0], args [1]);
6609                         }
6610                 }
6611
6612                 if (ins)
6613                         return ins;
6614         } else if (cmethod->klass->image == mono_defaults.corlib &&
6615                            (strcmp (cmethod->klass->name_space, "System.Diagnostics") == 0) &&
6616                            (strcmp (cmethod->klass->name, "Debugger") == 0)) {
6617                 if (!strcmp (cmethod->name, "Break") && fsig->param_count == 0) {
6618                         if (should_insert_brekpoint (cfg->method)) {
6619                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
6620                         } else {
6621                                 MONO_INST_NEW (cfg, ins, OP_NOP);
6622                                 MONO_ADD_INS (cfg->cbb, ins);
6623                         }
6624                         return ins;
6625                 }
6626         } else if (cmethod->klass->image == mono_defaults.corlib &&
6627                    (strcmp (cmethod->klass->name_space, "System") == 0) &&
6628                    (strcmp (cmethod->klass->name, "Environment") == 0)) {
6629                 if (!strcmp (cmethod->name, "get_IsRunningOnWindows") && fsig->param_count == 0) {
6630 #ifdef TARGET_WIN32
6631                         EMIT_NEW_ICONST (cfg, ins, 1);
6632 #else
6633                         EMIT_NEW_ICONST (cfg, ins, 0);
6634 #endif
6635                 }
6636         } else if (cmethod->klass->image == mono_defaults.corlib &&
6637                            (strcmp (cmethod->klass->name_space, "System.Reflection") == 0) &&
6638                            (strcmp (cmethod->klass->name, "Assembly") == 0)) {
6639                 if (cfg->llvm_only && !strcmp (cmethod->name, "GetExecutingAssembly")) {
6640                         /* No stack walks are current available, so implement this as an intrinsic */
6641                         MonoInst *assembly_ins;
6642
6643                         EMIT_NEW_AOTCONST (cfg, assembly_ins, MONO_PATCH_INFO_IMAGE, cfg->method->klass->image);
6644                         ins = mono_emit_jit_icall (cfg, mono_get_assembly_object, &assembly_ins);
6645                         return ins;
6646                 }
6647         } else if (cmethod->klass == mono_defaults.math_class) {
6648                 /* 
6649                  * There is general branchless code for Min/Max, but it does not work for 
6650                  * all inputs:
6651                  * http://everything2.com/?node_id=1051618
6652                  */
6653         } else if (((!strcmp (cmethod->klass->image->assembly->aname.name, "MonoMac") ||
6654                     !strcmp (cmethod->klass->image->assembly->aname.name, "monotouch")) &&
6655                                 !strcmp (cmethod->klass->name_space, "XamCore.ObjCRuntime") &&
6656                                 !strcmp (cmethod->klass->name, "Selector")) ||
6657                            (!strcmp (cmethod->klass->image->assembly->aname.name, "Xamarin.iOS") &&
6658                                 !strcmp (cmethod->klass->name_space, "ObjCRuntime") &&
6659                                 !strcmp (cmethod->klass->name, "Selector"))
6660                            ) {
6661 #ifdef MONO_ARCH_HAVE_OBJC_GET_SELECTOR
6662                 if (!strcmp (cmethod->name, "GetHandle") && fsig->param_count == 1 &&
6663                     (args [0]->opcode == OP_GOT_ENTRY || args [0]->opcode == OP_AOTCONST) &&
6664                     cfg->compile_aot) {
6665                         MonoInst *pi;
6666                         MonoJumpInfoToken *ji;
6667                         MonoString *s;
6668
6669                         cfg->disable_llvm = TRUE;
6670
6671                         if (args [0]->opcode == OP_GOT_ENTRY) {
6672                                 pi = args [0]->inst_p1;
6673                                 g_assert (pi->opcode == OP_PATCH_INFO);
6674                                 g_assert (GPOINTER_TO_INT (pi->inst_p1) == MONO_PATCH_INFO_LDSTR);
6675                                 ji = pi->inst_p0;
6676                         } else {
6677                                 g_assert (GPOINTER_TO_INT (args [0]->inst_p1) == MONO_PATCH_INFO_LDSTR);
6678                                 ji = args [0]->inst_p0;
6679                         }
6680
6681                         NULLIFY_INS (args [0]);
6682
6683                         // FIXME: Ugly
6684                         s = mono_ldstr (cfg->domain, ji->image, mono_metadata_token_index (ji->token));
6685                         MONO_INST_NEW (cfg, ins, OP_OBJC_GET_SELECTOR);
6686                         ins->dreg = mono_alloc_ireg (cfg);
6687                         // FIXME: Leaks
6688                         ins->inst_p0 = mono_string_to_utf8 (s);
6689                         MONO_ADD_INS (cfg->cbb, ins);
6690                         return ins;
6691                 }
6692 #endif
6693         }
6694
6695 #ifdef MONO_ARCH_SIMD_INTRINSICS
6696         if (cfg->opt & MONO_OPT_SIMD) {
6697                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
6698                 if (ins)
6699                         return ins;
6700         }
6701 #endif
6702
6703         ins = mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
6704         if (ins)
6705                 return ins;
6706
6707         if (COMPILE_LLVM (cfg)) {
6708                 ins = llvm_emit_inst_for_method (cfg, cmethod, fsig, args);
6709                 if (ins)
6710                         return ins;
6711         }
6712
6713         return mono_arch_emit_inst_for_method (cfg, cmethod, fsig, args);
6714 }
6715
6716 /*
6717  * This entry point could be used later for arbitrary method
6718  * redirection.
6719  */
6720 inline static MonoInst*
6721 mini_redirect_call (MonoCompile *cfg, MonoMethod *method,  
6722                                         MonoMethodSignature *signature, MonoInst **args, MonoInst *this_ins)
6723 {
6724         if (method->klass == mono_defaults.string_class) {
6725                 /* managed string allocation support */
6726                 if (strcmp (method->name, "InternalAllocateStr") == 0 && !(mono_profiler_events & MONO_PROFILE_ALLOCATIONS) && !(cfg->opt & MONO_OPT_SHARED)) {
6727                         MonoInst *iargs [2];
6728                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
6729                         MonoMethod *managed_alloc = NULL;
6730
6731                         g_assert (vtable); /*Should not fail since it System.String*/
6732 #ifndef MONO_CROSS_COMPILE
6733                         managed_alloc = mono_gc_get_managed_allocator (method->klass, FALSE, FALSE);
6734 #endif
6735                         if (!managed_alloc)
6736                                 return NULL;
6737                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
6738                         iargs [1] = args [0];
6739                         return mono_emit_method_call (cfg, managed_alloc, iargs, this_ins);
6740                 }
6741         }
6742         return NULL;
6743 }
6744
6745 static void
6746 mono_save_args (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **sp)
6747 {
6748         MonoInst *store, *temp;
6749         int i;
6750
6751         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
6752                 MonoType *argtype = (sig->hasthis && (i == 0)) ? type_from_stack_type (*sp) : sig->params [i - sig->hasthis];
6753
6754                 /*
6755                  * FIXME: We should use *args++ = sp [0], but that would mean the arg
6756                  * would be different than the MonoInst's used to represent arguments, and
6757                  * the ldelema implementation can't deal with that.
6758                  * Solution: When ldelema is used on an inline argument, create a var for 
6759                  * it, emit ldelema on that var, and emit the saving code below in
6760                  * inline_method () if needed.
6761                  */
6762                 temp = mono_compile_create_var (cfg, argtype, OP_LOCAL);
6763                 cfg->args [i] = temp;
6764                 /* This uses cfg->args [i] which is set by the preceeding line */
6765                 EMIT_NEW_ARGSTORE (cfg, store, i, *sp);
6766                 store->cil_code = sp [0]->cil_code;
6767                 sp++;
6768         }
6769 }
6770
6771 #define MONO_INLINE_CALLED_LIMITED_METHODS 1
6772 #define MONO_INLINE_CALLER_LIMITED_METHODS 1
6773
6774 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
6775 static gboolean
6776 check_inline_called_method_name_limit (MonoMethod *called_method)
6777 {
6778         int strncmp_result;
6779         static const char *limit = NULL;
6780         
6781         if (limit == NULL) {
6782                 const char *limit_string = g_getenv ("MONO_INLINE_CALLED_METHOD_NAME_LIMIT");
6783
6784                 if (limit_string != NULL)
6785                         limit = limit_string;
6786                 else
6787                         limit = "";
6788         }
6789
6790         if (limit [0] != '\0') {
6791                 char *called_method_name = mono_method_full_name (called_method, TRUE);
6792
6793                 strncmp_result = strncmp (called_method_name, limit, strlen (limit));
6794                 g_free (called_method_name);
6795         
6796                 //return (strncmp_result <= 0);
6797                 return (strncmp_result == 0);
6798         } else {
6799                 return TRUE;
6800         }
6801 }
6802 #endif
6803
6804 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
6805 static gboolean
6806 check_inline_caller_method_name_limit (MonoMethod *caller_method)
6807 {
6808         int strncmp_result;
6809         static const char *limit = NULL;
6810         
6811         if (limit == NULL) {
6812                 const char *limit_string = g_getenv ("MONO_INLINE_CALLER_METHOD_NAME_LIMIT");
6813                 if (limit_string != NULL) {
6814                         limit = limit_string;
6815                 } else {
6816                         limit = "";
6817                 }
6818         }
6819
6820         if (limit [0] != '\0') {
6821                 char *caller_method_name = mono_method_full_name (caller_method, TRUE);
6822
6823                 strncmp_result = strncmp (caller_method_name, limit, strlen (limit));
6824                 g_free (caller_method_name);
6825         
6826                 //return (strncmp_result <= 0);
6827                 return (strncmp_result == 0);
6828         } else {
6829                 return TRUE;
6830         }
6831 }
6832 #endif
6833
6834 static void
6835 emit_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
6836 {
6837         static double r8_0 = 0.0;
6838         static float r4_0 = 0.0;
6839         MonoInst *ins;
6840         int t;
6841
6842         rtype = mini_get_underlying_type (rtype);
6843         t = rtype->type;
6844
6845         if (rtype->byref) {
6846                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
6847         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
6848                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
6849         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
6850                 MONO_EMIT_NEW_I8CONST (cfg, dreg, 0);
6851         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
6852                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
6853                 ins->type = STACK_R4;
6854                 ins->inst_p0 = (void*)&r4_0;
6855                 ins->dreg = dreg;
6856                 MONO_ADD_INS (cfg->cbb, ins);
6857         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
6858                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
6859                 ins->type = STACK_R8;
6860                 ins->inst_p0 = (void*)&r8_0;
6861                 ins->dreg = dreg;
6862                 MONO_ADD_INS (cfg->cbb, ins);
6863         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
6864                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
6865                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
6866         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (rtype)) {
6867                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
6868         } else {
6869                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
6870         }
6871 }
6872
6873 static void
6874 emit_dummy_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
6875 {
6876         int t;
6877
6878         rtype = mini_get_underlying_type (rtype);
6879         t = rtype->type;
6880
6881         if (rtype->byref) {
6882                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_PCONST);
6883         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
6884                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_ICONST);
6885         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
6886                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_I8CONST);
6887         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
6888                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R4CONST);
6889         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
6890                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R8CONST);
6891         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
6892                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
6893                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
6894         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (rtype)) {
6895                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
6896         } else {
6897                 emit_init_rvar (cfg, dreg, rtype);
6898         }
6899 }
6900
6901 /* If INIT is FALSE, emit dummy initialization statements to keep the IR valid */
6902 static void
6903 emit_init_local (MonoCompile *cfg, int local, MonoType *type, gboolean init)
6904 {
6905         MonoInst *var = cfg->locals [local];
6906         if (COMPILE_SOFT_FLOAT (cfg)) {
6907                 MonoInst *store;
6908                 int reg = alloc_dreg (cfg, var->type);
6909                 emit_init_rvar (cfg, reg, type);
6910                 EMIT_NEW_LOCSTORE (cfg, store, local, cfg->cbb->last_ins);
6911         } else {
6912                 if (init)
6913                         emit_init_rvar (cfg, var->dreg, type);
6914                 else
6915                         emit_dummy_init_rvar (cfg, var->dreg, type);
6916         }
6917 }
6918
6919 /*
6920  * inline_method:
6921  *
6922  *   Return the cost of inlining CMETHOD.
6923  */
6924 static int
6925 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
6926                            guchar *ip, guint real_offset, gboolean inline_always)
6927 {
6928         MonoInst *ins, *rvar = NULL;
6929         MonoMethodHeader *cheader;
6930         MonoBasicBlock *ebblock, *sbblock;
6931         int i, costs;
6932         MonoMethod *prev_inlined_method;
6933         MonoInst **prev_locals, **prev_args;
6934         MonoType **prev_arg_types;
6935         guint prev_real_offset;
6936         GHashTable *prev_cbb_hash;
6937         MonoBasicBlock **prev_cil_offset_to_bb;
6938         MonoBasicBlock *prev_cbb;
6939         unsigned char* prev_cil_start;
6940         guint32 prev_cil_offset_to_bb_len;
6941         MonoMethod *prev_current_method;
6942         MonoGenericContext *prev_generic_context;
6943         gboolean ret_var_set, prev_ret_var_set, prev_disable_inline, virtual = FALSE;
6944
6945         g_assert (cfg->exception_type == MONO_EXCEPTION_NONE);
6946
6947 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
6948         if ((! inline_always) && ! check_inline_called_method_name_limit (cmethod))
6949                 return 0;
6950 #endif
6951 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
6952         if ((! inline_always) && ! check_inline_caller_method_name_limit (cfg->method))
6953                 return 0;
6954 #endif
6955
6956         if (!fsig)
6957                 fsig = mono_method_signature (cmethod);
6958
6959         if (cfg->verbose_level > 2)
6960                 printf ("INLINE START %p %s -> %s\n", cmethod,  mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
6961
6962         if (!cmethod->inline_info) {
6963                 cfg->stat_inlineable_methods++;
6964                 cmethod->inline_info = 1;
6965         }
6966
6967         /* allocate local variables */
6968         cheader = mono_method_get_header (cmethod);
6969
6970         if (cheader == NULL || mono_loader_get_last_error ()) {
6971                 MonoLoaderError *error = mono_loader_get_last_error ();
6972
6973                 if (cheader)
6974                         mono_metadata_free_mh (cheader);
6975                 if (inline_always && error)
6976                         mono_cfg_set_exception (cfg, error->exception_type);
6977
6978                 mono_loader_clear_error ();
6979                 return 0;
6980         }
6981
6982         /*Must verify before creating locals as it can cause the JIT to assert.*/
6983         if (mono_compile_is_broken (cfg, cmethod, FALSE)) {
6984                 mono_metadata_free_mh (cheader);
6985                 return 0;
6986         }
6987
6988         /* allocate space to store the return value */
6989         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
6990                 rvar = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
6991         }
6992
6993         prev_locals = cfg->locals;
6994         cfg->locals = mono_mempool_alloc0 (cfg->mempool, cheader->num_locals * sizeof (MonoInst*));     
6995         for (i = 0; i < cheader->num_locals; ++i)
6996                 cfg->locals [i] = mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
6997
6998         /* allocate start and end blocks */
6999         /* This is needed so if the inline is aborted, we can clean up */
7000         NEW_BBLOCK (cfg, sbblock);
7001         sbblock->real_offset = real_offset;
7002
7003         NEW_BBLOCK (cfg, ebblock);
7004         ebblock->block_num = cfg->num_bblocks++;
7005         ebblock->real_offset = real_offset;
7006
7007         prev_args = cfg->args;
7008         prev_arg_types = cfg->arg_types;
7009         prev_inlined_method = cfg->inlined_method;
7010         cfg->inlined_method = cmethod;
7011         cfg->ret_var_set = FALSE;
7012         cfg->inline_depth ++;
7013         prev_real_offset = cfg->real_offset;
7014         prev_cbb_hash = cfg->cbb_hash;
7015         prev_cil_offset_to_bb = cfg->cil_offset_to_bb;
7016         prev_cil_offset_to_bb_len = cfg->cil_offset_to_bb_len;
7017         prev_cil_start = cfg->cil_start;
7018         prev_cbb = cfg->cbb;
7019         prev_current_method = cfg->current_method;
7020         prev_generic_context = cfg->generic_context;
7021         prev_ret_var_set = cfg->ret_var_set;
7022         prev_disable_inline = cfg->disable_inline;
7023
7024         if (ip && *ip == CEE_CALLVIRT && !(cmethod->flags & METHOD_ATTRIBUTE_STATIC))
7025                 virtual = TRUE;
7026
7027         costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, rvar, sp, real_offset, virtual);
7028
7029         ret_var_set = cfg->ret_var_set;
7030
7031         cfg->inlined_method = prev_inlined_method;
7032         cfg->real_offset = prev_real_offset;
7033         cfg->cbb_hash = prev_cbb_hash;
7034         cfg->cil_offset_to_bb = prev_cil_offset_to_bb;
7035         cfg->cil_offset_to_bb_len = prev_cil_offset_to_bb_len;
7036         cfg->cil_start = prev_cil_start;
7037         cfg->locals = prev_locals;
7038         cfg->args = prev_args;
7039         cfg->arg_types = prev_arg_types;
7040         cfg->current_method = prev_current_method;
7041         cfg->generic_context = prev_generic_context;
7042         cfg->ret_var_set = prev_ret_var_set;
7043         cfg->disable_inline = prev_disable_inline;
7044         cfg->inline_depth --;
7045
7046         if ((costs >= 0 && costs < 60) || inline_always || (costs >= 0 && (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))) {
7047                 if (cfg->verbose_level > 2)
7048                         printf ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
7049                 
7050                 cfg->stat_inlined_methods++;
7051
7052                 /* always add some code to avoid block split failures */
7053                 MONO_INST_NEW (cfg, ins, OP_NOP);
7054                 MONO_ADD_INS (prev_cbb, ins);
7055
7056                 prev_cbb->next_bb = sbblock;
7057                 link_bblock (cfg, prev_cbb, sbblock);
7058
7059                 /* 
7060                  * Get rid of the begin and end bblocks if possible to aid local
7061                  * optimizations.
7062                  */
7063                 mono_merge_basic_blocks (cfg, prev_cbb, sbblock);
7064
7065                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] != ebblock))
7066                         mono_merge_basic_blocks (cfg, prev_cbb, prev_cbb->out_bb [0]);
7067
7068                 if ((ebblock->in_count == 1) && ebblock->in_bb [0]->out_count == 1) {
7069                         MonoBasicBlock *prev = ebblock->in_bb [0];
7070                         mono_merge_basic_blocks (cfg, prev, ebblock);
7071                         cfg->cbb = prev;
7072                         if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] == prev)) {
7073                                 mono_merge_basic_blocks (cfg, prev_cbb, prev);
7074                                 cfg->cbb = prev_cbb;
7075                         }
7076                 } else {
7077                         /* 
7078                          * Its possible that the rvar is set in some prev bblock, but not in others.
7079                          * (#1835).
7080                          */
7081                         if (rvar) {
7082                                 MonoBasicBlock *bb;
7083
7084                                 for (i = 0; i < ebblock->in_count; ++i) {
7085                                         bb = ebblock->in_bb [i];
7086
7087                                         if (bb->last_ins && bb->last_ins->opcode == OP_NOT_REACHED) {
7088                                                 cfg->cbb = bb;
7089
7090                                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
7091                                         }
7092                                 }
7093                         }
7094
7095                         cfg->cbb = ebblock;
7096                 }
7097
7098                 if (rvar) {
7099                         /*
7100                          * If the inlined method contains only a throw, then the ret var is not 
7101                          * set, so set it to a dummy value.
7102                          */
7103                         if (!ret_var_set)
7104                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
7105
7106                         EMIT_NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
7107                         *sp++ = ins;
7108                 }
7109                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
7110                 return costs + 1;
7111         } else {
7112                 if (cfg->verbose_level > 2)
7113                         printf ("INLINE ABORTED %s (cost %d)\n", mono_method_full_name (cmethod, TRUE), costs);
7114                 cfg->exception_type = MONO_EXCEPTION_NONE;
7115                 mono_loader_clear_error ();
7116
7117                 /* This gets rid of the newly added bblocks */
7118                 cfg->cbb = prev_cbb;
7119         }
7120         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
7121         return 0;
7122 }
7123
7124 /*
7125  * Some of these comments may well be out-of-date.
7126  * Design decisions: we do a single pass over the IL code (and we do bblock 
7127  * splitting/merging in the few cases when it's required: a back jump to an IL
7128  * address that was not already seen as bblock starting point).
7129  * Code is validated as we go (full verification is still better left to metadata/verify.c).
7130  * Complex operations are decomposed in simpler ones right away. We need to let the 
7131  * arch-specific code peek and poke inside this process somehow (except when the 
7132  * optimizations can take advantage of the full semantic info of coarse opcodes).
7133  * All the opcodes of the form opcode.s are 'normalized' to opcode.
7134  * MonoInst->opcode initially is the IL opcode or some simplification of that 
7135  * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific 
7136  * opcode with value bigger than OP_LAST.
7137  * At this point the IR can be handed over to an interpreter, a dumb code generator
7138  * or to the optimizing code generator that will translate it to SSA form.
7139  *
7140  * Profiling directed optimizations.
7141  * We may compile by default with few or no optimizations and instrument the code
7142  * or the user may indicate what methods to optimize the most either in a config file
7143  * or through repeated runs where the compiler applies offline the optimizations to 
7144  * each method and then decides if it was worth it.
7145  */
7146
7147 #define CHECK_TYPE(ins) if (!(ins)->type) UNVERIFIED
7148 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) UNVERIFIED
7149 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) UNVERIFIED
7150 #define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) UNVERIFIED
7151 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
7152 #define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
7153 #define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
7154 #define CHECK_TYPELOAD(klass) if (!(klass) || (klass)->exception_type) TYPE_LOAD_ERROR ((klass))
7155
7156 /* offset from br.s -> br like opcodes */
7157 #define BIG_BRANCH_OFFSET 13
7158
7159 static gboolean
7160 ip_in_bb (MonoCompile *cfg, MonoBasicBlock *bb, const guint8* ip)
7161 {
7162         MonoBasicBlock *b = cfg->cil_offset_to_bb [ip - cfg->cil_start];
7163
7164         return b == NULL || b == bb;
7165 }
7166
7167 static int
7168 get_basic_blocks (MonoCompile *cfg, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
7169 {
7170         unsigned char *ip = start;
7171         unsigned char *target;
7172         int i;
7173         guint cli_addr;
7174         MonoBasicBlock *bblock;
7175         const MonoOpcode *opcode;
7176
7177         while (ip < end) {
7178                 cli_addr = ip - start;
7179                 i = mono_opcode_value ((const guint8 **)&ip, end);
7180                 if (i < 0)
7181                         UNVERIFIED;
7182                 opcode = &mono_opcodes [i];
7183                 switch (opcode->argument) {
7184                 case MonoInlineNone:
7185                         ip++; 
7186                         break;
7187                 case MonoInlineString:
7188                 case MonoInlineType:
7189                 case MonoInlineField:
7190                 case MonoInlineMethod:
7191                 case MonoInlineTok:
7192                 case MonoInlineSig:
7193                 case MonoShortInlineR:
7194                 case MonoInlineI:
7195                         ip += 5;
7196                         break;
7197                 case MonoInlineVar:
7198                         ip += 3;
7199                         break;
7200                 case MonoShortInlineVar:
7201                 case MonoShortInlineI:
7202                         ip += 2;
7203                         break;
7204                 case MonoShortInlineBrTarget:
7205                         target = start + cli_addr + 2 + (signed char)ip [1];
7206                         GET_BBLOCK (cfg, bblock, target);
7207                         ip += 2;
7208                         if (ip < end)
7209                                 GET_BBLOCK (cfg, bblock, ip);
7210                         break;
7211                 case MonoInlineBrTarget:
7212                         target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
7213                         GET_BBLOCK (cfg, bblock, target);
7214                         ip += 5;
7215                         if (ip < end)
7216                                 GET_BBLOCK (cfg, bblock, ip);
7217                         break;
7218                 case MonoInlineSwitch: {
7219                         guint32 n = read32 (ip + 1);
7220                         guint32 j;
7221                         ip += 5;
7222                         cli_addr += 5 + 4 * n;
7223                         target = start + cli_addr;
7224                         GET_BBLOCK (cfg, bblock, target);
7225                         
7226                         for (j = 0; j < n; ++j) {
7227                                 target = start + cli_addr + (gint32)read32 (ip);
7228                                 GET_BBLOCK (cfg, bblock, target);
7229                                 ip += 4;
7230                         }
7231                         break;
7232                 }
7233                 case MonoInlineR:
7234                 case MonoInlineI8:
7235                         ip += 9;
7236                         break;
7237                 default:
7238                         g_assert_not_reached ();
7239                 }
7240
7241                 if (i == CEE_THROW) {
7242                         unsigned char *bb_start = ip - 1;
7243                         
7244                         /* Find the start of the bblock containing the throw */
7245                         bblock = NULL;
7246                         while ((bb_start >= start) && !bblock) {
7247                                 bblock = cfg->cil_offset_to_bb [(bb_start) - start];
7248                                 bb_start --;
7249                         }
7250                         if (bblock)
7251                                 bblock->out_of_line = 1;
7252                 }
7253         }
7254         return 0;
7255 unverified:
7256 exception_exit:
7257         *pos = ip;
7258         return 1;
7259 }
7260
7261 static inline MonoMethod *
7262 mini_get_method_allow_open (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
7263 {
7264         MonoMethod *method;
7265
7266         if (m->wrapper_type != MONO_WRAPPER_NONE) {
7267                 method = mono_method_get_wrapper_data (m, token);
7268                 if (context) {
7269                         MonoError error;
7270                         method = mono_class_inflate_generic_method_checked (method, context, &error);
7271                         g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
7272                 }
7273         } else {
7274                 method = mono_get_method_full (m->klass->image, token, klass, context);
7275         }
7276
7277         return method;
7278 }
7279
7280 static inline MonoMethod *
7281 mini_get_method (MonoCompile *cfg, MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
7282 {
7283         MonoMethod *method = mini_get_method_allow_open (m, token, klass, context);
7284
7285         if (method && cfg && !cfg->gshared && mono_class_is_open_constructed_type (&method->klass->byval_arg))
7286                 return NULL;
7287
7288         return method;
7289 }
7290
7291 static inline MonoClass*
7292 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
7293 {
7294         MonoError error;
7295         MonoClass *klass;
7296
7297         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7298                 klass = mono_method_get_wrapper_data (method, token);
7299                 if (context)
7300                         klass = mono_class_inflate_generic_class (klass, context);
7301         } else {
7302                 klass = mono_class_get_and_inflate_typespec_checked (method->klass->image, token, context, &error);
7303                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
7304         }
7305         if (klass)
7306                 mono_class_init (klass);
7307         return klass;
7308 }
7309
7310 static inline MonoMethodSignature*
7311 mini_get_signature (MonoMethod *method, guint32 token, MonoGenericContext *context)
7312 {
7313         MonoMethodSignature *fsig;
7314
7315         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7316                 fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
7317         } else {
7318                 fsig = mono_metadata_parse_signature (method->klass->image, token);
7319         }
7320         if (context) {
7321                 MonoError error;
7322                 fsig = mono_inflate_generic_signature(fsig, context, &error);
7323                 // FIXME:
7324                 g_assert(mono_error_ok(&error));
7325         }
7326         return fsig;
7327 }
7328
7329 static MonoMethod*
7330 throw_exception (void)
7331 {
7332         static MonoMethod *method = NULL;
7333
7334         if (!method) {
7335                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
7336                 method = mono_class_get_method_from_name (secman->securitymanager, "ThrowException", 1);
7337         }
7338         g_assert (method);
7339         return method;
7340 }
7341
7342 static void
7343 emit_throw_exception (MonoCompile *cfg, MonoException *ex)
7344 {
7345         MonoMethod *thrower = throw_exception ();
7346         MonoInst *args [1];
7347
7348         EMIT_NEW_PCONST (cfg, args [0], ex);
7349         mono_emit_method_call (cfg, thrower, args, NULL);
7350 }
7351
7352 /*
7353  * Return the original method is a wrapper is specified. We can only access 
7354  * the custom attributes from the original method.
7355  */
7356 static MonoMethod*
7357 get_original_method (MonoMethod *method)
7358 {
7359         if (method->wrapper_type == MONO_WRAPPER_NONE)
7360                 return method;
7361
7362         /* native code (which is like Critical) can call any managed method XXX FIXME XXX to validate all usages */
7363         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)
7364                 return NULL;
7365
7366         /* in other cases we need to find the original method */
7367         return mono_marshal_method_from_wrapper (method);
7368 }
7369
7370 static void
7371 ensure_method_is_allowed_to_access_field (MonoCompile *cfg, MonoMethod *caller, MonoClassField *field)
7372 {
7373         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
7374         MonoException *ex = mono_security_core_clr_is_field_access_allowed (get_original_method (caller), field);
7375         if (ex)
7376                 emit_throw_exception (cfg, ex);
7377 }
7378
7379 static void
7380 ensure_method_is_allowed_to_call_method (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee)
7381 {
7382         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
7383         MonoException *ex = mono_security_core_clr_is_call_allowed (get_original_method (caller), callee);
7384         if (ex)
7385                 emit_throw_exception (cfg, ex);
7386 }
7387
7388 /*
7389  * Check that the IL instructions at ip are the array initialization
7390  * sequence and return the pointer to the data and the size.
7391  */
7392 static const char*
7393 initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, MonoClass *klass, guint32 len, int *out_size, guint32 *out_field_token)
7394 {
7395         /*
7396          * newarr[System.Int32]
7397          * dup
7398          * ldtoken field valuetype ...
7399          * call void class [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle)
7400          */
7401         if (ip [0] == CEE_DUP && ip [1] == CEE_LDTOKEN && ip [5] == 0x4 && ip [6] == CEE_CALL) {
7402                 MonoError error;
7403                 guint32 token = read32 (ip + 7);
7404                 guint32 field_token = read32 (ip + 2);
7405                 guint32 field_index = field_token & 0xffffff;
7406                 guint32 rva;
7407                 const char *data_ptr;
7408                 int size = 0;
7409                 MonoMethod *cmethod;
7410                 MonoClass *dummy_class;
7411                 MonoClassField *field = mono_field_from_token_checked (method->klass->image, field_token, &dummy_class, NULL, &error);
7412                 int dummy_align;
7413
7414                 if (!field) {
7415                         mono_error_cleanup (&error); /* FIXME don't swallow the error */
7416                         return NULL;
7417                 }
7418
7419                 *out_field_token = field_token;
7420
7421                 cmethod = mini_get_method (NULL, method, token, NULL, NULL);
7422                 if (!cmethod)
7423                         return NULL;
7424                 if (strcmp (cmethod->name, "InitializeArray") || strcmp (cmethod->klass->name, "RuntimeHelpers") || cmethod->klass->image != mono_defaults.corlib)
7425                         return NULL;
7426                 switch (mono_type_get_underlying_type (&klass->byval_arg)->type) {
7427                 case MONO_TYPE_BOOLEAN:
7428                 case MONO_TYPE_I1:
7429                 case MONO_TYPE_U1:
7430                         size = 1; break;
7431                 /* we need to swap on big endian, so punt. Should we handle R4 and R8 as well? */
7432 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
7433                 case MONO_TYPE_CHAR:
7434                 case MONO_TYPE_I2:
7435                 case MONO_TYPE_U2:
7436                         size = 2; break;
7437                 case MONO_TYPE_I4:
7438                 case MONO_TYPE_U4:
7439                 case MONO_TYPE_R4:
7440                         size = 4; break;
7441                 case MONO_TYPE_R8:
7442                 case MONO_TYPE_I8:
7443                 case MONO_TYPE_U8:
7444                         size = 8; break;
7445 #endif
7446                 default:
7447                         return NULL;
7448                 }
7449                 size *= len;
7450                 if (size > mono_type_size (field->type, &dummy_align))
7451                     return NULL;
7452                 *out_size = size;
7453                 /*g_print ("optimized in %s: size: %d, numelems: %d\n", method->name, size, newarr->inst_newa_len->inst_c0);*/
7454                 if (!image_is_dynamic (method->klass->image)) {
7455                         field_index = read32 (ip + 2) & 0xffffff;
7456                         mono_metadata_field_info (method->klass->image, field_index - 1, NULL, &rva, NULL);
7457                         data_ptr = mono_image_rva_map (method->klass->image, rva);
7458                         /*g_print ("field: 0x%08x, rva: %d, rva_ptr: %p\n", read32 (ip + 2), rva, data_ptr);*/
7459                         /* for aot code we do the lookup on load */
7460                         if (aot && data_ptr)
7461                                 return GUINT_TO_POINTER (rva);
7462                 } else {
7463                         /*FIXME is it possible to AOT a SRE assembly not meant to be saved? */ 
7464                         g_assert (!aot);
7465                         data_ptr = mono_field_get_data (field);
7466                 }
7467                 return data_ptr;
7468         }
7469         return NULL;
7470 }
7471
7472 static void
7473 set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsigned char *ip)
7474 {
7475         char *method_fname = mono_method_full_name (method, TRUE);
7476         char *method_code;
7477         MonoMethodHeader *header = mono_method_get_header (method);
7478
7479         if (header->code_size == 0)
7480                 method_code = g_strdup ("method body is empty.");
7481         else
7482                 method_code = mono_disasm_code_one (NULL, method, ip, NULL);
7483         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
7484         cfg->exception_message = g_strdup_printf ("Invalid IL code in %s: %s\n", method_fname, method_code);
7485         g_free (method_fname);
7486         g_free (method_code);
7487         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
7488 }
7489
7490 static void
7491 set_exception_object (MonoCompile *cfg, MonoException *exception)
7492 {
7493         mono_cfg_set_exception (cfg, MONO_EXCEPTION_OBJECT_SUPPLIED);
7494         MONO_GC_REGISTER_ROOT_SINGLE (cfg->exception_ptr, MONO_ROOT_SOURCE_JIT, "jit exception");
7495         cfg->exception_ptr = exception;
7496 }
7497
7498 static void
7499 emit_stloc_ir (MonoCompile *cfg, MonoInst **sp, MonoMethodHeader *header, int n)
7500 {
7501         MonoInst *ins;
7502         guint32 opcode = mono_type_to_regmove (cfg, header->locals [n]);
7503         if ((opcode == OP_MOVE) && cfg->cbb->last_ins == sp [0]  &&
7504                         ((sp [0]->opcode == OP_ICONST) || (sp [0]->opcode == OP_I8CONST))) {
7505                 /* Optimize reg-reg moves away */
7506                 /* 
7507                  * Can't optimize other opcodes, since sp[0] might point to
7508                  * the last ins of a decomposed opcode.
7509                  */
7510                 sp [0]->dreg = (cfg)->locals [n]->dreg;
7511         } else {
7512                 EMIT_NEW_LOCSTORE (cfg, ins, n, *sp);
7513         }
7514 }
7515
7516 /*
7517  * ldloca inhibits many optimizations so try to get rid of it in common
7518  * cases.
7519  */
7520 static inline unsigned char *
7521 emit_optimized_ldloca_ir (MonoCompile *cfg, unsigned char *ip, unsigned char *end, int size)
7522 {
7523         int local, token;
7524         MonoClass *klass;
7525         MonoType *type;
7526
7527         if (size == 1) {
7528                 local = ip [1];
7529                 ip += 2;
7530         } else {
7531                 local = read16 (ip + 2);
7532                 ip += 4;
7533         }
7534         
7535         if (ip + 6 < end && (ip [0] == CEE_PREFIX1) && (ip [1] == CEE_INITOBJ) && ip_in_bb (cfg, cfg->cbb, ip + 1)) {
7536                 /* From the INITOBJ case */
7537                 token = read32 (ip + 2);
7538                 klass = mini_get_class (cfg->current_method, token, cfg->generic_context);
7539                 CHECK_TYPELOAD (klass);
7540                 type = mini_get_underlying_type (&klass->byval_arg);
7541                 emit_init_local (cfg, local, type, TRUE);
7542                 return ip + 6;
7543         }
7544  exception_exit:
7545         return NULL;
7546 }
7547
7548 static gboolean
7549 is_exception_class (MonoClass *klass)
7550 {
7551         while (klass) {
7552                 if (klass == mono_defaults.exception_class)
7553                         return TRUE;
7554                 klass = klass->parent;
7555         }
7556         return FALSE;
7557 }
7558
7559 /*
7560  * is_jit_optimizer_disabled:
7561  *
7562  *   Determine whenever M's assembly has a DebuggableAttribute with the
7563  * IsJITOptimizerDisabled flag set.
7564  */
7565 static gboolean
7566 is_jit_optimizer_disabled (MonoMethod *m)
7567 {
7568         MonoAssembly *ass = m->klass->image->assembly;
7569         MonoCustomAttrInfo* attrs;
7570         static MonoClass *klass;
7571         int i;
7572         gboolean val = FALSE;
7573
7574         g_assert (ass);
7575         if (ass->jit_optimizer_disabled_inited)
7576                 return ass->jit_optimizer_disabled;
7577
7578         if (!klass)
7579                 klass = mono_class_from_name (mono_defaults.corlib, "System.Diagnostics", "DebuggableAttribute");
7580         if (!klass) {
7581                 /* Linked away */
7582                 ass->jit_optimizer_disabled = FALSE;
7583                 mono_memory_barrier ();
7584                 ass->jit_optimizer_disabled_inited = TRUE;
7585                 return FALSE;
7586         }
7587
7588         attrs = mono_custom_attrs_from_assembly (ass);
7589         if (attrs) {
7590                 for (i = 0; i < attrs->num_attrs; ++i) {
7591                         MonoCustomAttrEntry *attr = &attrs->attrs [i];
7592                         const gchar *p;
7593                         MonoMethodSignature *sig;
7594
7595                         if (!attr->ctor || attr->ctor->klass != klass)
7596                                 continue;
7597                         /* Decode the attribute. See reflection.c */
7598                         p = (const char*)attr->data;
7599                         g_assert (read16 (p) == 0x0001);
7600                         p += 2;
7601
7602                         // FIXME: Support named parameters
7603                         sig = mono_method_signature (attr->ctor);
7604                         if (sig->param_count != 2 || sig->params [0]->type != MONO_TYPE_BOOLEAN || sig->params [1]->type != MONO_TYPE_BOOLEAN)
7605                                 continue;
7606                         /* Two boolean arguments */
7607                         p ++;
7608                         val = *p;
7609                 }
7610                 mono_custom_attrs_free (attrs);
7611         }
7612
7613         ass->jit_optimizer_disabled = val;
7614         mono_memory_barrier ();
7615         ass->jit_optimizer_disabled_inited = TRUE;
7616
7617         return val;
7618 }
7619
7620 static gboolean
7621 is_supported_tail_call (MonoCompile *cfg, MonoMethod *method, MonoMethod *cmethod, MonoMethodSignature *fsig, int call_opcode)
7622 {
7623         gboolean supported_tail_call;
7624         int i;
7625
7626 #ifdef MONO_ARCH_HAVE_OP_TAIL_CALL
7627         supported_tail_call = mono_arch_tail_call_supported (cfg, mono_method_signature (method), mono_method_signature (cmethod));
7628 #else
7629         supported_tail_call = mono_metadata_signature_equal (mono_method_signature (method), mono_method_signature (cmethod)) && !MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->ret);
7630 #endif
7631
7632         for (i = 0; i < fsig->param_count; ++i) {
7633                 if (fsig->params [i]->byref || fsig->params [i]->type == MONO_TYPE_PTR || fsig->params [i]->type == MONO_TYPE_FNPTR)
7634                         /* These can point to the current method's stack */
7635                         supported_tail_call = FALSE;
7636         }
7637         if (fsig->hasthis && cmethod->klass->valuetype)
7638                 /* this might point to the current method's stack */
7639                 supported_tail_call = FALSE;
7640         if (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
7641                 supported_tail_call = FALSE;
7642         if (cfg->method->save_lmf)
7643                 supported_tail_call = FALSE;
7644         if (cmethod->wrapper_type && cmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD)
7645                 supported_tail_call = FALSE;
7646         if (call_opcode != CEE_CALL)
7647                 supported_tail_call = FALSE;
7648
7649         /* Debugging support */
7650 #if 0
7651         if (supported_tail_call) {
7652                 if (!mono_debug_count ())
7653                         supported_tail_call = FALSE;
7654         }
7655 #endif
7656
7657         return supported_tail_call;
7658 }
7659
7660 /*
7661  * handle_ctor_call:
7662  *
7663  *   Handle calls made to ctors from NEWOBJ opcodes.
7664  */
7665 static void
7666 handle_ctor_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used,
7667                                   MonoInst **sp, guint8 *ip, int *inline_costs)
7668 {
7669         MonoInst *vtable_arg = NULL, *callvirt_this_arg = NULL, *ins;
7670
7671         if (cmethod->klass->valuetype && mono_class_generic_sharing_enabled (cmethod->klass) &&
7672                                         mono_method_is_generic_sharable (cmethod, TRUE)) {
7673                 if (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst) {
7674                         mono_class_vtable (cfg->domain, cmethod->klass);
7675                         CHECK_TYPELOAD (cmethod->klass);
7676
7677                         vtable_arg = emit_get_rgctx_method (cfg, context_used,
7678                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
7679                 } else {
7680                         if (context_used) {
7681                                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
7682                                                                                                    cmethod->klass, MONO_RGCTX_INFO_VTABLE);
7683                         } else {
7684                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
7685
7686                                 CHECK_TYPELOAD (cmethod->klass);
7687                                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
7688                         }
7689                 }
7690         }
7691
7692         /* Avoid virtual calls to ctors if possible */
7693         if (mono_class_is_marshalbyref (cmethod->klass))
7694                 callvirt_this_arg = sp [0];
7695
7696         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_ctor (cfg, cmethod, fsig, sp))) {
7697                 g_assert (MONO_TYPE_IS_VOID (fsig->ret));
7698                 CHECK_CFG_EXCEPTION;
7699         } else if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used && !vtable_arg &&
7700                            mono_method_check_inlining (cfg, cmethod) &&
7701                            !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE)) {
7702                 int costs;
7703
7704                 if ((costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, FALSE))) {
7705                         cfg->real_offset += 5;
7706
7707                         *inline_costs += costs - 5;
7708                 } else {
7709                         INLINE_FAILURE ("inline failure");
7710                         // FIXME-VT: Clean this up
7711                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))
7712                                 GSHAREDVT_FAILURE(*ip);
7713                         mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, callvirt_this_arg, NULL, NULL);
7714                 }
7715         } else if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
7716                 MonoInst *addr;
7717
7718                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE);
7719                 mono_emit_calli (cfg, fsig, sp, addr, NULL, vtable_arg);
7720         } else if (context_used &&
7721                            ((!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
7722                                  !mono_class_generic_sharing_enabled (cmethod->klass)) || cfg->gsharedvt)) {
7723                 MonoInst *cmethod_addr;
7724
7725                 /* Generic calls made out of gsharedvt methods cannot be patched, so use an indirect call */
7726
7727                 cmethod_addr = emit_get_rgctx_method (cfg, context_used,
7728                                                                                           cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
7729
7730                 mono_emit_calli (cfg, fsig, sp, cmethod_addr, NULL, vtable_arg);
7731         } else {
7732                 INLINE_FAILURE ("ctor call");
7733                 ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp,
7734                                                                                   callvirt_this_arg, NULL, vtable_arg);
7735         }
7736  exception_exit:
7737         return;
7738 }
7739
7740 static void
7741 emit_setret (MonoCompile *cfg, MonoInst *val)
7742 {
7743         MonoType *ret_type = mini_get_underlying_type (mono_method_signature (cfg->method)->ret);
7744         MonoInst *ins;
7745
7746         if (mini_type_to_stind (cfg, ret_type) == CEE_STOBJ) {
7747                 MonoInst *ret_addr;
7748
7749                 if (!cfg->vret_addr) {
7750                         EMIT_NEW_VARSTORE (cfg, ins, cfg->ret, ret_type, val);
7751                 } else {
7752                         EMIT_NEW_RETLOADA (cfg, ret_addr);
7753
7754                         EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STOREV_MEMBASE, ret_addr->dreg, 0, val->dreg);
7755                         ins->klass = mono_class_from_mono_type (ret_type);
7756                 }
7757         } else {
7758 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
7759                 if (COMPILE_SOFT_FLOAT (cfg) && !ret_type->byref && ret_type->type == MONO_TYPE_R4) {
7760                         MonoInst *iargs [1];
7761                         MonoInst *conv;
7762
7763                         iargs [0] = val;
7764                         conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
7765                         mono_arch_emit_setret (cfg, cfg->method, conv);
7766                 } else {
7767                         mono_arch_emit_setret (cfg, cfg->method, val);
7768                 }
7769 #else
7770                 mono_arch_emit_setret (cfg, cfg->method, val);
7771 #endif
7772         }
7773 }
7774
7775 static MonoMethodSignature*
7776 sig_to_rgctx_sig (MonoMethodSignature *sig)
7777 {
7778         // FIXME: memory allocation
7779         MonoMethodSignature *res;
7780         int i;
7781
7782         res = g_malloc (MONO_SIZEOF_METHOD_SIGNATURE + (sig->param_count + 1) * sizeof (MonoType*));
7783         memcpy (res, sig, MONO_SIZEOF_METHOD_SIGNATURE);
7784         res->param_count = sig->param_count + 1;
7785         for (i = 0; i < sig->param_count; ++i)
7786                 res->params [i] = sig->params [i];
7787         res->params [sig->param_count] = &mono_defaults.int_class->byval_arg;
7788         return res;
7789 }
7790
7791 /*
7792  * mono_method_to_ir:
7793  *
7794  *   Translate the .net IL into linear IR.
7795  */
7796 int
7797 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
7798                    MonoInst *return_var, MonoInst **inline_args, 
7799                    guint inline_offset, gboolean is_virtual_call)
7800 {
7801         MonoError error;
7802         MonoInst *ins, **sp, **stack_start;
7803         MonoBasicBlock *tblock = NULL, *init_localsbb = NULL;
7804         MonoSimpleBasicBlock *bb = NULL, *original_bb = NULL;
7805         MonoMethod *cmethod, *method_definition;
7806         MonoInst **arg_array;
7807         MonoMethodHeader *header;
7808         MonoImage *image;
7809         guint32 token, ins_flag;
7810         MonoClass *klass;
7811         MonoClass *constrained_class = NULL;
7812         unsigned char *ip, *end, *target, *err_pos;
7813         MonoMethodSignature *sig;
7814         MonoGenericContext *generic_context = NULL;
7815         MonoGenericContainer *generic_container = NULL;
7816         MonoType **param_types;
7817         int i, n, start_new_bblock, dreg;
7818         int num_calls = 0, inline_costs = 0;
7819         int breakpoint_id = 0;
7820         guint num_args;
7821         GSList *class_inits = NULL;
7822         gboolean dont_verify, dont_verify_stloc, readonly = FALSE;
7823         int context_used;
7824         gboolean init_locals, seq_points, skip_dead_blocks;
7825         gboolean sym_seq_points = FALSE;
7826         MonoDebugMethodInfo *minfo;
7827         MonoBitSet *seq_point_locs = NULL;
7828         MonoBitSet *seq_point_set_locs = NULL;
7829
7830         cfg->disable_inline = is_jit_optimizer_disabled (method);
7831
7832         /* serialization and xdomain stuff may need access to private fields and methods */
7833         dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
7834         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE;
7835         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH;
7836         dont_verify |= method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; /* bug #77896 */
7837         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP;
7838         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP_INVOKE;
7839
7840         /* still some type unsafety issues in marshal wrappers... (unknown is PtrToStructure) */
7841         dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE;
7842         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_UNKNOWN;
7843         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED;
7844         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_STELEMREF;
7845
7846         image = method->klass->image;
7847         header = mono_method_get_header (method);
7848         if (!header) {
7849                 MonoLoaderError *error;
7850
7851                 if ((error = mono_loader_get_last_error ())) {
7852                         mono_cfg_set_exception (cfg, error->exception_type);
7853                 } else {
7854                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
7855                         cfg->exception_message = g_strdup_printf ("Missing or incorrect header for method %s", cfg->method->name);
7856                 }
7857                 goto exception_exit;
7858         }
7859         generic_container = mono_method_get_generic_container (method);
7860         sig = mono_method_signature (method);
7861         num_args = sig->hasthis + sig->param_count;
7862         ip = (unsigned char*)header->code;
7863         cfg->cil_start = ip;
7864         end = ip + header->code_size;
7865         cfg->stat_cil_code_size += header->code_size;
7866
7867         seq_points = cfg->gen_seq_points && cfg->method == method;
7868
7869         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
7870                 /* We could hit a seq point before attaching to the JIT (#8338) */
7871                 seq_points = FALSE;
7872         }
7873
7874         if (cfg->gen_sdb_seq_points && cfg->method == method) {
7875                 minfo = mono_debug_lookup_method (method);
7876                 if (minfo) {
7877                         MonoSymSeqPoint *sps;
7878                         int i, n_il_offsets;
7879
7880                         mono_debug_get_seq_points (minfo, NULL, NULL, NULL, &sps, &n_il_offsets);
7881                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
7882                         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);
7883                         sym_seq_points = TRUE;
7884                         for (i = 0; i < n_il_offsets; ++i) {
7885                                 if (sps [i].il_offset < header->code_size)
7886                                         mono_bitset_set_fast (seq_point_locs, sps [i].il_offset);
7887                         }
7888                         g_free (sps);
7889                 } else if (!method->wrapper_type && !method->dynamic && mono_debug_image_has_debug_info (method->klass->image)) {
7890                         /* Methods without line number info like auto-generated property accessors */
7891                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
7892                         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);
7893                         sym_seq_points = TRUE;
7894                 }
7895         }
7896
7897         /* 
7898          * Methods without init_locals set could cause asserts in various passes
7899          * (#497220). To work around this, we emit dummy initialization opcodes
7900          * (OP_DUMMY_ICONST etc.) which generate no code. These are only supported
7901          * on some platforms.
7902          */
7903         if ((cfg->opt & MONO_OPT_UNSAFE) && ARCH_HAVE_DUMMY_INIT)
7904                 init_locals = header->init_locals;
7905         else
7906                 init_locals = TRUE;
7907
7908         method_definition = method;
7909         while (method_definition->is_inflated) {
7910                 MonoMethodInflated *imethod = (MonoMethodInflated *) method_definition;
7911                 method_definition = imethod->declaring;
7912         }
7913
7914         /* SkipVerification is not allowed if core-clr is enabled */
7915         if (!dont_verify && mini_assembly_can_skip_verification (cfg->domain, method)) {
7916                 dont_verify = TRUE;
7917                 dont_verify_stloc = TRUE;
7918         }
7919
7920         if (sig->is_inflated)
7921                 generic_context = mono_method_get_context (method);
7922         else if (generic_container)
7923                 generic_context = &generic_container->context;
7924         cfg->generic_context = generic_context;
7925
7926         if (!cfg->gshared)
7927                 g_assert (!sig->has_type_parameters);
7928
7929         if (sig->generic_param_count && method->wrapper_type == MONO_WRAPPER_NONE) {
7930                 g_assert (method->is_inflated);
7931                 g_assert (mono_method_get_context (method)->method_inst);
7932         }
7933         if (method->is_inflated && mono_method_get_context (method)->method_inst)
7934                 g_assert (sig->generic_param_count);
7935
7936         if (cfg->method == method) {
7937                 cfg->real_offset = 0;
7938         } else {
7939                 cfg->real_offset = inline_offset;
7940         }
7941
7942         cfg->cil_offset_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoBasicBlock*) * header->code_size);
7943         cfg->cil_offset_to_bb_len = header->code_size;
7944
7945         cfg->current_method = method;
7946
7947         if (cfg->verbose_level > 2)
7948                 printf ("method to IR %s\n", mono_method_full_name (method, TRUE));
7949
7950         param_types = mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * num_args);
7951         if (sig->hasthis)
7952                 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
7953         for (n = 0; n < sig->param_count; ++n)
7954                 param_types [n + sig->hasthis] = sig->params [n];
7955         cfg->arg_types = param_types;
7956
7957         cfg->dont_inline = g_list_prepend (cfg->dont_inline, method);
7958         if (cfg->method == method) {
7959
7960                 if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
7961                         cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
7962
7963                 /* ENTRY BLOCK */
7964                 NEW_BBLOCK (cfg, start_bblock);
7965                 cfg->bb_entry = start_bblock;
7966                 start_bblock->cil_code = NULL;
7967                 start_bblock->cil_length = 0;
7968
7969                 /* EXIT BLOCK */
7970                 NEW_BBLOCK (cfg, end_bblock);
7971                 cfg->bb_exit = end_bblock;
7972                 end_bblock->cil_code = NULL;
7973                 end_bblock->cil_length = 0;
7974                 end_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
7975                 g_assert (cfg->num_bblocks == 2);
7976
7977                 arg_array = cfg->args;
7978
7979                 if (header->num_clauses) {
7980                         cfg->spvars = g_hash_table_new (NULL, NULL);
7981                         cfg->exvars = g_hash_table_new (NULL, NULL);
7982                 }
7983                 /* handle exception clauses */
7984                 for (i = 0; i < header->num_clauses; ++i) {
7985                         MonoBasicBlock *try_bb;
7986                         MonoExceptionClause *clause = &header->clauses [i];
7987                         GET_BBLOCK (cfg, try_bb, ip + clause->try_offset);
7988
7989                         try_bb->real_offset = clause->try_offset;
7990                         try_bb->try_start = TRUE;
7991                         try_bb->region = ((i + 1) << 8) | clause->flags;
7992                         GET_BBLOCK (cfg, tblock, ip + clause->handler_offset);
7993                         tblock->real_offset = clause->handler_offset;
7994                         tblock->flags |= BB_EXCEPTION_HANDLER;
7995
7996                         /*
7997                          * Linking the try block with the EH block hinders inlining as we won't be able to 
7998                          * merge the bblocks from inlining and produce an artificial hole for no good reason.
7999                          */
8000                         if (COMPILE_LLVM (cfg))
8001                                 link_bblock (cfg, try_bb, tblock);
8002
8003                         if (*(ip + clause->handler_offset) == CEE_POP)
8004                                 tblock->flags |= BB_EXCEPTION_DEAD_OBJ;
8005
8006                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
8007                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER ||
8008                             clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
8009                                 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
8010                                 MONO_ADD_INS (tblock, ins);
8011
8012                                 if (seq_points && clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY && clause->flags != MONO_EXCEPTION_CLAUSE_FILTER) {
8013                                         /* finally clauses already have a seq point */
8014                                         /* seq points for filter clauses are emitted below */
8015                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
8016                                         MONO_ADD_INS (tblock, ins);
8017                                 }
8018
8019                                 /* todo: is a fault block unsafe to optimize? */
8020                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
8021                                         tblock->flags |= BB_EXCEPTION_UNSAFE;
8022                         }
8023
8024                         /*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);
8025                           while (p < end) {
8026                           printf ("%s", mono_disasm_code_one (NULL, method, p, &p));
8027                           }*/
8028                         /* catch and filter blocks get the exception object on the stack */
8029                         if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
8030                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
8031
8032                                 /* mostly like handle_stack_args (), but just sets the input args */
8033                                 /* printf ("handling clause at IL_%04x\n", clause->handler_offset); */
8034                                 tblock->in_scount = 1;
8035                                 tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
8036                                 tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
8037
8038                                 cfg->cbb = tblock;
8039
8040 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
8041                                 /* The EH code passes in the exception in a register to both JITted and LLVM compiled code */
8042                                 if (!cfg->compile_llvm) {
8043                                         MONO_INST_NEW (cfg, ins, OP_GET_EX_OBJ);
8044                                         ins->dreg = tblock->in_stack [0]->dreg;
8045                                         MONO_ADD_INS (tblock, ins);
8046                                 }
8047 #else
8048                                 MonoInst *dummy_use;
8049
8050                                 /* 
8051                                  * Add a dummy use for the exvar so its liveness info will be
8052                                  * correct.
8053                                  */
8054                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, tblock->in_stack [0]);
8055 #endif
8056
8057                                 if (seq_points && clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
8058                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
8059                                         MONO_ADD_INS (tblock, ins);
8060                                 }
8061                                 
8062                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
8063                                         GET_BBLOCK (cfg, tblock, ip + clause->data.filter_offset);
8064                                         tblock->flags |= BB_EXCEPTION_HANDLER;
8065                                         tblock->real_offset = clause->data.filter_offset;
8066                                         tblock->in_scount = 1;
8067                                         tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
8068                                         /* The filter block shares the exvar with the handler block */
8069                                         tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
8070                                         MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
8071                                         MONO_ADD_INS (tblock, ins);
8072                                 }
8073                         }
8074
8075                         if (clause->flags != MONO_EXCEPTION_CLAUSE_FILTER &&
8076                                         clause->data.catch_class &&
8077                                         cfg->gshared &&
8078                                         mono_class_check_context_used (clause->data.catch_class)) {
8079                                 /*
8080                                  * In shared generic code with catch
8081                                  * clauses containing type variables
8082                                  * the exception handling code has to
8083                                  * be able to get to the rgctx.
8084                                  * Therefore we have to make sure that
8085                                  * the vtable/mrgctx argument (for
8086                                  * static or generic methods) or the
8087                                  * "this" argument (for non-static
8088                                  * methods) are live.
8089                                  */
8090                                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
8091                                                 mini_method_get_context (method)->method_inst ||
8092                                                 method->klass->valuetype) {
8093                                         mono_get_vtable_var (cfg);
8094                                 } else {
8095                                         MonoInst *dummy_use;
8096
8097                                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, arg_array [0]);
8098                                 }
8099                         }
8100                 }
8101         } else {
8102                 arg_array = (MonoInst **) alloca (sizeof (MonoInst *) * num_args);
8103                 cfg->cbb = start_bblock;
8104                 cfg->args = arg_array;
8105                 mono_save_args (cfg, sig, inline_args);
8106         }
8107
8108         /* FIRST CODE BLOCK */
8109         NEW_BBLOCK (cfg, tblock);
8110         tblock->cil_code = ip;
8111         cfg->cbb = tblock;
8112         cfg->ip = ip;
8113
8114         ADD_BBLOCK (cfg, tblock);
8115
8116         if (cfg->method == method) {
8117                 breakpoint_id = mono_debugger_method_has_breakpoint (method);
8118                 if (breakpoint_id) {
8119                         MONO_INST_NEW (cfg, ins, OP_BREAK);
8120                         MONO_ADD_INS (cfg->cbb, ins);
8121                 }
8122         }
8123
8124         /* we use a separate basic block for the initialization code */
8125         NEW_BBLOCK (cfg, init_localsbb);
8126         cfg->bb_init = init_localsbb;
8127         init_localsbb->real_offset = cfg->real_offset;
8128         start_bblock->next_bb = init_localsbb;
8129         init_localsbb->next_bb = cfg->cbb;
8130         link_bblock (cfg, start_bblock, init_localsbb);
8131         link_bblock (cfg, init_localsbb, cfg->cbb);
8132                 
8133         cfg->cbb = init_localsbb;
8134
8135         if (cfg->gsharedvt && cfg->method == method) {
8136                 MonoGSharedVtMethodInfo *info;
8137                 MonoInst *var, *locals_var;
8138                 int dreg;
8139
8140                 info = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoGSharedVtMethodInfo));
8141                 info->method = cfg->method;
8142                 info->count_entries = 16;
8143                 info->entries = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
8144                 cfg->gsharedvt_info = info;
8145
8146                 var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8147                 /* prevent it from being register allocated */
8148                 //var->flags |= MONO_INST_VOLATILE;
8149                 cfg->gsharedvt_info_var = var;
8150
8151                 ins = emit_get_rgctx_gsharedvt_method (cfg, mini_method_check_context_used (cfg, method), method, info);
8152                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, var->dreg, ins->dreg);
8153
8154                 /* Allocate locals */
8155                 locals_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8156                 /* prevent it from being register allocated */
8157                 //locals_var->flags |= MONO_INST_VOLATILE;
8158                 cfg->gsharedvt_locals_var = locals_var;
8159
8160                 dreg = alloc_ireg (cfg);
8161                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, dreg, var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, locals_size));
8162
8163                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
8164                 ins->dreg = locals_var->dreg;
8165                 ins->sreg1 = dreg;
8166                 MONO_ADD_INS (cfg->cbb, ins);
8167                 cfg->gsharedvt_locals_var_ins = ins;
8168                 
8169                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
8170                 /*
8171                 if (init_locals)
8172                         ins->flags |= MONO_INST_INIT;
8173                 */
8174         }
8175
8176         if (mono_security_core_clr_enabled ()) {
8177                 /* check if this is native code, e.g. an icall or a p/invoke */
8178                 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
8179                         MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
8180                         if (wrapped) {
8181                                 gboolean pinvk = (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL);
8182                                 gboolean icall = (wrapped->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL);
8183
8184                                 /* if this ia a native call then it can only be JITted from platform code */
8185                                 if ((icall || pinvk) && method->klass && method->klass->image) {
8186                                         if (!mono_security_core_clr_is_platform_image (method->klass->image)) {
8187                                                 MonoException *ex = icall ? mono_get_exception_security () : 
8188                                                         mono_get_exception_method_access ();
8189                                                 emit_throw_exception (cfg, ex);
8190                                         }
8191                                 }
8192                         }
8193                 }
8194         }
8195
8196         CHECK_CFG_EXCEPTION;
8197
8198         if (header->code_size == 0)
8199                 UNVERIFIED;
8200
8201         if (get_basic_blocks (cfg, header, cfg->real_offset, ip, end, &err_pos)) {
8202                 ip = err_pos;
8203                 UNVERIFIED;
8204         }
8205
8206         if (cfg->method == method)
8207                 mono_debug_init_method (cfg, cfg->cbb, breakpoint_id);
8208
8209         for (n = 0; n < header->num_locals; ++n) {
8210                 if (header->locals [n]->type == MONO_TYPE_VOID && !header->locals [n]->byref)
8211                         UNVERIFIED;
8212         }
8213         class_inits = NULL;
8214
8215         /* We force the vtable variable here for all shared methods
8216            for the possibility that they might show up in a stack
8217            trace where their exact instantiation is needed. */
8218         if (cfg->gshared && method == cfg->method) {
8219                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
8220                                 mini_method_get_context (method)->method_inst ||
8221                                 method->klass->valuetype) {
8222                         mono_get_vtable_var (cfg);
8223                 } else {
8224                         /* FIXME: Is there a better way to do this?
8225                            We need the variable live for the duration
8226                            of the whole method. */
8227                         cfg->args [0]->flags |= MONO_INST_VOLATILE;
8228                 }
8229         }
8230
8231         /* add a check for this != NULL to inlined methods */
8232         if (is_virtual_call) {
8233                 MonoInst *arg_ins;
8234
8235                 NEW_ARGLOAD (cfg, arg_ins, 0);
8236                 MONO_ADD_INS (cfg->cbb, arg_ins);
8237                 MONO_EMIT_NEW_CHECK_THIS (cfg, arg_ins->dreg);
8238         }
8239
8240         skip_dead_blocks = !dont_verify;
8241         if (skip_dead_blocks) {
8242                 original_bb = bb = mono_basic_block_split (method, &cfg->error);
8243                 CHECK_CFG_ERROR;
8244                 g_assert (bb);
8245         }
8246
8247         /* we use a spare stack slot in SWITCH and NEWOBJ and others */
8248         stack_start = sp = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
8249
8250         ins_flag = 0;
8251         start_new_bblock = 0;
8252         while (ip < end) {
8253                 if (cfg->method == method)
8254                         cfg->real_offset = ip - header->code;
8255                 else
8256                         cfg->real_offset = inline_offset;
8257                 cfg->ip = ip;
8258
8259                 context_used = 0;
8260
8261                 if (start_new_bblock) {
8262                         cfg->cbb->cil_length = ip - cfg->cbb->cil_code;
8263                         if (start_new_bblock == 2) {
8264                                 g_assert (ip == tblock->cil_code);
8265                         } else {
8266                                 GET_BBLOCK (cfg, tblock, ip);
8267                         }
8268                         cfg->cbb->next_bb = tblock;
8269                         cfg->cbb = tblock;
8270                         start_new_bblock = 0;
8271                         for (i = 0; i < cfg->cbb->in_scount; ++i) {
8272                                 if (cfg->verbose_level > 3)
8273                                         printf ("loading %d from temp %d\n", i, (int)cfg->cbb->in_stack [i]->inst_c0);
8274                                 EMIT_NEW_TEMPLOAD (cfg, ins, cfg->cbb->in_stack [i]->inst_c0);
8275                                 *sp++ = ins;
8276                         }
8277                         if (class_inits)
8278                                 g_slist_free (class_inits);
8279                         class_inits = NULL;
8280                 } else {
8281                         if ((tblock = cfg->cil_offset_to_bb [ip - cfg->cil_start]) && (tblock != cfg->cbb)) {
8282                                 link_bblock (cfg, cfg->cbb, tblock);
8283                                 if (sp != stack_start) {
8284                                         handle_stack_args (cfg, stack_start, sp - stack_start);
8285                                         sp = stack_start;
8286                                         CHECK_UNVERIFIABLE (cfg);
8287                                 }
8288                                 cfg->cbb->next_bb = tblock;
8289                                 cfg->cbb = tblock;
8290                                 for (i = 0; i < cfg->cbb->in_scount; ++i) {
8291                                         if (cfg->verbose_level > 3)
8292                                                 printf ("loading %d from temp %d\n", i, (int)cfg->cbb->in_stack [i]->inst_c0);
8293                                         EMIT_NEW_TEMPLOAD (cfg, ins, cfg->cbb->in_stack [i]->inst_c0);
8294                                         *sp++ = ins;
8295                                 }
8296                                 g_slist_free (class_inits);
8297                                 class_inits = NULL;
8298                         }
8299                 }
8300
8301                 if (skip_dead_blocks) {
8302                         int ip_offset = ip - header->code;
8303
8304                         if (ip_offset == bb->end)
8305                                 bb = bb->next;
8306
8307                         if (bb->dead) {
8308                                 int op_size = mono_opcode_size (ip, end);
8309                                 g_assert (op_size > 0); /*The BB formation pass must catch all bad ops*/
8310
8311                                 if (cfg->verbose_level > 3) printf ("SKIPPING DEAD OP at %x\n", ip_offset);
8312
8313                                 if (ip_offset + op_size == bb->end) {
8314                                         MONO_INST_NEW (cfg, ins, OP_NOP);
8315                                         MONO_ADD_INS (cfg->cbb, ins);
8316                                         start_new_bblock = 1;
8317                                 }
8318
8319                                 ip += op_size;
8320                                 continue;
8321                         }
8322                 }
8323                 /*
8324                  * Sequence points are points where the debugger can place a breakpoint.
8325                  * Currently, we generate these automatically at points where the IL
8326                  * stack is empty.
8327                  */
8328                 if (seq_points && ((!sym_seq_points && (sp == stack_start)) || (sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code)))) {
8329                         /*
8330                          * Make methods interruptable at the beginning, and at the targets of
8331                          * backward branches.
8332                          * Also, do this at the start of every bblock in methods with clauses too,
8333                          * to be able to handle instructions with inprecise control flow like
8334                          * throw/endfinally.
8335                          * Backward branches are handled at the end of method-to-ir ().
8336                          */
8337                         gboolean intr_loc = ip == header->code || (!cfg->cbb->last_ins && cfg->header->num_clauses);
8338                         gboolean sym_seq_point = sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code);
8339
8340                         /* Avoid sequence points on empty IL like .volatile */
8341                         // FIXME: Enable this
8342                         //if (!(cfg->cbb->last_ins && cfg->cbb->last_ins->opcode == OP_SEQ_POINT)) {
8343                         NEW_SEQ_POINT (cfg, ins, ip - header->code, intr_loc);
8344                         if ((sp != stack_start) && !sym_seq_point)
8345                                 ins->flags |= MONO_INST_NONEMPTY_STACK;
8346                         MONO_ADD_INS (cfg->cbb, ins);
8347
8348                         if (sym_seq_points)
8349                                 mono_bitset_set_fast (seq_point_set_locs, ip - header->code);
8350                 }
8351
8352                 cfg->cbb->real_offset = cfg->real_offset;
8353
8354                 if ((cfg->method == method) && cfg->coverage_info) {
8355                         guint32 cil_offset = ip - header->code;
8356                         cfg->coverage_info->data [cil_offset].cil_code = ip;
8357
8358                         /* TODO: Use an increment here */
8359 #if defined(TARGET_X86)
8360                         MONO_INST_NEW (cfg, ins, OP_STORE_MEM_IMM);
8361                         ins->inst_p0 = &(cfg->coverage_info->data [cil_offset].count);
8362                         ins->inst_imm = 1;
8363                         MONO_ADD_INS (cfg->cbb, ins);
8364 #else
8365                         EMIT_NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
8366                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, ins->dreg, 0, 1);
8367 #endif
8368                 }
8369
8370                 if (cfg->verbose_level > 3)
8371                         printf ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
8372
8373                 switch (*ip) {
8374                 case CEE_NOP:
8375                         if (seq_points && !sym_seq_points && sp != stack_start) {
8376                                 /*
8377                                  * The C# compiler uses these nops to notify the JIT that it should
8378                                  * insert seq points.
8379                                  */
8380                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, FALSE);
8381                                 MONO_ADD_INS (cfg->cbb, ins);
8382                         }
8383                         if (cfg->keep_cil_nops)
8384                                 MONO_INST_NEW (cfg, ins, OP_HARD_NOP);
8385                         else
8386                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8387                         ip++;
8388                         MONO_ADD_INS (cfg->cbb, ins);
8389                         break;
8390                 case CEE_BREAK:
8391                         if (should_insert_brekpoint (cfg->method)) {
8392                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
8393                         } else {
8394                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8395                         }
8396                         ip++;
8397                         MONO_ADD_INS (cfg->cbb, ins);
8398                         break;
8399                 case CEE_LDARG_0:
8400                 case CEE_LDARG_1:
8401                 case CEE_LDARG_2:
8402                 case CEE_LDARG_3:
8403                         CHECK_STACK_OVF (1);
8404                         n = (*ip)-CEE_LDARG_0;
8405                         CHECK_ARG (n);
8406                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8407                         ip++;
8408                         *sp++ = ins;
8409                         break;
8410                 case CEE_LDLOC_0:
8411                 case CEE_LDLOC_1:
8412                 case CEE_LDLOC_2:
8413                 case CEE_LDLOC_3:
8414                         CHECK_STACK_OVF (1);
8415                         n = (*ip)-CEE_LDLOC_0;
8416                         CHECK_LOCAL (n);
8417                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8418                         ip++;
8419                         *sp++ = ins;
8420                         break;
8421                 case CEE_STLOC_0:
8422                 case CEE_STLOC_1:
8423                 case CEE_STLOC_2:
8424                 case CEE_STLOC_3: {
8425                         CHECK_STACK (1);
8426                         n = (*ip)-CEE_STLOC_0;
8427                         CHECK_LOCAL (n);
8428                         --sp;
8429                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
8430                                 UNVERIFIED;
8431                         emit_stloc_ir (cfg, sp, header, n);
8432                         ++ip;
8433                         inline_costs += 1;
8434                         break;
8435                         }
8436                 case CEE_LDARG_S:
8437                         CHECK_OPSIZE (2);
8438                         CHECK_STACK_OVF (1);
8439                         n = ip [1];
8440                         CHECK_ARG (n);
8441                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8442                         *sp++ = ins;
8443                         ip += 2;
8444                         break;
8445                 case CEE_LDARGA_S:
8446                         CHECK_OPSIZE (2);
8447                         CHECK_STACK_OVF (1);
8448                         n = ip [1];
8449                         CHECK_ARG (n);
8450                         NEW_ARGLOADA (cfg, ins, n);
8451                         MONO_ADD_INS (cfg->cbb, ins);
8452                         *sp++ = ins;
8453                         ip += 2;
8454                         break;
8455                 case CEE_STARG_S:
8456                         CHECK_OPSIZE (2);
8457                         CHECK_STACK (1);
8458                         --sp;
8459                         n = ip [1];
8460                         CHECK_ARG (n);
8461                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [ip [1]], *sp))
8462                                 UNVERIFIED;
8463                         EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
8464                         ip += 2;
8465                         break;
8466                 case CEE_LDLOC_S:
8467                         CHECK_OPSIZE (2);
8468                         CHECK_STACK_OVF (1);
8469                         n = ip [1];
8470                         CHECK_LOCAL (n);
8471                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8472                         *sp++ = ins;
8473                         ip += 2;
8474                         break;
8475                 case CEE_LDLOCA_S: {
8476                         unsigned char *tmp_ip;
8477                         CHECK_OPSIZE (2);
8478                         CHECK_STACK_OVF (1);
8479                         CHECK_LOCAL (ip [1]);
8480
8481                         if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 1))) {
8482                                 ip = tmp_ip;
8483                                 inline_costs += 1;
8484                                 break;
8485                         }
8486
8487                         EMIT_NEW_LOCLOADA (cfg, ins, ip [1]);
8488                         *sp++ = ins;
8489                         ip += 2;
8490                         break;
8491                 }
8492                 case CEE_STLOC_S:
8493                         CHECK_OPSIZE (2);
8494                         CHECK_STACK (1);
8495                         --sp;
8496                         CHECK_LOCAL (ip [1]);
8497                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [ip [1]], *sp))
8498                                 UNVERIFIED;
8499                         emit_stloc_ir (cfg, sp, header, ip [1]);
8500                         ip += 2;
8501                         inline_costs += 1;
8502                         break;
8503                 case CEE_LDNULL:
8504                         CHECK_STACK_OVF (1);
8505                         EMIT_NEW_PCONST (cfg, ins, NULL);
8506                         ins->type = STACK_OBJ;
8507                         ++ip;
8508                         *sp++ = ins;
8509                         break;
8510                 case CEE_LDC_I4_M1:
8511                         CHECK_STACK_OVF (1);
8512                         EMIT_NEW_ICONST (cfg, ins, -1);
8513                         ++ip;
8514                         *sp++ = ins;
8515                         break;
8516                 case CEE_LDC_I4_0:
8517                 case CEE_LDC_I4_1:
8518                 case CEE_LDC_I4_2:
8519                 case CEE_LDC_I4_3:
8520                 case CEE_LDC_I4_4:
8521                 case CEE_LDC_I4_5:
8522                 case CEE_LDC_I4_6:
8523                 case CEE_LDC_I4_7:
8524                 case CEE_LDC_I4_8:
8525                         CHECK_STACK_OVF (1);
8526                         EMIT_NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
8527                         ++ip;
8528                         *sp++ = ins;
8529                         break;
8530                 case CEE_LDC_I4_S:
8531                         CHECK_OPSIZE (2);
8532                         CHECK_STACK_OVF (1);
8533                         ++ip;
8534                         EMIT_NEW_ICONST (cfg, ins, *((signed char*)ip));
8535                         ++ip;
8536                         *sp++ = ins;
8537                         break;
8538                 case CEE_LDC_I4:
8539                         CHECK_OPSIZE (5);
8540                         CHECK_STACK_OVF (1);
8541                         EMIT_NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
8542                         ip += 5;
8543                         *sp++ = ins;
8544                         break;
8545                 case CEE_LDC_I8:
8546                         CHECK_OPSIZE (9);
8547                         CHECK_STACK_OVF (1);
8548                         MONO_INST_NEW (cfg, ins, OP_I8CONST);
8549                         ins->type = STACK_I8;
8550                         ins->dreg = alloc_dreg (cfg, STACK_I8);
8551                         ++ip;
8552                         ins->inst_l = (gint64)read64 (ip);
8553                         MONO_ADD_INS (cfg->cbb, ins);
8554                         ip += 8;
8555                         *sp++ = ins;
8556                         break;
8557                 case CEE_LDC_R4: {
8558                         float *f;
8559                         gboolean use_aotconst = FALSE;
8560
8561 #ifdef TARGET_POWERPC
8562                         /* FIXME: Clean this up */
8563                         if (cfg->compile_aot)
8564                                 use_aotconst = TRUE;
8565 #endif
8566
8567                         /* FIXME: we should really allocate this only late in the compilation process */
8568                         f = mono_domain_alloc (cfg->domain, sizeof (float));
8569                         CHECK_OPSIZE (5);
8570                         CHECK_STACK_OVF (1);
8571
8572                         if (use_aotconst) {
8573                                 MonoInst *cons;
8574                                 int dreg;
8575
8576                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R4, f);
8577
8578                                 dreg = alloc_freg (cfg);
8579                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR4_MEMBASE, dreg, cons->dreg, 0);
8580                                 ins->type = cfg->r4_stack_type;
8581                         } else {
8582                                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
8583                                 ins->type = cfg->r4_stack_type;
8584                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8585                                 ins->inst_p0 = f;
8586                                 MONO_ADD_INS (cfg->cbb, ins);
8587                         }
8588                         ++ip;
8589                         readr4 (ip, f);
8590                         ip += 4;
8591                         *sp++ = ins;                    
8592                         break;
8593                 }
8594                 case CEE_LDC_R8: {
8595                         double *d;
8596                         gboolean use_aotconst = FALSE;
8597
8598 #ifdef TARGET_POWERPC
8599                         /* FIXME: Clean this up */
8600                         if (cfg->compile_aot)
8601                                 use_aotconst = TRUE;
8602 #endif
8603
8604                         /* FIXME: we should really allocate this only late in the compilation process */
8605                         d = mono_domain_alloc (cfg->domain, sizeof (double));
8606                         CHECK_OPSIZE (9);
8607                         CHECK_STACK_OVF (1);
8608
8609                         if (use_aotconst) {
8610                                 MonoInst *cons;
8611                                 int dreg;
8612
8613                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R8, d);
8614
8615                                 dreg = alloc_freg (cfg);
8616                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR8_MEMBASE, dreg, cons->dreg, 0);
8617                                 ins->type = STACK_R8;
8618                         } else {
8619                                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
8620                                 ins->type = STACK_R8;
8621                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8622                                 ins->inst_p0 = d;
8623                                 MONO_ADD_INS (cfg->cbb, ins);
8624                         }
8625                         ++ip;
8626                         readr8 (ip, d);
8627                         ip += 8;
8628                         *sp++ = ins;
8629                         break;
8630                 }
8631                 case CEE_DUP: {
8632                         MonoInst *temp, *store;
8633                         CHECK_STACK (1);
8634                         CHECK_STACK_OVF (1);
8635                         sp--;
8636                         ins = *sp;
8637
8638                         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
8639                         EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
8640
8641                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8642                         *sp++ = ins;
8643
8644                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8645                         *sp++ = ins;
8646
8647                         ++ip;
8648                         inline_costs += 2;
8649                         break;
8650                 }
8651                 case CEE_POP:
8652                         CHECK_STACK (1);
8653                         ip++;
8654                         --sp;
8655
8656 #ifdef TARGET_X86
8657                         if (sp [0]->type == STACK_R8)
8658                                 /* we need to pop the value from the x86 FP stack */
8659                                 MONO_EMIT_NEW_UNALU (cfg, OP_X86_FPOP, -1, sp [0]->dreg);
8660 #endif
8661                         break;
8662                 case CEE_JMP: {
8663                         MonoCallInst *call;
8664                         MonoMethodSignature *fsig;
8665                         int i, n;
8666
8667                         INLINE_FAILURE ("jmp");
8668                         GSHAREDVT_FAILURE (*ip);
8669
8670                         CHECK_OPSIZE (5);
8671                         if (stack_start != sp)
8672                                 UNVERIFIED;
8673                         token = read32 (ip + 1);
8674                         /* FIXME: check the signature matches */
8675                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
8676
8677                         if (!cmethod || mono_loader_get_last_error ())
8678                                 LOAD_ERROR;
8679  
8680                         if (cfg->gshared && mono_method_check_context_used (cmethod))
8681                                 GENERIC_SHARING_FAILURE (CEE_JMP);
8682
8683                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
8684
8685                         fsig = mono_method_signature (cmethod);
8686                         n = fsig->param_count + fsig->hasthis;
8687                         if (cfg->llvm_only) {
8688                                 MonoInst **args;
8689
8690                                 args = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
8691                                 for (i = 0; i < n; ++i)
8692                                         EMIT_NEW_ARGLOAD (cfg, args [i], i);
8693                                 ins = mono_emit_method_call_full (cfg, cmethod, fsig, TRUE, args, NULL, NULL, NULL);
8694                                 /*
8695                                  * The code in mono-basic-block.c treats the rest of the code as dead, but we
8696                                  * have to emit a normal return since llvm expects it.
8697                                  */
8698                                 if (cfg->ret)
8699                                         emit_setret (cfg, ins);
8700                                 MONO_INST_NEW (cfg, ins, OP_BR);
8701                                 ins->inst_target_bb = end_bblock;
8702                                 MONO_ADD_INS (cfg->cbb, ins);
8703                                 link_bblock (cfg, cfg->cbb, end_bblock);
8704                                 ip += 5;
8705                                 break;
8706                         } else if (ARCH_HAVE_OP_TAIL_CALL) {
8707                                 /* Handle tail calls similarly to calls */
8708                                 DISABLE_AOT (cfg);
8709
8710                                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
8711                                 call->method = cmethod;
8712                                 call->tail_call = TRUE;
8713                                 call->signature = mono_method_signature (cmethod);
8714                                 call->args = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
8715                                 call->inst.inst_p0 = cmethod;
8716                                 for (i = 0; i < n; ++i)
8717                                         EMIT_NEW_ARGLOAD (cfg, call->args [i], i);
8718
8719                                 mono_arch_emit_call (cfg, call);
8720                                 cfg->param_area = MAX(cfg->param_area, call->stack_usage);
8721                                 MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
8722                         } else {
8723                                 for (i = 0; i < num_args; ++i)
8724                                         /* Prevent arguments from being optimized away */
8725                                         arg_array [i]->flags |= MONO_INST_VOLATILE;
8726
8727                                 MONO_INST_NEW_CALL (cfg, call, OP_JMP);
8728                                 ins = (MonoInst*)call;
8729                                 ins->inst_p0 = cmethod;
8730                                 MONO_ADD_INS (cfg->cbb, ins);
8731                         }
8732
8733                         ip += 5;
8734                         start_new_bblock = 1;
8735                         break;
8736                 }
8737                 case CEE_CALLI: {
8738                         MonoInst *addr;
8739                         MonoMethodSignature *fsig;
8740
8741                         CHECK_OPSIZE (5);
8742                         token = read32 (ip + 1);
8743
8744                         ins = NULL;
8745
8746                         //GSHAREDVT_FAILURE (*ip);
8747                         cmethod = NULL;
8748                         CHECK_STACK (1);
8749                         --sp;
8750                         addr = *sp;
8751                         fsig = mini_get_signature (method, token, generic_context);
8752
8753                         if (method->dynamic && fsig->pinvoke) {
8754                                 MonoInst *args [3];
8755
8756                                 /*
8757                                  * This is a call through a function pointer using a pinvoke
8758                                  * signature. Have to create a wrapper and call that instead.
8759                                  * FIXME: This is very slow, need to create a wrapper at JIT time
8760                                  * instead based on the signature.
8761                                  */
8762                                 EMIT_NEW_IMAGECONST (cfg, args [0], method->klass->image);
8763                                 EMIT_NEW_PCONST (cfg, args [1], fsig);
8764                                 args [2] = addr;
8765                                 addr = mono_emit_jit_icall (cfg, mono_get_native_calli_wrapper, args);
8766                         }
8767
8768                         n = fsig->param_count + fsig->hasthis;
8769
8770                         CHECK_STACK (n);
8771
8772                         //g_assert (!virtual || fsig->hasthis);
8773
8774                         sp -= n;
8775
8776                         inline_costs += 10 * num_calls++;
8777
8778                         /*
8779                          * Making generic calls out of gsharedvt methods.
8780                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
8781                          * patching gshared method addresses into a gsharedvt method.
8782                          */
8783                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
8784                                 /*
8785                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
8786                                  */
8787                                 MonoInst *callee = addr;
8788
8789                                 if (method->wrapper_type != MONO_WRAPPER_DELEGATE_INVOKE)
8790                                         /* Not tested */
8791                                         GSHAREDVT_FAILURE (*ip);
8792
8793                                 addr = emit_get_rgctx_sig (cfg, context_used,
8794                                                                                           fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
8795                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
8796                                 goto calli_end;
8797                         }
8798
8799                         /* Prevent inlining of methods with indirect calls */
8800                         INLINE_FAILURE ("indirect call");
8801
8802                         if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST || addr->opcode == OP_GOT_ENTRY) {
8803                                 int info_type;
8804                                 gpointer info_data;
8805
8806                                 /*
8807                                  * Instead of emitting an indirect call, emit a direct call
8808                                  * with the contents of the aotconst as the patch info.
8809                                  */
8810                                 if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST) {
8811                                         info_type = addr->inst_c1;
8812                                         info_data = addr->inst_p0;
8813                                 } else {
8814                                         info_type = addr->inst_right->inst_c1;
8815                                         info_data = addr->inst_right->inst_left;
8816                                 }
8817
8818                                 if (info_type == MONO_PATCH_INFO_ICALL_ADDR || info_type == MONO_PATCH_INFO_JIT_ICALL_ADDR) {
8819                                         ins = (MonoInst*)mono_emit_abs_call (cfg, info_type, info_data, fsig, sp);
8820                                         NULLIFY_INS (addr);
8821                                         goto calli_end;
8822                                 }
8823                         }
8824                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8825
8826                         calli_end:
8827
8828                         /* End of call, INS should contain the result of the call, if any */
8829
8830                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8831                                 g_assert (ins);
8832                                 *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
8833                         }
8834
8835                         CHECK_CFG_EXCEPTION;
8836
8837                         ip += 5;
8838                         ins_flag = 0;
8839                         constrained_class = NULL;
8840                         break;
8841                 }
8842                 case CEE_CALL:
8843                 case CEE_CALLVIRT: {
8844                         MonoInst *addr = NULL;
8845                         MonoMethodSignature *fsig = NULL;
8846                         int array_rank = 0;
8847                         int virtual = *ip == CEE_CALLVIRT;
8848                         gboolean pass_imt_from_rgctx = FALSE;
8849                         MonoInst *imt_arg = NULL;
8850                         MonoInst *keep_this_alive = NULL;
8851                         gboolean pass_vtable = FALSE;
8852                         gboolean pass_mrgctx = FALSE;
8853                         MonoInst *vtable_arg = NULL;
8854                         gboolean check_this = FALSE;
8855                         gboolean supported_tail_call = FALSE;
8856                         gboolean tail_call = FALSE;
8857                         gboolean need_seq_point = FALSE;
8858                         guint32 call_opcode = *ip;
8859                         gboolean emit_widen = TRUE;
8860                         gboolean push_res = TRUE;
8861                         gboolean skip_ret = FALSE;
8862                         gboolean delegate_invoke = FALSE;
8863                         gboolean direct_icall = FALSE;
8864                         gboolean constrained_partial_call = FALSE;
8865                         MonoMethod *cil_method;
8866
8867                         CHECK_OPSIZE (5);
8868                         token = read32 (ip + 1);
8869
8870                         ins = NULL;
8871
8872                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
8873                         cil_method = cmethod;
8874                                 
8875                         if (constrained_class) {
8876                                 if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->gshared) {
8877                                         if (!mini_is_gsharedvt_klass (constrained_class)) {
8878                                                 g_assert (!cmethod->klass->valuetype);
8879                                                 if (!mini_type_is_reference (&constrained_class->byval_arg))
8880                                                         constrained_partial_call = TRUE;
8881                                         }
8882                                 }
8883
8884                                 if (method->wrapper_type != MONO_WRAPPER_NONE) {
8885                                         if (cfg->verbose_level > 2)
8886                                                 printf ("DM Constrained call to %s\n", mono_type_get_full_name (constrained_class));
8887                                         if (!((constrained_class->byval_arg.type == MONO_TYPE_VAR ||
8888                                                    constrained_class->byval_arg.type == MONO_TYPE_MVAR) &&
8889                                                   cfg->gshared)) {
8890                                                 cmethod = mono_get_method_constrained_with_method (image, cil_method, constrained_class, generic_context, &cfg->error);
8891                                                 CHECK_CFG_ERROR;
8892                                         }
8893                                 } else {
8894                                         if (cfg->verbose_level > 2)
8895                                                 printf ("Constrained call to %s\n", mono_type_get_full_name (constrained_class));
8896
8897                                         if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->gshared) {
8898                                                 /* 
8899                                                  * This is needed since get_method_constrained can't find 
8900                                                  * the method in klass representing a type var.
8901                                                  * The type var is guaranteed to be a reference type in this
8902                                                  * case.
8903                                                  */
8904                                                 if (!mini_is_gsharedvt_klass (constrained_class))
8905                                                         g_assert (!cmethod->klass->valuetype);
8906                                         } else {
8907                                                 cmethod = mono_get_method_constrained_checked (image, token, constrained_class, generic_context, &cil_method, &cfg->error);
8908                                                 CHECK_CFG_ERROR;
8909                                         }
8910                                 }
8911                         }
8912                                         
8913                         if (!cmethod || mono_loader_get_last_error ())
8914                                 LOAD_ERROR;
8915                         if (!dont_verify && !cfg->skip_visibility) {
8916                                 MonoMethod *target_method = cil_method;
8917                                 if (method->is_inflated) {
8918                                         target_method = mini_get_method_allow_open (method, token, NULL, &(mono_method_get_generic_container (method_definition)->context));
8919                                 }
8920                                 if (!mono_method_can_access_method (method_definition, target_method) &&
8921                                         !mono_method_can_access_method (method, cil_method))
8922                                         METHOD_ACCESS_FAILURE (method, cil_method);
8923                         }
8924
8925                         if (mono_security_core_clr_enabled ())
8926                                 ensure_method_is_allowed_to_call_method (cfg, method, cil_method);
8927
8928                         if (!virtual && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
8929                                 /* MS.NET seems to silently convert this to a callvirt */
8930                                 virtual = 1;
8931
8932                         {
8933                                 /*
8934                                  * MS.NET accepts non virtual calls to virtual final methods of transparent proxy classes and
8935                                  * converts to a callvirt.
8936                                  *
8937                                  * tests/bug-515884.il is an example of this behavior
8938                                  */
8939                                 const int test_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_STATIC;
8940                                 const int expected_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL;
8941                                 if (!virtual && mono_class_is_marshalbyref (cmethod->klass) && (cmethod->flags & test_flags) == expected_flags && cfg->method->wrapper_type == MONO_WRAPPER_NONE)
8942                                         virtual = 1;
8943                         }
8944
8945                         if (!cmethod->klass->inited)
8946                                 if (!mono_class_init (cmethod->klass))
8947                                         TYPE_LOAD_ERROR (cmethod->klass);
8948
8949                         fsig = mono_method_signature (cmethod);
8950                         if (!fsig)
8951                                 LOAD_ERROR;
8952                         if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
8953                                 mini_class_is_system_array (cmethod->klass)) {
8954                                 array_rank = cmethod->klass->rank;
8955                         } else if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && icall_is_direct_callable (cfg, cmethod)) {
8956                                 direct_icall = TRUE;
8957                         } else if (fsig->pinvoke) {
8958                                 MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
8959                                 fsig = mono_method_signature (wrapper);
8960                         } else if (constrained_class) {
8961                         } else {
8962                                 fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
8963                                 CHECK_CFG_ERROR;
8964                         }
8965
8966                         /* See code below */
8967                         if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
8968                                 MonoBasicBlock *tbb;
8969
8970                                 GET_BBLOCK (cfg, tbb, ip + 5);
8971                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
8972                                         /*
8973                                          * We want to extend the try block to cover the call, but we can't do it if the
8974                                          * call is made directly since its followed by an exception check.
8975                                          */
8976                                         direct_icall = FALSE;
8977                                 }
8978                         }
8979
8980                         mono_save_token_info (cfg, image, token, cil_method);
8981
8982                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip + 5 - header->code)))
8983                                 need_seq_point = TRUE;
8984
8985                         /* Don't support calls made using type arguments for now */
8986                         /*
8987                           if (cfg->gsharedvt) {
8988                           if (mini_is_gsharedvt_signature (fsig))
8989                           GSHAREDVT_FAILURE (*ip);
8990                           }
8991                         */
8992
8993                         if (cmethod->string_ctor && method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE)
8994                                 g_assert_not_reached ();
8995
8996                         n = fsig->param_count + fsig->hasthis;
8997
8998                         if (!cfg->gshared && cmethod->klass->generic_container)
8999                                 UNVERIFIED;
9000
9001                         if (!cfg->gshared)
9002                                 g_assert (!mono_method_check_context_used (cmethod));
9003
9004                         CHECK_STACK (n);
9005
9006                         //g_assert (!virtual || fsig->hasthis);
9007
9008                         sp -= n;
9009
9010                         if (constrained_class) {
9011                                 if (mini_is_gsharedvt_klass (constrained_class)) {
9012                                         if ((cmethod->klass != mono_defaults.object_class) && constrained_class->valuetype && cmethod->klass->valuetype) {
9013                                                 /* The 'Own method' case below */
9014                                         } else if (cmethod->klass->image != mono_defaults.corlib && !(cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !cmethod->klass->valuetype) {
9015                                                 /* 'The type parameter is instantiated as a reference type' case below. */
9016                                         } else {
9017                                                 ins = handle_constrained_gsharedvt_call (cfg, cmethod, fsig, sp, constrained_class, &emit_widen);
9018                                                 CHECK_CFG_EXCEPTION;
9019                                                 g_assert (ins);
9020                                                 goto call_end;
9021                                         }
9022                                 }
9023
9024                                 /*
9025                                  * We have the `constrained.' prefix opcode.
9026                                  */
9027                                 if (constrained_partial_call) {
9028                                         gboolean need_box = TRUE;
9029
9030                                         /*
9031                                          * The receiver is a valuetype, but the exact type is not known at compile time. This means the
9032                                          * called method is not known at compile time either. The called method could end up being
9033                                          * one of the methods on the parent classes (object/valuetype/enum), in which case we need
9034                                          * to box the receiver.
9035                                          * A simple solution would be to box always and make a normal virtual call, but that would
9036                                          * be bad performance wise.
9037                                          */
9038                                         if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE && cmethod->klass->generic_class) {
9039                                                 /*
9040                                                  * The parent classes implement no generic interfaces, so the called method will be a vtype method, so no boxing neccessary.
9041                                                  */
9042                                                 need_box = FALSE;
9043                                         }
9044
9045                                         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)) {
9046                                                 /* The called method is not virtual, i.e. Object:GetType (), the receiver is a vtype, has to box */
9047                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9048                                                 ins->klass = constrained_class;
9049                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9050                                                 CHECK_CFG_EXCEPTION;
9051                                         } else if (need_box) {
9052                                                 MonoInst *box_type;
9053                                                 MonoBasicBlock *is_ref_bb, *end_bb;
9054                                                 MonoInst *nonbox_call;
9055
9056                                                 /*
9057                                                  * Determine at runtime whenever the called method is defined on object/valuetype/enum, and emit a boxing call
9058                                                  * if needed.
9059                                                  * FIXME: It is possible to inline the called method in a lot of cases, i.e. for T_INT,
9060                                                  * the no-box case goes to a method in Int32, while the box case goes to a method in Enum.
9061                                                  */
9062                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
9063
9064                                                 NEW_BBLOCK (cfg, is_ref_bb);
9065                                                 NEW_BBLOCK (cfg, end_bb);
9066
9067                                                 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);
9068                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, box_type->dreg, 1);
9069                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
9070
9071                                                 /* Non-ref case */
9072                                                 nonbox_call = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9073
9074                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
9075
9076                                                 /* Ref case */
9077                                                 MONO_START_BB (cfg, is_ref_bb);
9078                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9079                                                 ins->klass = constrained_class;
9080                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9081                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9082
9083                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
9084
9085                                                 MONO_START_BB (cfg, end_bb);
9086                                                 cfg->cbb = end_bb;
9087
9088                                                 nonbox_call->dreg = ins->dreg;
9089                                                 goto call_end;
9090                                         } else {
9091                                                 g_assert (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE);
9092                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
9093                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9094                                                 goto call_end;
9095                                         }
9096                                 } else if (constrained_class->valuetype && (cmethod->klass == mono_defaults.object_class || cmethod->klass == mono_defaults.enum_class->parent || cmethod->klass == mono_defaults.enum_class)) {
9097                                         /*
9098                                          * The type parameter is instantiated as a valuetype,
9099                                          * but that type doesn't override the method we're
9100                                          * calling, so we need to box `this'.
9101                                          */
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                                         CHECK_CFG_EXCEPTION;
9106                                 } else if (!constrained_class->valuetype) {
9107                                         int dreg = alloc_ireg_ref (cfg);
9108
9109                                         /*
9110                                          * The type parameter is instantiated as a reference
9111                                          * type.  We have a managed pointer on the stack, so
9112                                          * we need to dereference it here.
9113                                          */
9114                                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, sp [0]->dreg, 0);
9115                                         ins->type = STACK_OBJ;
9116                                         sp [0] = ins;
9117                                 } else {
9118                                         if (cmethod->klass->valuetype) {
9119                                                 /* Own method */
9120                                         } else {
9121                                                 /* Interface method */
9122                                                 int ioffset, slot;
9123
9124                                                 mono_class_setup_vtable (constrained_class);
9125                                                 CHECK_TYPELOAD (constrained_class);
9126                                                 ioffset = mono_class_interface_offset (constrained_class, cmethod->klass);
9127                                                 if (ioffset == -1)
9128                                                         TYPE_LOAD_ERROR (constrained_class);
9129                                                 slot = mono_method_get_vtable_slot (cmethod);
9130                                                 if (slot == -1)
9131                                                         TYPE_LOAD_ERROR (cmethod->klass);
9132                                                 cmethod = constrained_class->vtable [ioffset + slot];
9133
9134                                                 if (cmethod->klass == mono_defaults.enum_class) {
9135                                                         /* Enum implements some interfaces, so treat this as the first case */
9136                                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9137                                                         ins->klass = constrained_class;
9138                                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9139                                                         CHECK_CFG_EXCEPTION;
9140                                                 }
9141                                         }
9142                                         virtual = 0;
9143                                 }
9144                                 constrained_class = NULL;
9145                         }
9146
9147                         if (check_call_signature (cfg, fsig, sp))
9148                                 UNVERIFIED;
9149
9150                         if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (cmethod->name, "Invoke"))
9151                                 delegate_invoke = TRUE;
9152
9153                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_sharable_method (cfg, cmethod, fsig, sp))) {
9154                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9155                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
9156                                         emit_widen = FALSE;
9157                                 }
9158
9159                                 goto call_end;
9160                         }
9161
9162                         /* 
9163                          * If the callee is a shared method, then its static cctor
9164                          * might not get called after the call was patched.
9165                          */
9166                         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)) {
9167                                 emit_class_init (cfg, cmethod->klass);
9168                                 CHECK_TYPELOAD (cmethod->klass);
9169                         }
9170
9171                         check_method_sharing (cfg, cmethod, &pass_vtable, &pass_mrgctx);
9172
9173                         if (cfg->gshared) {
9174                                 MonoGenericContext *cmethod_context = mono_method_get_context (cmethod);
9175
9176                                 context_used = mini_method_check_context_used (cfg, cmethod);
9177
9178                                 if (context_used && (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
9179                                         /* Generic method interface
9180                                            calls are resolved via a
9181                                            helper function and don't
9182                                            need an imt. */
9183                                         if (!cmethod_context || !cmethod_context->method_inst)
9184                                                 pass_imt_from_rgctx = TRUE;
9185                                 }
9186
9187                                 /*
9188                                  * If a shared method calls another
9189                                  * shared method then the caller must
9190                                  * have a generic sharing context
9191                                  * because the magic trampoline
9192                                  * requires it.  FIXME: We shouldn't
9193                                  * have to force the vtable/mrgctx
9194                                  * variable here.  Instead there
9195                                  * should be a flag in the cfg to
9196                                  * request a generic sharing context.
9197                                  */
9198                                 if (context_used &&
9199                                                 ((method->flags & METHOD_ATTRIBUTE_STATIC) || method->klass->valuetype))
9200                                         mono_get_vtable_var (cfg);
9201                         }
9202
9203                         if (pass_vtable) {
9204                                 if (context_used) {
9205                                         vtable_arg = emit_get_rgctx_klass (cfg, context_used, cmethod->klass, MONO_RGCTX_INFO_VTABLE);
9206                                 } else {
9207                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
9208
9209                                         CHECK_TYPELOAD (cmethod->klass);
9210                                         EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
9211                                 }
9212                         }
9213
9214                         if (pass_mrgctx) {
9215                                 g_assert (!vtable_arg);
9216
9217                                 if (!cfg->compile_aot) {
9218                                         /* 
9219                                          * emit_get_rgctx_method () calls mono_class_vtable () so check 
9220                                          * for type load errors before.
9221                                          */
9222                                         mono_class_setup_vtable (cmethod->klass);
9223                                         CHECK_TYPELOAD (cmethod->klass);
9224                                 }
9225
9226                                 vtable_arg = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
9227
9228                                 /* !marshalbyref is needed to properly handle generic methods + remoting */
9229                                 if ((!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
9230                                          MONO_METHOD_IS_FINAL (cmethod)) &&
9231                                         !mono_class_is_marshalbyref (cmethod->klass)) {
9232                                         if (virtual)
9233                                                 check_this = TRUE;
9234                                         virtual = 0;
9235                                 }
9236                         }
9237
9238                         if (pass_imt_from_rgctx) {
9239                                 g_assert (!pass_vtable);
9240
9241                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9242                                         cmethod, MONO_RGCTX_INFO_METHOD);
9243                         }
9244
9245                         if (check_this)
9246                                 MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9247
9248                         /* Calling virtual generic methods */
9249                         if (virtual && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) && 
9250                             !(MONO_METHOD_IS_FINAL (cmethod) && 
9251                               cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) &&
9252                             fsig->generic_param_count && 
9253                                 !(cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) &&
9254                                 !cfg->llvm_only) {
9255                                 MonoInst *this_temp, *this_arg_temp, *store;
9256                                 MonoInst *iargs [4];
9257                                 gboolean use_imt = FALSE;
9258
9259                                 g_assert (fsig->is_inflated);
9260
9261                                 /* Prevent inlining of methods that contain indirect calls */
9262                                 INLINE_FAILURE ("virtual generic call");
9263
9264                                 if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))
9265                                         GSHAREDVT_FAILURE (*ip);
9266
9267 #if MONO_ARCH_HAVE_GENERALIZED_IMT_THUNK && defined(MONO_ARCH_GSHARED_SUPPORTED)
9268                                 if (cmethod->wrapper_type == MONO_WRAPPER_NONE)
9269                                         use_imt = TRUE;
9270 #endif
9271
9272                                 if (use_imt) {
9273                                         g_assert (!imt_arg);
9274                                         if (!context_used)
9275                                                 g_assert (cmethod->is_inflated);
9276                                         imt_arg = emit_get_rgctx_method (cfg, context_used,
9277                                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
9278                                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, sp [0], imt_arg, NULL);
9279                                 } else {
9280                                         this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
9281                                         NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
9282                                         MONO_ADD_INS (cfg->cbb, store);
9283
9284                                         /* FIXME: This should be a managed pointer */
9285                                         this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
9286
9287                                         EMIT_NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
9288                                         iargs [1] = emit_get_rgctx_method (cfg, context_used,
9289                                                                                                            cmethod, MONO_RGCTX_INFO_METHOD);
9290                                         EMIT_NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
9291                                         addr = mono_emit_jit_icall (cfg,
9292                                                                                                 mono_helper_compile_generic_method, iargs);
9293
9294                                         EMIT_NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
9295
9296                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9297                                 }
9298
9299                                 goto call_end;
9300                         }
9301
9302                         /*
9303                          * Implement a workaround for the inherent races involved in locking:
9304                          * Monitor.Enter ()
9305                          * try {
9306                          * } finally {
9307                          *    Monitor.Exit ()
9308                          * }
9309                          * If a thread abort happens between the call to Monitor.Enter () and the start of the
9310                          * try block, the Exit () won't be executed, see:
9311                          * http://www.bluebytesoftware.com/blog/2007/01/30/MonitorEnterThreadAbortsAndOrphanedLocks.aspx
9312                          * To work around this, we extend such try blocks to include the last x bytes
9313                          * of the Monitor.Enter () call.
9314                          */
9315                         if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
9316                                 MonoBasicBlock *tbb;
9317
9318                                 GET_BBLOCK (cfg, tbb, ip + 5);
9319                                 /* 
9320                                  * Only extend try blocks with a finally, to avoid catching exceptions thrown
9321                                  * from Monitor.Enter like ArgumentNullException.
9322                                  */
9323                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
9324                                         /* Mark this bblock as needing to be extended */
9325                                         tbb->extend_try_block = TRUE;
9326                                 }
9327                         }
9328
9329                         /* Conversion to a JIT intrinsic */
9330                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_method (cfg, cmethod, fsig, sp))) {
9331                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9332                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
9333                                         emit_widen = FALSE;
9334                                 }
9335                                 goto call_end;
9336                         }
9337
9338                         /* Inlining */
9339                         if ((cfg->opt & MONO_OPT_INLINE) &&
9340                                 (!virtual || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || MONO_METHOD_IS_FINAL (cmethod)) &&
9341                             mono_method_check_inlining (cfg, cmethod)) {
9342                                 int costs;
9343                                 gboolean always = FALSE;
9344
9345                                 if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
9346                                         (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
9347                                         /* Prevent inlining of methods that call wrappers */
9348                                         INLINE_FAILURE ("wrapper call");
9349                                         cmethod = mono_marshal_get_native_wrapper (cmethod, TRUE, FALSE);
9350                                         always = TRUE;
9351                                 }
9352
9353                                 costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, always);
9354                                 if (costs) {
9355                                         cfg->real_offset += 5;
9356
9357                                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9358                                                 /* *sp is already set by inline_method */
9359                                                 sp++;
9360                                                 push_res = FALSE;
9361                                         }
9362
9363                                         inline_costs += costs;
9364
9365                                         goto call_end;
9366                                 }
9367                         }
9368
9369                         /* Tail recursion elimination */
9370                         if ((cfg->opt & MONO_OPT_TAILC) && call_opcode == CEE_CALL && cmethod == method && ip [5] == CEE_RET && !vtable_arg) {
9371                                 gboolean has_vtargs = FALSE;
9372                                 int i;
9373
9374                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9375                                 INLINE_FAILURE ("tail call");
9376
9377                                 /* keep it simple */
9378                                 for (i =  fsig->param_count - 1; i >= 0; i--) {
9379                                         if (MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->params [i])) 
9380                                                 has_vtargs = TRUE;
9381                                 }
9382
9383                                 if (!has_vtargs) {
9384                                         for (i = 0; i < n; ++i)
9385                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9386                                         MONO_INST_NEW (cfg, ins, OP_BR);
9387                                         MONO_ADD_INS (cfg->cbb, ins);
9388                                         tblock = start_bblock->out_bb [0];
9389                                         link_bblock (cfg, cfg->cbb, tblock);
9390                                         ins->inst_target_bb = tblock;
9391                                         start_new_bblock = 1;
9392
9393                                         /* skip the CEE_RET, too */
9394                                         if (ip_in_bb (cfg, cfg->cbb, ip + 5))
9395                                                 skip_ret = TRUE;
9396                                         push_res = FALSE;
9397                                         goto call_end;
9398                                 }
9399                         }
9400
9401                         inline_costs += 10 * num_calls++;
9402
9403                         /*
9404                          * Making generic calls out of gsharedvt methods.
9405                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
9406                          * patching gshared method addresses into a gsharedvt method.
9407                          */
9408                         if (cfg->gsharedvt && (mini_is_gsharedvt_signature (fsig) || cmethod->is_inflated || cmethod->klass->generic_class) &&
9409                                 !(cmethod->klass->rank && cmethod->klass->byval_arg.type != MONO_TYPE_SZARRAY)) {
9410                                 MonoRgctxInfoType info_type;
9411
9412                                 if (virtual) {
9413                                         //if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
9414                                                 //GSHAREDVT_FAILURE (*ip);
9415                                         // disable for possible remoting calls
9416                                         if (fsig->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class))
9417                                                 GSHAREDVT_FAILURE (*ip);
9418                                         if (fsig->generic_param_count) {
9419                                                 /* virtual generic call */
9420                                                 g_assert (!imt_arg);
9421                                                 /* Same as the virtual generic case above */
9422                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9423                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9424                                                 /* This is not needed, as the trampoline code will pass one, and it might be passed in the same reg as the imt arg */
9425                                                 vtable_arg = NULL;
9426                                         } else if ((cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !imt_arg) {
9427                                                 /* This can happen when we call a fully instantiated iface method */
9428                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9429                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9430                                                 vtable_arg = NULL;
9431                                         }
9432                                 }
9433
9434                                 if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (cmethod->name, "Invoke")))
9435                                         keep_this_alive = sp [0];
9436
9437                                 if (virtual && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))
9438                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
9439                                 else
9440                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE;
9441                                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, info_type);
9442
9443                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9444                                 goto call_end;
9445                         }
9446
9447                         /* Generic sharing */
9448
9449                         /*
9450                          * Use this if the callee is gsharedvt sharable too, since
9451                          * at runtime we might find an instantiation so the call cannot
9452                          * be patched (the 'no_patch' code path in mini-trampolines.c).
9453                          */
9454                         if (context_used && !imt_arg && !array_rank && !delegate_invoke &&
9455                                 (!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
9456                                  !mono_class_generic_sharing_enabled (cmethod->klass)) &&
9457                                 (!virtual || MONO_METHOD_IS_FINAL (cmethod) ||
9458                                  !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))) {
9459                                 INLINE_FAILURE ("gshared");
9460
9461                                 g_assert (cfg->gshared && cmethod);
9462                                 g_assert (!addr);
9463
9464                                 /*
9465                                  * We are compiling a call to a
9466                                  * generic method from shared code,
9467                                  * which means that we have to look up
9468                                  * the method in the rgctx and do an
9469                                  * indirect call.
9470                                  */
9471                                 if (fsig->hasthis)
9472                                         MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9473
9474                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
9475                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9476                                 goto call_end;
9477                         }
9478
9479                         /* Direct calls to icalls */
9480                         if (direct_icall) {
9481                                 MonoMethod *wrapper;
9482                                 int costs;
9483
9484                                 /* Inline the wrapper */
9485                                 wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
9486
9487                                 costs = inline_method (cfg, wrapper, fsig, sp, ip, cfg->real_offset, TRUE);
9488                                 g_assert (costs > 0);
9489                                 cfg->real_offset += 5;
9490
9491                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9492                                         /* *sp is already set by inline_method */
9493                                         sp++;
9494                                         push_res = FALSE;
9495                                 }
9496
9497                                 inline_costs += costs;
9498
9499                                 goto call_end;
9500                         }
9501                                         
9502                         /* Array methods */
9503                         if (array_rank) {
9504                                 MonoInst *addr;
9505
9506                                 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ 
9507                                         MonoInst *val = sp [fsig->param_count];
9508
9509                                         if (val->type == STACK_OBJ) {
9510                                                 MonoInst *iargs [2];
9511
9512                                                 iargs [0] = sp [0];
9513                                                 iargs [1] = val;
9514                                                 
9515                                                 mono_emit_jit_icall (cfg, mono_helper_stelem_ref_check, iargs);
9516                                         }
9517                                         
9518                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, TRUE);
9519                                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, fsig->params [fsig->param_count - 1], addr->dreg, 0, val->dreg);
9520                                         if (cfg->gen_write_barriers && val->type == STACK_OBJ && !(val->opcode == OP_PCONST && val->inst_c0 == 0))
9521                                                 emit_write_barrier (cfg, addr, val);
9522                                         if (cfg->gen_write_barriers && mini_is_gsharedvt_klass (cmethod->klass))
9523                                                 GSHAREDVT_FAILURE (*ip);
9524                                 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
9525                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9526
9527                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, addr->dreg, 0);
9528                                 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
9529                                         if (!cmethod->klass->element_class->valuetype && !readonly)
9530                                                 mini_emit_check_array_type (cfg, sp [0], cmethod->klass);
9531                                         CHECK_TYPELOAD (cmethod->klass);
9532                                         
9533                                         readonly = FALSE;
9534                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9535                                         ins = addr;
9536                                 } else {
9537                                         g_assert_not_reached ();
9538                                 }
9539
9540                                 emit_widen = FALSE;
9541                                 goto call_end;
9542                         }
9543
9544                         ins = mini_redirect_call (cfg, cmethod, fsig, sp, virtual ? sp [0] : NULL);
9545                         if (ins)
9546                                 goto call_end;
9547
9548                         /* Tail prefix / tail call optimization */
9549
9550                         /* FIXME: Enabling TAILC breaks some inlining/stack trace/etc tests */
9551                         /* FIXME: runtime generic context pointer for jumps? */
9552                         /* FIXME: handle this for generic sharing eventually */
9553                         if ((ins_flag & MONO_INST_TAILCALL) &&
9554                                 !vtable_arg && !cfg->gshared && is_supported_tail_call (cfg, method, cmethod, fsig, call_opcode))
9555                                 supported_tail_call = TRUE;
9556
9557                         if (supported_tail_call) {
9558                                 MonoCallInst *call;
9559
9560                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9561                                 INLINE_FAILURE ("tail call");
9562
9563                                 //printf ("HIT: %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
9564
9565                                 if (ARCH_HAVE_OP_TAIL_CALL) {
9566                                         /* Handle tail calls similarly to normal calls */
9567                                         tail_call = TRUE;
9568                                 } else {
9569                                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
9570
9571                                         MONO_INST_NEW_CALL (cfg, call, OP_JMP);
9572                                         call->tail_call = TRUE;
9573                                         call->method = cmethod;
9574                                         call->signature = mono_method_signature (cmethod);
9575
9576                                         /*
9577                                          * We implement tail calls by storing the actual arguments into the 
9578                                          * argument variables, then emitting a CEE_JMP.
9579                                          */
9580                                         for (i = 0; i < n; ++i) {
9581                                                 /* Prevent argument from being register allocated */
9582                                                 arg_array [i]->flags |= MONO_INST_VOLATILE;
9583                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9584                                         }
9585                                         ins = (MonoInst*)call;
9586                                         ins->inst_p0 = cmethod;
9587                                         ins->inst_p1 = arg_array [0];
9588                                         MONO_ADD_INS (cfg->cbb, ins);
9589                                         link_bblock (cfg, cfg->cbb, end_bblock);
9590                                         start_new_bblock = 1;
9591
9592                                         // FIXME: Eliminate unreachable epilogs
9593
9594                                         /*
9595                                          * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9596                                          * only reachable from this call.
9597                                          */
9598                                         GET_BBLOCK (cfg, tblock, ip + 5);
9599                                         if (tblock == cfg->cbb || tblock->in_count == 0)
9600                                                 skip_ret = TRUE;
9601                                         push_res = FALSE;
9602
9603                                         goto call_end;
9604                                 }
9605                         }
9606
9607                         /* 
9608                          * Synchronized wrappers.
9609                          * Its hard to determine where to replace a method with its synchronized
9610                          * wrapper without causing an infinite recursion. The current solution is
9611                          * to add the synchronized wrapper in the trampolines, and to
9612                          * change the called method to a dummy wrapper, and resolve that wrapper
9613                          * to the real method in mono_jit_compile_method ().
9614                          */
9615                         if (cfg->method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
9616                                 MonoMethod *orig = mono_marshal_method_from_wrapper (cfg->method);
9617                                 if (cmethod == orig || (cmethod->is_inflated && mono_method_get_declaring_generic_method (cmethod) == orig))
9618                                         cmethod = mono_marshal_get_synchronized_inner_wrapper (cmethod);
9619                         }
9620
9621                         /*
9622                          * Interface calls in llvm-only mode are complicated becase the callee might need an rgctx arg,
9623                          * (i.e. its a vtype method), and there is no way to for the caller to know this at compile time.
9624                          * So we make resolve_iface_call return the rgctx, and do two calls with different signatures
9625                          * based on whenever there is an rgctx or not.
9626                          */
9627                         if (cfg->llvm_only && virtual && cmethod && (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
9628                                 MonoInst *args [16], *icall_args [16];
9629                                 MonoBasicBlock *rgctx_bb, *end_bb;
9630                                 MonoInst *call1, *call2, *call_target;
9631                                 MonoMethodSignature *rgctx_sig;
9632                                 int rgctx_reg, tmp_reg;
9633
9634                                 MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
9635
9636                                 NEW_BBLOCK (cfg, rgctx_bb);
9637                                 NEW_BBLOCK (cfg, end_bb);
9638
9639                                 // FIXME: Optimize this
9640
9641                                 guint32 imt_slot = mono_method_get_imt_slot (cmethod);
9642
9643                                 icall_args [0] = sp [0];
9644                                 EMIT_NEW_ICONST (cfg, icall_args [1], imt_slot);
9645                                 if (imt_arg) {
9646                                         icall_args [2] = imt_arg;
9647                                 } else {
9648                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_METHODCONST, cmethod);
9649                                         icall_args [2] = ins;
9650                                 }
9651
9652                                 rgctx_reg = alloc_preg (cfg);
9653                                 MONO_EMIT_NEW_PCONST (cfg, rgctx_reg, NULL);
9654                                 EMIT_NEW_VARLOADA_VREG (cfg, icall_args [3], rgctx_reg, &mono_defaults.int_class->byval_arg);
9655                                 //EMIT_NEW_PCONST (cfg, icall_args [3], NULL);
9656
9657                                 call_target = mono_emit_jit_icall (cfg, mono_resolve_iface_call, icall_args);
9658
9659                                 // FIXME: Only do this if needed (generic calls)
9660
9661                                 // Check whenever to pass an rgctx
9662                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rgctx_reg, 0);
9663                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, rgctx_bb);
9664                                 /* Non rgctx case */
9665                                 call1 = mono_emit_calli (cfg, fsig, sp, call_target, NULL, vtable_arg);
9666                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
9667                                 /* Rgctx case */
9668                                 MONO_START_BB (cfg, rgctx_bb);
9669                                 /* Make a call with an rgctx */
9670                                 g_assert (fsig->param_count + 2 < 16);
9671                                 args [0] = sp [0];
9672                                 for (i = 0; i < fsig->param_count; ++i)
9673                                         args [i + 1] = sp [i + 1];
9674                                 tmp_reg = alloc_preg (cfg);
9675                                 EMIT_NEW_UNALU (cfg, args [fsig->param_count + 1], OP_MOVE, tmp_reg, rgctx_reg);
9676                                 rgctx_sig = sig_to_rgctx_sig (fsig);
9677                                 call2 = mono_emit_calli (cfg, rgctx_sig, args, call_target, NULL, NULL);
9678                                 call2->dreg = call1->dreg;
9679                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
9680                                 /* End */
9681                                 MONO_START_BB (cfg, end_bb);
9682                                 ins = call1;
9683                                 goto call_end;
9684                         }
9685
9686                         /* Common call */
9687                         INLINE_FAILURE ("call");
9688                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, tail_call, sp, virtual ? sp [0] : NULL,
9689                                                                                           imt_arg, vtable_arg);
9690
9691                         if (tail_call && !cfg->llvm_only) {
9692                                 link_bblock (cfg, cfg->cbb, end_bblock);
9693                                 start_new_bblock = 1;
9694
9695                                 // FIXME: Eliminate unreachable epilogs
9696
9697                                 /*
9698                                  * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9699                                  * only reachable from this call.
9700                                  */
9701                                 GET_BBLOCK (cfg, tblock, ip + 5);
9702                                 if (tblock == cfg->cbb || tblock->in_count == 0)
9703                                         skip_ret = TRUE;
9704                                 push_res = FALSE;
9705                         }
9706
9707                         call_end:
9708
9709                         /* End of call, INS should contain the result of the call, if any */
9710
9711                         if (push_res && !MONO_TYPE_IS_VOID (fsig->ret)) {
9712                                 g_assert (ins);
9713                                 if (emit_widen)
9714                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
9715                                 else
9716                                         *sp++ = ins;
9717                         }
9718
9719                         if (keep_this_alive) {
9720                                 MonoInst *dummy_use;
9721
9722                                 /* See mono_emit_method_call_full () */
9723                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, keep_this_alive);
9724                         }
9725
9726                         CHECK_CFG_EXCEPTION;
9727
9728                         ip += 5;
9729                         if (skip_ret) {
9730                                 g_assert (*ip == CEE_RET);
9731                                 ip += 1;
9732                         }
9733                         ins_flag = 0;
9734                         constrained_class = NULL;
9735                         if (need_seq_point)
9736                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
9737                         break;
9738                 }
9739                 case CEE_RET:
9740                         if (cfg->method != method) {
9741                                 /* return from inlined method */
9742                                 /* 
9743                                  * If in_count == 0, that means the ret is unreachable due to
9744                                  * being preceeded by a throw. In that case, inline_method () will
9745                                  * handle setting the return value 
9746                                  * (test case: test_0_inline_throw ()).
9747                                  */
9748                                 if (return_var && cfg->cbb->in_count) {
9749                                         MonoType *ret_type = mono_method_signature (method)->ret;
9750
9751                                         MonoInst *store;
9752                                         CHECK_STACK (1);
9753                                         --sp;
9754
9755                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
9756                                                 UNVERIFIED;
9757
9758                                         //g_assert (returnvar != -1);
9759                                         EMIT_NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
9760                                         cfg->ret_var_set = TRUE;
9761                                 } 
9762                         } else {
9763                                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
9764
9765                                 if (cfg->lmf_var && cfg->cbb->in_count && !cfg->llvm_only)
9766                                         emit_pop_lmf (cfg);
9767
9768                                 if (cfg->ret) {
9769                                         MonoType *ret_type = mini_get_underlying_type (mono_method_signature (method)->ret);
9770
9771                                         if (seq_points && !sym_seq_points) {
9772                                                 /* 
9773                                                  * Place a seq point here too even through the IL stack is not
9774                                                  * empty, so a step over on
9775                                                  * call <FOO>
9776                                                  * ret
9777                                                  * will work correctly.
9778                                                  */
9779                                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, TRUE);
9780                                                 MONO_ADD_INS (cfg->cbb, ins);
9781                                         }
9782
9783                                         g_assert (!return_var);
9784                                         CHECK_STACK (1);
9785                                         --sp;
9786
9787                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
9788                                                 UNVERIFIED;
9789
9790                                         emit_setret (cfg, *sp);
9791                                 }
9792                         }
9793                         if (sp != stack_start)
9794                                 UNVERIFIED;
9795                         MONO_INST_NEW (cfg, ins, OP_BR);
9796                         ip++;
9797                         ins->inst_target_bb = end_bblock;
9798                         MONO_ADD_INS (cfg->cbb, ins);
9799                         link_bblock (cfg, cfg->cbb, end_bblock);
9800                         start_new_bblock = 1;
9801                         break;
9802                 case CEE_BR_S:
9803                         CHECK_OPSIZE (2);
9804                         MONO_INST_NEW (cfg, ins, OP_BR);
9805                         ip++;
9806                         target = ip + 1 + (signed char)(*ip);
9807                         ++ip;
9808                         GET_BBLOCK (cfg, tblock, target);
9809                         link_bblock (cfg, cfg->cbb, tblock);
9810                         ins->inst_target_bb = tblock;
9811                         if (sp != stack_start) {
9812                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9813                                 sp = stack_start;
9814                                 CHECK_UNVERIFIABLE (cfg);
9815                         }
9816                         MONO_ADD_INS (cfg->cbb, ins);
9817                         start_new_bblock = 1;
9818                         inline_costs += BRANCH_COST;
9819                         break;
9820                 case CEE_BEQ_S:
9821                 case CEE_BGE_S:
9822                 case CEE_BGT_S:
9823                 case CEE_BLE_S:
9824                 case CEE_BLT_S:
9825                 case CEE_BNE_UN_S:
9826                 case CEE_BGE_UN_S:
9827                 case CEE_BGT_UN_S:
9828                 case CEE_BLE_UN_S:
9829                 case CEE_BLT_UN_S:
9830                         CHECK_OPSIZE (2);
9831                         CHECK_STACK (2);
9832                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
9833                         ip++;
9834                         target = ip + 1 + *(signed char*)ip;
9835                         ip++;
9836
9837                         ADD_BINCOND (NULL);
9838
9839                         sp = stack_start;
9840                         inline_costs += BRANCH_COST;
9841                         break;
9842                 case CEE_BR:
9843                         CHECK_OPSIZE (5);
9844                         MONO_INST_NEW (cfg, ins, OP_BR);
9845                         ip++;
9846
9847                         target = ip + 4 + (gint32)read32(ip);
9848                         ip += 4;
9849                         GET_BBLOCK (cfg, tblock, target);
9850                         link_bblock (cfg, cfg->cbb, tblock);
9851                         ins->inst_target_bb = tblock;
9852                         if (sp != stack_start) {
9853                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9854                                 sp = stack_start;
9855                                 CHECK_UNVERIFIABLE (cfg);
9856                         }
9857
9858                         MONO_ADD_INS (cfg->cbb, ins);
9859
9860                         start_new_bblock = 1;
9861                         inline_costs += BRANCH_COST;
9862                         break;
9863                 case CEE_BRFALSE_S:
9864                 case CEE_BRTRUE_S:
9865                 case CEE_BRFALSE:
9866                 case CEE_BRTRUE: {
9867                         MonoInst *cmp;
9868                         gboolean is_short = ((*ip) == CEE_BRFALSE_S) || ((*ip) == CEE_BRTRUE_S);
9869                         gboolean is_true = ((*ip) == CEE_BRTRUE_S) || ((*ip) == CEE_BRTRUE);
9870                         guint32 opsize = is_short ? 1 : 4;
9871
9872                         CHECK_OPSIZE (opsize);
9873                         CHECK_STACK (1);
9874                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
9875                                 UNVERIFIED;
9876                         ip ++;
9877                         target = ip + opsize + (is_short ? *(signed char*)ip : (gint32)read32(ip));
9878                         ip += opsize;
9879
9880                         sp--;
9881
9882                         GET_BBLOCK (cfg, tblock, target);
9883                         link_bblock (cfg, cfg->cbb, tblock);
9884                         GET_BBLOCK (cfg, tblock, ip);
9885                         link_bblock (cfg, cfg->cbb, tblock);
9886
9887                         if (sp != stack_start) {
9888                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9889                                 CHECK_UNVERIFIABLE (cfg);
9890                         }
9891
9892                         MONO_INST_NEW(cfg, cmp, OP_ICOMPARE_IMM);
9893                         cmp->sreg1 = sp [0]->dreg;
9894                         type_from_op (cfg, cmp, sp [0], NULL);
9895                         CHECK_TYPE (cmp);
9896
9897 #if SIZEOF_REGISTER == 4
9898                         if (cmp->opcode == OP_LCOMPARE_IMM) {
9899                                 /* Convert it to OP_LCOMPARE */
9900                                 MONO_INST_NEW (cfg, ins, OP_I8CONST);
9901                                 ins->type = STACK_I8;
9902                                 ins->dreg = alloc_dreg (cfg, STACK_I8);
9903                                 ins->inst_l = 0;
9904                                 MONO_ADD_INS (cfg->cbb, ins);
9905                                 cmp->opcode = OP_LCOMPARE;
9906                                 cmp->sreg2 = ins->dreg;
9907                         }
9908 #endif
9909                         MONO_ADD_INS (cfg->cbb, cmp);
9910
9911                         MONO_INST_NEW (cfg, ins, is_true ? CEE_BNE_UN : CEE_BEQ);
9912                         type_from_op (cfg, ins, sp [0], NULL);
9913                         MONO_ADD_INS (cfg->cbb, ins);
9914                         ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);
9915                         GET_BBLOCK (cfg, tblock, target);
9916                         ins->inst_true_bb = tblock;
9917                         GET_BBLOCK (cfg, tblock, ip);
9918                         ins->inst_false_bb = tblock;
9919                         start_new_bblock = 2;
9920
9921                         sp = stack_start;
9922                         inline_costs += BRANCH_COST;
9923                         break;
9924                 }
9925                 case CEE_BEQ:
9926                 case CEE_BGE:
9927                 case CEE_BGT:
9928                 case CEE_BLE:
9929                 case CEE_BLT:
9930                 case CEE_BNE_UN:
9931                 case CEE_BGE_UN:
9932                 case CEE_BGT_UN:
9933                 case CEE_BLE_UN:
9934                 case CEE_BLT_UN:
9935                         CHECK_OPSIZE (5);
9936                         CHECK_STACK (2);
9937                         MONO_INST_NEW (cfg, ins, *ip);
9938                         ip++;
9939                         target = ip + 4 + (gint32)read32(ip);
9940                         ip += 4;
9941
9942                         ADD_BINCOND (NULL);
9943
9944                         sp = stack_start;
9945                         inline_costs += BRANCH_COST;
9946                         break;
9947                 case CEE_SWITCH: {
9948                         MonoInst *src1;
9949                         MonoBasicBlock **targets;
9950                         MonoBasicBlock *default_bblock;
9951                         MonoJumpInfoBBTable *table;
9952                         int offset_reg = alloc_preg (cfg);
9953                         int target_reg = alloc_preg (cfg);
9954                         int table_reg = alloc_preg (cfg);
9955                         int sum_reg = alloc_preg (cfg);
9956                         gboolean use_op_switch;
9957
9958                         CHECK_OPSIZE (5);
9959                         CHECK_STACK (1);
9960                         n = read32 (ip + 1);
9961                         --sp;
9962                         src1 = sp [0];
9963                         if ((src1->type != STACK_I4) && (src1->type != STACK_PTR)) 
9964                                 UNVERIFIED;
9965
9966                         ip += 5;
9967                         CHECK_OPSIZE (n * sizeof (guint32));
9968                         target = ip + n * sizeof (guint32);
9969
9970                         GET_BBLOCK (cfg, default_bblock, target);
9971                         default_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
9972
9973                         targets = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * n);
9974                         for (i = 0; i < n; ++i) {
9975                                 GET_BBLOCK (cfg, tblock, target + (gint32)read32(ip));
9976                                 targets [i] = tblock;
9977                                 targets [i]->flags |= BB_INDIRECT_JUMP_TARGET;
9978                                 ip += 4;
9979                         }
9980
9981                         if (sp != stack_start) {
9982                                 /* 
9983                                  * Link the current bb with the targets as well, so handle_stack_args
9984                                  * will set their in_stack correctly.
9985                                  */
9986                                 link_bblock (cfg, cfg->cbb, default_bblock);
9987                                 for (i = 0; i < n; ++i)
9988                                         link_bblock (cfg, cfg->cbb, targets [i]);
9989
9990                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9991                                 sp = stack_start;
9992                                 CHECK_UNVERIFIABLE (cfg);
9993
9994                                 /* Undo the links */
9995                                 mono_unlink_bblock (cfg, cfg->cbb, default_bblock);
9996                                 for (i = 0; i < n; ++i)
9997                                         mono_unlink_bblock (cfg, cfg->cbb, targets [i]);
9998                         }
9999
10000                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, src1->dreg, n);
10001                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBGE_UN, default_bblock);
10002
10003                         for (i = 0; i < n; ++i)
10004                                 link_bblock (cfg, cfg->cbb, targets [i]);
10005
10006                         table = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
10007                         table->table = targets;
10008                         table->table_size = n;
10009
10010                         use_op_switch = FALSE;
10011 #ifdef TARGET_ARM
10012                         /* ARM implements SWITCH statements differently */
10013                         /* FIXME: Make it use the generic implementation */
10014                         if (!cfg->compile_aot)
10015                                 use_op_switch = TRUE;
10016 #endif
10017
10018                         if (COMPILE_LLVM (cfg))
10019                                 use_op_switch = TRUE;
10020
10021                         cfg->cbb->has_jump_table = 1;
10022
10023                         if (use_op_switch) {
10024                                 MONO_INST_NEW (cfg, ins, OP_SWITCH);
10025                                 ins->sreg1 = src1->dreg;
10026                                 ins->inst_p0 = table;
10027                                 ins->inst_many_bb = targets;
10028                                 ins->klass = GUINT_TO_POINTER (n);
10029                                 MONO_ADD_INS (cfg->cbb, ins);
10030                         } else {
10031                                 if (sizeof (gpointer) == 8)
10032                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 3);
10033                                 else
10034                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 2);
10035
10036 #if SIZEOF_REGISTER == 8
10037                                 /* The upper word might not be zero, and we add it to a 64 bit address later */
10038                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, offset_reg, offset_reg);
10039 #endif
10040
10041                                 if (cfg->compile_aot) {
10042                                         MONO_EMIT_NEW_AOTCONST (cfg, table_reg, table, MONO_PATCH_INFO_SWITCH);
10043                                 } else {
10044                                         MONO_INST_NEW (cfg, ins, OP_JUMP_TABLE);
10045                                         ins->inst_c1 = MONO_PATCH_INFO_SWITCH;
10046                                         ins->inst_p0 = table;
10047                                         ins->dreg = table_reg;
10048                                         MONO_ADD_INS (cfg->cbb, ins);
10049                                 }
10050
10051                                 /* FIXME: Use load_memindex */
10052                                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, table_reg, offset_reg);
10053                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, target_reg, sum_reg, 0);
10054                                 MONO_EMIT_NEW_UNALU (cfg, OP_BR_REG, -1, target_reg);
10055                         }
10056                         start_new_bblock = 1;
10057                         inline_costs += (BRANCH_COST * 2);
10058                         break;
10059                 }
10060                 case CEE_LDIND_I1:
10061                 case CEE_LDIND_U1:
10062                 case CEE_LDIND_I2:
10063                 case CEE_LDIND_U2:
10064                 case CEE_LDIND_I4:
10065                 case CEE_LDIND_U4:
10066                 case CEE_LDIND_I8:
10067                 case CEE_LDIND_I:
10068                 case CEE_LDIND_R4:
10069                 case CEE_LDIND_R8:
10070                 case CEE_LDIND_REF:
10071                         CHECK_STACK (1);
10072                         --sp;
10073
10074                         switch (*ip) {
10075                         case CEE_LDIND_R4:
10076                         case CEE_LDIND_R8:
10077                                 dreg = alloc_freg (cfg);
10078                                 break;
10079                         case CEE_LDIND_I8:
10080                                 dreg = alloc_lreg (cfg);
10081                                 break;
10082                         case CEE_LDIND_REF:
10083                                 dreg = alloc_ireg_ref (cfg);
10084                                 break;
10085                         default:
10086                                 dreg = alloc_preg (cfg);
10087                         }
10088
10089                         NEW_LOAD_MEMBASE (cfg, ins, ldind_to_load_membase (*ip), dreg, sp [0]->dreg, 0);
10090                         ins->type = ldind_type [*ip - CEE_LDIND_I1];
10091                         if (*ip == CEE_LDIND_R4)
10092                                 ins->type = cfg->r4_stack_type;
10093                         ins->flags |= ins_flag;
10094                         MONO_ADD_INS (cfg->cbb, ins);
10095                         *sp++ = ins;
10096                         if (ins_flag & MONO_INST_VOLATILE) {
10097                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10098                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10099                         }
10100                         ins_flag = 0;
10101                         ++ip;
10102                         break;
10103                 case CEE_STIND_REF:
10104                 case CEE_STIND_I1:
10105                 case CEE_STIND_I2:
10106                 case CEE_STIND_I4:
10107                 case CEE_STIND_I8:
10108                 case CEE_STIND_R4:
10109                 case CEE_STIND_R8:
10110                 case CEE_STIND_I:
10111                         CHECK_STACK (2);
10112                         sp -= 2;
10113
10114                         if (ins_flag & MONO_INST_VOLATILE) {
10115                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
10116                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
10117                         }
10118
10119                         NEW_STORE_MEMBASE (cfg, ins, stind_to_store_membase (*ip), sp [0]->dreg, 0, sp [1]->dreg);
10120                         ins->flags |= ins_flag;
10121                         ins_flag = 0;
10122
10123                         MONO_ADD_INS (cfg->cbb, ins);
10124
10125                         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)))
10126                                 emit_write_barrier (cfg, sp [0], sp [1]);
10127
10128                         inline_costs += 1;
10129                         ++ip;
10130                         break;
10131
10132                 case CEE_MUL:
10133                         CHECK_STACK (2);
10134
10135                         MONO_INST_NEW (cfg, ins, (*ip));
10136                         sp -= 2;
10137                         ins->sreg1 = sp [0]->dreg;
10138                         ins->sreg2 = sp [1]->dreg;
10139                         type_from_op (cfg, ins, sp [0], sp [1]);
10140                         CHECK_TYPE (ins);
10141                         ins->dreg = alloc_dreg ((cfg), (ins)->type);
10142
10143                         /* Use the immediate opcodes if possible */
10144                         if ((sp [1]->opcode == OP_ICONST) && mono_arch_is_inst_imm (sp [1]->inst_c0)) {
10145                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
10146                                 if (imm_opcode != -1) {
10147                                         ins->opcode = imm_opcode;
10148                                         ins->inst_p1 = (gpointer)(gssize)(sp [1]->inst_c0);
10149                                         ins->sreg2 = -1;
10150
10151                                         NULLIFY_INS (sp [1]);
10152                                 }
10153                         }
10154
10155                         MONO_ADD_INS ((cfg)->cbb, (ins));
10156
10157                         *sp++ = mono_decompose_opcode (cfg, ins);
10158                         ip++;
10159                         break;
10160                 case CEE_ADD:
10161                 case CEE_SUB:
10162                 case CEE_DIV:
10163                 case CEE_DIV_UN:
10164                 case CEE_REM:
10165                 case CEE_REM_UN:
10166                 case CEE_AND:
10167                 case CEE_OR:
10168                 case CEE_XOR:
10169                 case CEE_SHL:
10170                 case CEE_SHR:
10171                 case CEE_SHR_UN:
10172                         CHECK_STACK (2);
10173
10174                         MONO_INST_NEW (cfg, ins, (*ip));
10175                         sp -= 2;
10176                         ins->sreg1 = sp [0]->dreg;
10177                         ins->sreg2 = sp [1]->dreg;
10178                         type_from_op (cfg, ins, sp [0], sp [1]);
10179                         CHECK_TYPE (ins);
10180                         add_widen_op (cfg, ins, &sp [0], &sp [1]);
10181                         ins->dreg = alloc_dreg ((cfg), (ins)->type);
10182
10183                         /* FIXME: Pass opcode to is_inst_imm */
10184
10185                         /* Use the immediate opcodes if possible */
10186                         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)) {
10187                                 int imm_opcode;
10188
10189                                 imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
10190 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
10191                                 /* Keep emulated opcodes which are optimized away later */
10192                                 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) {
10193                                         imm_opcode = mono_op_to_op_imm (ins->opcode);
10194                                 }
10195 #endif
10196                                 if (imm_opcode != -1) {
10197                                         ins->opcode = imm_opcode;
10198                                         if (sp [1]->opcode == OP_I8CONST) {
10199 #if SIZEOF_REGISTER == 8
10200                                                 ins->inst_imm = sp [1]->inst_l;
10201 #else
10202                                                 ins->inst_ls_word = sp [1]->inst_ls_word;
10203                                                 ins->inst_ms_word = sp [1]->inst_ms_word;
10204 #endif
10205                                         }
10206                                         else
10207                                                 ins->inst_imm = (gssize)(sp [1]->inst_c0);
10208                                         ins->sreg2 = -1;
10209
10210                                         /* Might be followed by an instruction added by add_widen_op */
10211                                         if (sp [1]->next == NULL)
10212                                                 NULLIFY_INS (sp [1]);
10213                                 }
10214                         }
10215                         MONO_ADD_INS ((cfg)->cbb, (ins));
10216
10217                         *sp++ = mono_decompose_opcode (cfg, ins);
10218                         ip++;
10219                         break;
10220                 case CEE_NEG:
10221                 case CEE_NOT:
10222                 case CEE_CONV_I1:
10223                 case CEE_CONV_I2:
10224                 case CEE_CONV_I4:
10225                 case CEE_CONV_R4:
10226                 case CEE_CONV_R8:
10227                 case CEE_CONV_U4:
10228                 case CEE_CONV_I8:
10229                 case CEE_CONV_U8:
10230                 case CEE_CONV_OVF_I8:
10231                 case CEE_CONV_OVF_U8:
10232                 case CEE_CONV_R_UN:
10233                         CHECK_STACK (1);
10234
10235                         /* Special case this earlier so we have long constants in the IR */
10236                         if ((((*ip) == CEE_CONV_I8) || ((*ip) == CEE_CONV_U8)) && (sp [-1]->opcode == OP_ICONST)) {
10237                                 int data = sp [-1]->inst_c0;
10238                                 sp [-1]->opcode = OP_I8CONST;
10239                                 sp [-1]->type = STACK_I8;
10240 #if SIZEOF_REGISTER == 8
10241                                 if ((*ip) == CEE_CONV_U8)
10242                                         sp [-1]->inst_c0 = (guint32)data;
10243                                 else
10244                                         sp [-1]->inst_c0 = data;
10245 #else
10246                                 sp [-1]->inst_ls_word = data;
10247                                 if ((*ip) == CEE_CONV_U8)
10248                                         sp [-1]->inst_ms_word = 0;
10249                                 else
10250                                         sp [-1]->inst_ms_word = (data < 0) ? -1 : 0;
10251 #endif
10252                                 sp [-1]->dreg = alloc_dreg (cfg, STACK_I8);
10253                         }
10254                         else {
10255                                 ADD_UNOP (*ip);
10256                         }
10257                         ip++;
10258                         break;
10259                 case CEE_CONV_OVF_I4:
10260                 case CEE_CONV_OVF_I1:
10261                 case CEE_CONV_OVF_I2:
10262                 case CEE_CONV_OVF_I:
10263                 case CEE_CONV_OVF_U:
10264                         CHECK_STACK (1);
10265
10266                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
10267                                 ADD_UNOP (CEE_CONV_OVF_I8);
10268                                 ADD_UNOP (*ip);
10269                         } else {
10270                                 ADD_UNOP (*ip);
10271                         }
10272                         ip++;
10273                         break;
10274                 case CEE_CONV_OVF_U1:
10275                 case CEE_CONV_OVF_U2:
10276                 case CEE_CONV_OVF_U4:
10277                         CHECK_STACK (1);
10278
10279                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
10280                                 ADD_UNOP (CEE_CONV_OVF_U8);
10281                                 ADD_UNOP (*ip);
10282                         } else {
10283                                 ADD_UNOP (*ip);
10284                         }
10285                         ip++;
10286                         break;
10287                 case CEE_CONV_OVF_I1_UN:
10288                 case CEE_CONV_OVF_I2_UN:
10289                 case CEE_CONV_OVF_I4_UN:
10290                 case CEE_CONV_OVF_I8_UN:
10291                 case CEE_CONV_OVF_U1_UN:
10292                 case CEE_CONV_OVF_U2_UN:
10293                 case CEE_CONV_OVF_U4_UN:
10294                 case CEE_CONV_OVF_U8_UN:
10295                 case CEE_CONV_OVF_I_UN:
10296                 case CEE_CONV_OVF_U_UN:
10297                 case CEE_CONV_U2:
10298                 case CEE_CONV_U1:
10299                 case CEE_CONV_I:
10300                 case CEE_CONV_U:
10301                         CHECK_STACK (1);
10302                         ADD_UNOP (*ip);
10303                         CHECK_CFG_EXCEPTION;
10304                         ip++;
10305                         break;
10306                 case CEE_ADD_OVF:
10307                 case CEE_ADD_OVF_UN:
10308                 case CEE_MUL_OVF:
10309                 case CEE_MUL_OVF_UN:
10310                 case CEE_SUB_OVF:
10311                 case CEE_SUB_OVF_UN:
10312                         CHECK_STACK (2);
10313                         ADD_BINOP (*ip);
10314                         ip++;
10315                         break;
10316                 case CEE_CPOBJ:
10317                         GSHAREDVT_FAILURE (*ip);
10318                         CHECK_OPSIZE (5);
10319                         CHECK_STACK (2);
10320                         token = read32 (ip + 1);
10321                         klass = mini_get_class (method, token, generic_context);
10322                         CHECK_TYPELOAD (klass);
10323                         sp -= 2;
10324                         if (generic_class_is_reference_type (cfg, klass)) {
10325                                 MonoInst *store, *load;
10326                                 int dreg = alloc_ireg_ref (cfg);
10327
10328                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, dreg, sp [1]->dreg, 0);
10329                                 load->flags |= ins_flag;
10330                                 MONO_ADD_INS (cfg->cbb, load);
10331
10332                                 NEW_STORE_MEMBASE (cfg, store, OP_STORE_MEMBASE_REG, sp [0]->dreg, 0, dreg);
10333                                 store->flags |= ins_flag;
10334                                 MONO_ADD_INS (cfg->cbb, store);
10335
10336                                 if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER)
10337                                         emit_write_barrier (cfg, sp [0], sp [1]);
10338                         } else {
10339                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
10340                         }
10341                         ins_flag = 0;
10342                         ip += 5;
10343                         break;
10344                 case CEE_LDOBJ: {
10345                         int loc_index = -1;
10346                         int stloc_len = 0;
10347
10348                         CHECK_OPSIZE (5);
10349                         CHECK_STACK (1);
10350                         --sp;
10351                         token = read32 (ip + 1);
10352                         klass = mini_get_class (method, token, generic_context);
10353                         CHECK_TYPELOAD (klass);
10354
10355                         /* Optimize the common ldobj+stloc combination */
10356                         switch (ip [5]) {
10357                         case CEE_STLOC_S:
10358                                 loc_index = ip [6];
10359                                 stloc_len = 2;
10360                                 break;
10361                         case CEE_STLOC_0:
10362                         case CEE_STLOC_1:
10363                         case CEE_STLOC_2:
10364                         case CEE_STLOC_3:
10365                                 loc_index = ip [5] - CEE_STLOC_0;
10366                                 stloc_len = 1;
10367                                 break;
10368                         default:
10369                                 break;
10370                         }
10371
10372                         if ((loc_index != -1) && ip_in_bb (cfg, cfg->cbb, ip + 5)) {
10373                                 CHECK_LOCAL (loc_index);
10374
10375                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10376                                 ins->dreg = cfg->locals [loc_index]->dreg;
10377                                 ins->flags |= ins_flag;
10378                                 ip += 5;
10379                                 ip += stloc_len;
10380                                 if (ins_flag & MONO_INST_VOLATILE) {
10381                                         /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10382                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10383                                 }
10384                                 ins_flag = 0;
10385                                 break;
10386                         }
10387
10388                         /* Optimize the ldobj+stobj combination */
10389                         /* The reference case ends up being a load+store anyway */
10390                         /* Skip this if the operation is volatile. */
10391                         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)) {
10392                                 CHECK_STACK (1);
10393
10394                                 sp --;
10395
10396                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
10397
10398                                 ip += 5 + 5;
10399                                 ins_flag = 0;
10400                                 break;
10401                         }
10402
10403                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10404                         ins->flags |= ins_flag;
10405                         *sp++ = ins;
10406
10407                         if (ins_flag & MONO_INST_VOLATILE) {
10408                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10409                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10410                         }
10411
10412                         ip += 5;
10413                         ins_flag = 0;
10414                         inline_costs += 1;
10415                         break;
10416                 }
10417                 case CEE_LDSTR:
10418                         CHECK_STACK_OVF (1);
10419                         CHECK_OPSIZE (5);
10420                         n = read32 (ip + 1);
10421
10422                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
10423                                 EMIT_NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
10424                                 ins->type = STACK_OBJ;
10425                                 *sp = ins;
10426                         }
10427                         else if (method->wrapper_type != MONO_WRAPPER_NONE) {
10428                                 MonoInst *iargs [1];
10429                                 char *str = mono_method_get_wrapper_data (method, n);
10430
10431                                 if (cfg->compile_aot)
10432                                         EMIT_NEW_LDSTRLITCONST (cfg, iargs [0], str);
10433                                 else
10434                                         EMIT_NEW_PCONST (cfg, iargs [0], str);
10435                                 *sp = mono_emit_jit_icall (cfg, mono_string_new_wrapper, iargs);
10436                         } else {
10437                                 if (cfg->opt & MONO_OPT_SHARED) {
10438                                         MonoInst *iargs [3];
10439
10440                                         if (cfg->compile_aot) {
10441                                                 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
10442                                         }
10443                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10444                                         EMIT_NEW_IMAGECONST (cfg, iargs [1], image);
10445                                         EMIT_NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
10446                                         *sp = mono_emit_jit_icall (cfg, mono_ldstr, iargs);
10447                                         mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
10448                                 } else {
10449                                         if (cfg->cbb->out_of_line) {
10450                                                 MonoInst *iargs [2];
10451
10452                                                 if (image == mono_defaults.corlib) {
10453                                                         /* 
10454                                                          * Avoid relocations in AOT and save some space by using a 
10455                                                          * version of helper_ldstr specialized to mscorlib.
10456                                                          */
10457                                                         EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (n));
10458                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr_mscorlib, iargs);
10459                                                 } else {
10460                                                         /* Avoid creating the string object */
10461                                                         EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
10462                                                         EMIT_NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n));
10463                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr, iargs);
10464                                                 }
10465                                         } 
10466                                         else
10467                                         if (cfg->compile_aot) {
10468                                                 NEW_LDSTRCONST (cfg, ins, image, n);
10469                                                 *sp = ins;
10470                                                 MONO_ADD_INS (cfg->cbb, ins);
10471                                         } 
10472                                         else {
10473                                                 NEW_PCONST (cfg, ins, NULL);
10474                                                 ins->type = STACK_OBJ;
10475                                                 ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
10476                                                 if (!ins->inst_p0)
10477                                                         OUT_OF_MEMORY_FAILURE;
10478
10479                                                 *sp = ins;
10480                                                 MONO_ADD_INS (cfg->cbb, ins);
10481                                         }
10482                                 }
10483                         }
10484
10485                         sp++;
10486                         ip += 5;
10487                         break;
10488                 case CEE_NEWOBJ: {
10489                         MonoInst *iargs [2];
10490                         MonoMethodSignature *fsig;
10491                         MonoInst this_ins;
10492                         MonoInst *alloc;
10493                         MonoInst *vtable_arg = NULL;
10494
10495                         CHECK_OPSIZE (5);
10496                         token = read32 (ip + 1);
10497                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
10498                         if (!cmethod || mono_loader_get_last_error ())
10499                                 LOAD_ERROR;
10500                         fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
10501                         CHECK_CFG_ERROR;
10502
10503                         mono_save_token_info (cfg, image, token, cmethod);
10504
10505                         if (!mono_class_init (cmethod->klass))
10506                                 TYPE_LOAD_ERROR (cmethod->klass);
10507
10508                         context_used = mini_method_check_context_used (cfg, cmethod);
10509
10510                         if (mono_security_core_clr_enabled ())
10511                                 ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
10512
10513                         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)) {
10514                                 emit_class_init (cfg, cmethod->klass);
10515                                 CHECK_TYPELOAD (cmethod->klass);
10516                         }
10517
10518                         /*
10519                         if (cfg->gsharedvt) {
10520                                 if (mini_is_gsharedvt_variable_signature (sig))
10521                                         GSHAREDVT_FAILURE (*ip);
10522                         }
10523                         */
10524
10525                         n = fsig->param_count;
10526                         CHECK_STACK (n);
10527
10528                         /* 
10529                          * Generate smaller code for the common newobj <exception> instruction in
10530                          * argument checking code.
10531                          */
10532                         if (cfg->cbb->out_of_line && cmethod->klass->image == mono_defaults.corlib &&
10533                                 is_exception_class (cmethod->klass) && n <= 2 &&
10534                                 ((n < 1) || (!fsig->params [0]->byref && fsig->params [0]->type == MONO_TYPE_STRING)) && 
10535                                 ((n < 2) || (!fsig->params [1]->byref && fsig->params [1]->type == MONO_TYPE_STRING))) {
10536                                 MonoInst *iargs [3];
10537
10538                                 sp -= n;
10539
10540                                 EMIT_NEW_ICONST (cfg, iargs [0], cmethod->klass->type_token);
10541                                 switch (n) {
10542                                 case 0:
10543                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_0, iargs);
10544                                         break;
10545                                 case 1:
10546                                         iargs [1] = sp [0];
10547                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_1, iargs);
10548                                         break;
10549                                 case 2:
10550                                         iargs [1] = sp [0];
10551                                         iargs [2] = sp [1];
10552                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_2, iargs);
10553                                         break;
10554                                 default:
10555                                         g_assert_not_reached ();
10556                                 }
10557
10558                                 ip += 5;
10559                                 inline_costs += 5;
10560                                 break;
10561                         }
10562
10563                         /* move the args to allow room for 'this' in the first position */
10564                         while (n--) {
10565                                 --sp;
10566                                 sp [1] = sp [0];
10567                         }
10568
10569                         /* check_call_signature () requires sp[0] to be set */
10570                         this_ins.type = STACK_OBJ;
10571                         sp [0] = &this_ins;
10572                         if (check_call_signature (cfg, fsig, sp))
10573                                 UNVERIFIED;
10574
10575                         iargs [0] = NULL;
10576
10577                         if (mini_class_is_system_array (cmethod->klass)) {
10578                                 *sp = emit_get_rgctx_method (cfg, context_used,
10579                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
10580
10581                                 /* Avoid varargs in the common case */
10582                                 if (fsig->param_count == 1)
10583                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_1, sp);
10584                                 else if (fsig->param_count == 2)
10585                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_2, sp);
10586                                 else if (fsig->param_count == 3)
10587                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_3, sp);
10588                                 else if (fsig->param_count == 4)
10589                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_4, sp);
10590                                 else
10591                                         alloc = handle_array_new (cfg, fsig->param_count, sp, ip);
10592                         } else if (cmethod->string_ctor) {
10593                                 g_assert (!context_used);
10594                                 g_assert (!vtable_arg);
10595                                 /* we simply pass a null pointer */
10596                                 EMIT_NEW_PCONST (cfg, *sp, NULL); 
10597                                 /* now call the string ctor */
10598                                 alloc = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, NULL, NULL, NULL);
10599                         } else {
10600                                 if (cmethod->klass->valuetype) {
10601                                         iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
10602                                         emit_init_rvar (cfg, iargs [0]->dreg, &cmethod->klass->byval_arg);
10603                                         EMIT_NEW_TEMPLOADA (cfg, *sp, iargs [0]->inst_c0);
10604
10605                                         alloc = NULL;
10606
10607                                         /* 
10608                                          * The code generated by mini_emit_virtual_call () expects
10609                                          * iargs [0] to be a boxed instance, but luckily the vcall
10610                                          * will be transformed into a normal call there.
10611                                          */
10612                                 } else if (context_used) {
10613                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, context_used);
10614                                         *sp = alloc;
10615                                 } else {
10616                                         MonoVTable *vtable = NULL;
10617
10618                                         if (!cfg->compile_aot)
10619                                                 vtable = mono_class_vtable (cfg->domain, cmethod->klass);
10620                                         CHECK_TYPELOAD (cmethod->klass);
10621
10622                                         /*
10623                                          * TypeInitializationExceptions thrown from the mono_runtime_class_init
10624                                          * call in mono_jit_runtime_invoke () can abort the finalizer thread.
10625                                          * As a workaround, we call class cctors before allocating objects.
10626                                          */
10627                                         if (mini_field_access_needs_cctor_run (cfg, method, cmethod->klass, vtable) && !(g_slist_find (class_inits, cmethod->klass))) {
10628                                                 emit_class_init (cfg, cmethod->klass);
10629                                                 if (cfg->verbose_level > 2)
10630                                                         printf ("class %s.%s needs init call for ctor\n", cmethod->klass->name_space, cmethod->klass->name);
10631                                                 class_inits = g_slist_prepend (class_inits, cmethod->klass);
10632                                         }
10633
10634                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, 0);
10635                                         *sp = alloc;
10636                                 }
10637                                 CHECK_CFG_EXCEPTION; /*for handle_alloc*/
10638
10639                                 if (alloc)
10640                                         MONO_EMIT_NEW_UNALU (cfg, OP_NOT_NULL, -1, alloc->dreg);
10641
10642                                 /* Now call the actual ctor */
10643                                 handle_ctor_call (cfg, cmethod, fsig, context_used, sp, ip, &inline_costs);
10644                                 CHECK_CFG_EXCEPTION;
10645                         }
10646
10647                         if (alloc == NULL) {
10648                                 /* Valuetype */
10649                                 EMIT_NEW_TEMPLOAD (cfg, ins, iargs [0]->inst_c0);
10650                                 type_to_eval_stack_type (cfg, &ins->klass->byval_arg, ins);
10651                                 *sp++= ins;
10652                         } else {
10653                                 *sp++ = alloc;
10654                         }
10655                         
10656                         ip += 5;
10657                         inline_costs += 5;
10658                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip - header->code)))
10659                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
10660                         break;
10661                 }
10662                 case CEE_CASTCLASS:
10663                         CHECK_STACK (1);
10664                         --sp;
10665                         CHECK_OPSIZE (5);
10666                         token = read32 (ip + 1);
10667                         klass = mini_get_class (method, token, generic_context);
10668                         CHECK_TYPELOAD (klass);
10669                         if (sp [0]->type != STACK_OBJ)
10670                                 UNVERIFIED;
10671
10672                         ins = handle_castclass (cfg, klass, *sp, ip, &inline_costs);
10673                         CHECK_CFG_EXCEPTION;
10674
10675                         *sp ++ = ins;
10676                         ip += 5;
10677                         break;
10678                 case CEE_ISINST: {
10679                         CHECK_STACK (1);
10680                         --sp;
10681                         CHECK_OPSIZE (5);
10682                         token = read32 (ip + 1);
10683                         klass = mini_get_class (method, token, generic_context);
10684                         CHECK_TYPELOAD (klass);
10685                         if (sp [0]->type != STACK_OBJ)
10686                                 UNVERIFIED;
10687  
10688                         context_used = mini_class_check_context_used (cfg, klass);
10689
10690                         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
10691                                 MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
10692                                 MonoInst *args [3];
10693                                 int idx;
10694
10695                                 /* obj */
10696                                 args [0] = *sp;
10697
10698                                 /* klass */
10699                                 EMIT_NEW_CLASSCONST (cfg, args [1], klass);
10700
10701                                 /* inline cache*/
10702                                 if (cfg->compile_aot) {
10703                                         idx = get_castclass_cache_idx (cfg);
10704                                         EMIT_NEW_AOTCONST (cfg, args [2], MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
10705                                 } else {
10706                                         EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));
10707                                 }
10708
10709                                 *sp++ = mono_emit_method_call (cfg, mono_isinst, args, NULL);
10710                                 ip += 5;
10711                                 inline_costs += 2;
10712                         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
10713                                 MonoMethod *mono_isinst;
10714                                 MonoInst *iargs [1];
10715                                 int costs;
10716
10717                                 mono_isinst = mono_marshal_get_isinst (klass); 
10718                                 iargs [0] = sp [0];
10719
10720                                 costs = inline_method (cfg, mono_isinst, mono_method_signature (mono_isinst), 
10721                                                                            iargs, ip, cfg->real_offset, TRUE);
10722                                 CHECK_CFG_EXCEPTION;
10723                                 g_assert (costs > 0);
10724                                 
10725                                 ip += 5;
10726                                 cfg->real_offset += 5;
10727
10728                                 *sp++= iargs [0];
10729
10730                                 inline_costs += costs;
10731                         }
10732                         else {
10733                                 ins = handle_isinst (cfg, klass, *sp, context_used);
10734                                 CHECK_CFG_EXCEPTION;
10735                                 *sp ++ = ins;
10736                                 ip += 5;
10737                         }
10738                         break;
10739                 }
10740                 case CEE_UNBOX_ANY: {
10741                         MonoInst *res, *addr;
10742
10743                         CHECK_STACK (1);
10744                         --sp;
10745                         CHECK_OPSIZE (5);
10746                         token = read32 (ip + 1);
10747                         klass = mini_get_class (method, token, generic_context);
10748                         CHECK_TYPELOAD (klass);
10749
10750                         mono_save_token_info (cfg, image, token, klass);
10751
10752                         context_used = mini_class_check_context_used (cfg, klass);
10753
10754                         if (mini_is_gsharedvt_klass (klass)) {
10755                                 res = handle_unbox_gsharedvt (cfg, klass, *sp);
10756                                 inline_costs += 2;
10757                         } else if (generic_class_is_reference_type (cfg, klass)) {
10758                                 res = handle_castclass (cfg, klass, *sp, ip, &inline_costs);
10759                                 CHECK_CFG_EXCEPTION;
10760                         } else if (mono_class_is_nullable (klass)) {
10761                                 res = handle_unbox_nullable (cfg, *sp, klass, context_used);
10762                         } else {
10763                                 addr = handle_unbox (cfg, klass, sp, context_used);
10764                                 /* LDOBJ */
10765                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
10766                                 res = ins;
10767                                 inline_costs += 2;
10768                         }
10769
10770                         *sp ++ = res;
10771                         ip += 5;
10772                         break;
10773                 }
10774                 case CEE_BOX: {
10775                         MonoInst *val;
10776                         MonoClass *enum_class;
10777                         MonoMethod *has_flag;
10778
10779                         CHECK_STACK (1);
10780                         --sp;
10781                         val = *sp;
10782                         CHECK_OPSIZE (5);
10783                         token = read32 (ip + 1);
10784                         klass = mini_get_class (method, token, generic_context);
10785                         CHECK_TYPELOAD (klass);
10786
10787                         mono_save_token_info (cfg, image, token, klass);
10788
10789                         context_used = mini_class_check_context_used (cfg, klass);
10790
10791                         if (generic_class_is_reference_type (cfg, klass)) {
10792                                 *sp++ = val;
10793                                 ip += 5;
10794                                 break;
10795                         }
10796
10797                         if (klass == mono_defaults.void_class)
10798                                 UNVERIFIED;
10799                         if (target_type_is_incompatible (cfg, &klass->byval_arg, *sp))
10800                                 UNVERIFIED;
10801                         /* frequent check in generic code: box (struct), brtrue */
10802
10803                         /*
10804                          * Look for:
10805                          *
10806                          *   <push int/long ptr>
10807                          *   <push int/long>
10808                          *   box MyFlags
10809                          *   constrained. MyFlags
10810                          *   callvirt instace bool class [mscorlib] System.Enum::HasFlag (class [mscorlib] System.Enum)
10811                          *
10812                          * If we find this sequence and the operand types on box and constrained
10813                          * are equal, we can emit a specialized instruction sequence instead of
10814                          * the very slow HasFlag () call.
10815                          */
10816                         if ((cfg->opt & MONO_OPT_INTRINS) &&
10817                             /* Cheap checks first. */
10818                             ip + 5 + 6 + 5 < end &&
10819                             ip [5] == CEE_PREFIX1 &&
10820                             ip [6] == CEE_CONSTRAINED_ &&
10821                             ip [11] == CEE_CALLVIRT &&
10822                             ip_in_bb (cfg, cfg->cbb, ip + 5 + 6 + 5) &&
10823                             mono_class_is_enum (klass) &&
10824                             (enum_class = mini_get_class (method, read32 (ip + 7), generic_context)) &&
10825                             (has_flag = mini_get_method (cfg, method, read32 (ip + 12), NULL, generic_context)) &&
10826                             has_flag->klass == mono_defaults.enum_class &&
10827                             !strcmp (has_flag->name, "HasFlag") &&
10828                             has_flag->signature->hasthis &&
10829                             has_flag->signature->param_count == 1) {
10830                                 CHECK_TYPELOAD (enum_class);
10831
10832                                 if (enum_class == klass) {
10833                                         MonoInst *enum_this, *enum_flag;
10834
10835                                         ip += 5 + 6 + 5;
10836                                         --sp;
10837
10838                                         enum_this = sp [0];
10839                                         enum_flag = sp [1];
10840
10841                                         *sp++ = handle_enum_has_flag (cfg, klass, enum_this, enum_flag);
10842                                         break;
10843                                 }
10844                         }
10845
10846                         // FIXME: LLVM can't handle the inconsistent bb linking
10847                         if (!mono_class_is_nullable (klass) &&
10848                                 !mini_is_gsharedvt_klass (klass) &&
10849                                 ip + 5 < end && ip_in_bb (cfg, cfg->cbb, ip + 5) &&
10850                                 (ip [5] == CEE_BRTRUE || 
10851                                  ip [5] == CEE_BRTRUE_S ||
10852                                  ip [5] == CEE_BRFALSE ||
10853                                  ip [5] == CEE_BRFALSE_S)) {
10854                                 gboolean is_true = ip [5] == CEE_BRTRUE || ip [5] == CEE_BRTRUE_S;
10855                                 int dreg;
10856                                 MonoBasicBlock *true_bb, *false_bb;
10857
10858                                 ip += 5;
10859
10860                                 if (cfg->verbose_level > 3) {
10861                                         printf ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
10862                                         printf ("<box+brtrue opt>\n");
10863                                 }
10864
10865                                 switch (*ip) {
10866                                 case CEE_BRTRUE_S:
10867                                 case CEE_BRFALSE_S:
10868                                         CHECK_OPSIZE (2);
10869                                         ip++;
10870                                         target = ip + 1 + (signed char)(*ip);
10871                                         ip++;
10872                                         break;
10873                                 case CEE_BRTRUE:
10874                                 case CEE_BRFALSE:
10875                                         CHECK_OPSIZE (5);
10876                                         ip++;
10877                                         target = ip + 4 + (gint)(read32 (ip));
10878                                         ip += 4;
10879                                         break;
10880                                 default:
10881                                         g_assert_not_reached ();
10882                                 }
10883
10884                                 /* 
10885                                  * We need to link both bblocks, since it is needed for handling stack
10886                                  * arguments correctly (See test_0_box_brtrue_opt_regress_81102).
10887                                  * Branching to only one of them would lead to inconsistencies, so
10888                                  * generate an ICONST+BRTRUE, the branch opts will get rid of them.
10889                                  */
10890                                 GET_BBLOCK (cfg, true_bb, target);
10891                                 GET_BBLOCK (cfg, false_bb, ip);
10892
10893                                 mono_link_bblock (cfg, cfg->cbb, true_bb);
10894                                 mono_link_bblock (cfg, cfg->cbb, false_bb);
10895
10896                                 if (sp != stack_start) {
10897                                         handle_stack_args (cfg, stack_start, sp - stack_start);
10898                                         sp = stack_start;
10899                                         CHECK_UNVERIFIABLE (cfg);
10900                                 }
10901
10902                                 if (COMPILE_LLVM (cfg)) {
10903                                         dreg = alloc_ireg (cfg);
10904                                         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
10905                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, dreg, is_true ? 0 : 1);
10906
10907                                         MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, OP_IBEQ, true_bb, false_bb);
10908                                 } else {
10909                                         /* The JIT can't eliminate the iconst+compare */
10910                                         MONO_INST_NEW (cfg, ins, OP_BR);
10911                                         ins->inst_target_bb = is_true ? true_bb : false_bb;
10912                                         MONO_ADD_INS (cfg->cbb, ins);
10913                                 }
10914
10915                                 start_new_bblock = 1;
10916                                 break;
10917                         }
10918
10919                         *sp++ = handle_box (cfg, val, klass, context_used);
10920
10921                         CHECK_CFG_EXCEPTION;
10922                         ip += 5;
10923                         inline_costs += 1;
10924                         break;
10925                 }
10926                 case CEE_UNBOX: {
10927                         CHECK_STACK (1);
10928                         --sp;
10929                         CHECK_OPSIZE (5);
10930                         token = read32 (ip + 1);
10931                         klass = mini_get_class (method, token, generic_context);
10932                         CHECK_TYPELOAD (klass);
10933
10934                         mono_save_token_info (cfg, image, token, klass);
10935
10936                         context_used = mini_class_check_context_used (cfg, klass);
10937
10938                         if (mono_class_is_nullable (klass)) {
10939                                 MonoInst *val;
10940
10941                                 val = handle_unbox_nullable (cfg, *sp, klass, context_used);
10942                                 EMIT_NEW_VARLOADA (cfg, ins, get_vreg_to_inst (cfg, val->dreg), &val->klass->byval_arg);
10943
10944                                 *sp++= ins;
10945                         } else {
10946                                 ins = handle_unbox (cfg, klass, sp, context_used);
10947                                 *sp++ = ins;
10948                         }
10949                         ip += 5;
10950                         inline_costs += 2;
10951                         break;
10952                 }
10953                 case CEE_LDFLD:
10954                 case CEE_LDFLDA:
10955                 case CEE_STFLD:
10956                 case CEE_LDSFLD:
10957                 case CEE_LDSFLDA:
10958                 case CEE_STSFLD: {
10959                         MonoClassField *field;
10960 #ifndef DISABLE_REMOTING
10961                         int costs;
10962 #endif
10963                         guint foffset;
10964                         gboolean is_instance;
10965                         int op;
10966                         gpointer addr = NULL;
10967                         gboolean is_special_static;
10968                         MonoType *ftype;
10969                         MonoInst *store_val = NULL;
10970                         MonoInst *thread_ins;
10971
10972                         op = *ip;
10973                         is_instance = (op == CEE_LDFLD || op == CEE_LDFLDA || op == CEE_STFLD);
10974                         if (is_instance) {
10975                                 if (op == CEE_STFLD) {
10976                                         CHECK_STACK (2);
10977                                         sp -= 2;
10978                                         store_val = sp [1];
10979                                 } else {
10980                                         CHECK_STACK (1);
10981                                         --sp;
10982                                 }
10983                                 if (sp [0]->type == STACK_I4 || sp [0]->type == STACK_I8 || sp [0]->type == STACK_R8)
10984                                         UNVERIFIED;
10985                                 if (*ip != CEE_LDFLD && sp [0]->type == STACK_VTYPE)
10986                                         UNVERIFIED;
10987                         } else {
10988                                 if (op == CEE_STSFLD) {
10989                                         CHECK_STACK (1);
10990                                         sp--;
10991                                         store_val = sp [0];
10992                                 }
10993                         }
10994
10995                         CHECK_OPSIZE (5);
10996                         token = read32 (ip + 1);
10997                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
10998                                 field = mono_method_get_wrapper_data (method, token);
10999                                 klass = field->parent;
11000                         }
11001                         else {
11002                                 field = mono_field_from_token_checked (image, token, &klass, generic_context, &cfg->error);
11003                                 CHECK_CFG_ERROR;
11004                         }
11005                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
11006                                 FIELD_ACCESS_FAILURE (method, field);
11007                         mono_class_init (klass);
11008
11009                         /* if the class is Critical then transparent code cannot access it's fields */
11010                         if (!is_instance && mono_security_core_clr_enabled ())
11011                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
11012
11013                         /* XXX this is technically required but, so far (SL2), no [SecurityCritical] types (not many exists) have
11014                            any visible *instance* field  (in fact there's a single case for a static field in Marshal) XXX
11015                         if (mono_security_core_clr_enabled ())
11016                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
11017                         */
11018
11019                         ftype = mono_field_get_type (field);
11020
11021                         /*
11022                          * LDFLD etc. is usable on static fields as well, so convert those cases to
11023                          * the static case.
11024                          */
11025                         if (is_instance && ftype->attrs & FIELD_ATTRIBUTE_STATIC) {
11026                                 switch (op) {
11027                                 case CEE_LDFLD:
11028                                         op = CEE_LDSFLD;
11029                                         break;
11030                                 case CEE_STFLD:
11031                                         op = CEE_STSFLD;
11032                                         break;
11033                                 case CEE_LDFLDA:
11034                                         op = CEE_LDSFLDA;
11035                                         break;
11036                                 default:
11037                                         g_assert_not_reached ();
11038                                 }
11039                                 is_instance = FALSE;
11040                         }
11041
11042                         context_used = mini_class_check_context_used (cfg, klass);
11043
11044                         /* INSTANCE CASE */
11045
11046                         foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
11047                         if (op == CEE_STFLD) {
11048                                 if (target_type_is_incompatible (cfg, field->type, sp [1]))
11049                                         UNVERIFIED;
11050 #ifndef DISABLE_REMOTING
11051                                 if ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class) {
11052                                         MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type); 
11053                                         MonoInst *iargs [5];
11054
11055                                         GSHAREDVT_FAILURE (op);
11056
11057                                         iargs [0] = sp [0];
11058                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11059                                         EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
11060                                         EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : 
11061                                                     field->offset);
11062                                         iargs [4] = sp [1];
11063
11064                                         if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
11065                                                 costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), 
11066                                                                                            iargs, ip, cfg->real_offset, TRUE);
11067                                                 CHECK_CFG_EXCEPTION;
11068                                                 g_assert (costs > 0);
11069                                                       
11070                                                 cfg->real_offset += 5;
11071
11072                                                 inline_costs += costs;
11073                                         } else {
11074                                                 mono_emit_method_call (cfg, stfld_wrapper, iargs, NULL);
11075                                         }
11076                                 } else
11077 #endif
11078                                 {
11079                                         MonoInst *store;
11080
11081                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
11082
11083                                         if (mini_is_gsharedvt_klass (klass)) {
11084                                                 MonoInst *offset_ins;
11085
11086                                                 context_used = mini_class_check_context_used (cfg, klass);
11087
11088                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11089                                                 dreg = alloc_ireg_mp (cfg);
11090                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11091                                                 /* The decomposition will call mini_emit_stobj () which will emit a wbarrier if needed */
11092                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, dreg, 0, sp [1]->dreg);
11093                                         } else {
11094                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, sp [0]->dreg, foffset, sp [1]->dreg);
11095                                         }
11096                                         if (sp [0]->opcode != OP_LDADDR)
11097                                                 store->flags |= MONO_INST_FAULT;
11098
11099                                 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)) {
11100                                         /* insert call to write barrier */
11101                                         MonoInst *ptr;
11102                                         int dreg;
11103
11104                                         dreg = alloc_ireg_mp (cfg);
11105                                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
11106                                         emit_write_barrier (cfg, ptr, sp [1]);
11107                                 }
11108
11109                                         store->flags |= ins_flag;
11110                                 }
11111                                 ins_flag = 0;
11112                                 ip += 5;
11113                                 break;
11114                         }
11115
11116 #ifndef DISABLE_REMOTING
11117                         if (is_instance && ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class)) {
11118                                 MonoMethod *wrapper = (op == CEE_LDFLDA) ? mono_marshal_get_ldflda_wrapper (field->type) : mono_marshal_get_ldfld_wrapper (field->type); 
11119                                 MonoInst *iargs [4];
11120
11121                                 GSHAREDVT_FAILURE (op);
11122
11123                                 iargs [0] = sp [0];
11124                                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11125                                 EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
11126                                 EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
11127                                 if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
11128                                         costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), 
11129                                                                                    iargs, ip, cfg->real_offset, TRUE);
11130                                         CHECK_CFG_EXCEPTION;
11131                                         g_assert (costs > 0);
11132                                                       
11133                                         cfg->real_offset += 5;
11134
11135                                         *sp++ = iargs [0];
11136
11137                                         inline_costs += costs;
11138                                 } else {
11139                                         ins = mono_emit_method_call (cfg, wrapper, iargs, NULL);
11140                                         *sp++ = ins;
11141                                 }
11142                         } else 
11143 #endif
11144                         if (is_instance) {
11145                                 if (sp [0]->type == STACK_VTYPE) {
11146                                         MonoInst *var;
11147
11148                                         /* Have to compute the address of the variable */
11149
11150                                         var = get_vreg_to_inst (cfg, sp [0]->dreg);
11151                                         if (!var)
11152                                                 var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, sp [0]->dreg);
11153                                         else
11154                                                 g_assert (var->klass == klass);
11155                                         
11156                                         EMIT_NEW_VARLOADA (cfg, ins, var, &var->klass->byval_arg);
11157                                         sp [0] = ins;
11158                                 }
11159
11160                                 if (op == CEE_LDFLDA) {
11161                                         if (sp [0]->type == STACK_OBJ) {
11162                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
11163                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "NullReferenceException");
11164                                         }
11165
11166                                         dreg = alloc_ireg_mp (cfg);
11167
11168                                         if (mini_is_gsharedvt_klass (klass)) {
11169                                                 MonoInst *offset_ins;
11170
11171                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11172                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11173                                         } else {
11174                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
11175                                         }
11176                                         ins->klass = mono_class_from_mono_type (field->type);
11177                                         ins->type = STACK_MP;
11178                                         *sp++ = ins;
11179                                 } else {
11180                                         MonoInst *load;
11181
11182                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
11183
11184                                         if (mini_is_gsharedvt_klass (klass)) {
11185                                                 MonoInst *offset_ins;
11186
11187                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11188                                                 dreg = alloc_ireg_mp (cfg);
11189                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11190                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, dreg, 0);
11191                                         } else {
11192                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, sp [0]->dreg, foffset);
11193                                         }
11194                                         load->flags |= ins_flag;
11195                                         if (sp [0]->opcode != OP_LDADDR)
11196                                                 load->flags |= MONO_INST_FAULT;
11197                                         *sp++ = load;
11198                                 }
11199                         }
11200
11201                         if (is_instance) {
11202                                 ins_flag = 0;
11203                                 ip += 5;
11204                                 break;
11205                         }
11206
11207                         /* STATIC CASE */
11208                         context_used = mini_class_check_context_used (cfg, klass);
11209
11210                         if (ftype->attrs & FIELD_ATTRIBUTE_LITERAL)
11211                                 UNVERIFIED;
11212
11213                         /* The special_static_fields field is init'd in mono_class_vtable, so it needs
11214                          * to be called here.
11215                          */
11216                         if (!context_used && !(cfg->opt & MONO_OPT_SHARED)) {
11217                                 mono_class_vtable (cfg->domain, klass);
11218                                 CHECK_TYPELOAD (klass);
11219                         }
11220                         mono_domain_lock (cfg->domain);
11221                         if (cfg->domain->special_static_fields)
11222                                 addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
11223                         mono_domain_unlock (cfg->domain);
11224
11225                         is_special_static = mono_class_field_is_special_static (field);
11226
11227                         if (is_special_static && ((gsize)addr & 0x80000000) == 0)
11228                                 thread_ins = mono_get_thread_intrinsic (cfg);
11229                         else
11230                                 thread_ins = NULL;
11231
11232                         /* Generate IR to compute the field address */
11233                         if (is_special_static && ((gsize)addr & 0x80000000) == 0 && thread_ins && !(cfg->opt & MONO_OPT_SHARED) && !context_used) {
11234                                 /*
11235                                  * Fast access to TLS data
11236                                  * Inline version of get_thread_static_data () in
11237                                  * threads.c.
11238                                  */
11239                                 guint32 offset;
11240                                 int idx, static_data_reg, array_reg, dreg;
11241
11242                                 GSHAREDVT_FAILURE (op);
11243
11244                                 MONO_ADD_INS (cfg->cbb, thread_ins);
11245                                 static_data_reg = alloc_ireg (cfg);
11246                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, MONO_STRUCT_OFFSET (MonoInternalThread, static_data));
11247
11248                                 if (cfg->compile_aot) {
11249                                         int offset_reg, offset2_reg, idx_reg;
11250
11251                                         /* For TLS variables, this will return the TLS offset */
11252                                         EMIT_NEW_SFLDACONST (cfg, ins, field);
11253                                         offset_reg = ins->dreg;
11254                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset_reg, offset_reg, 0x7fffffff);
11255                                         idx_reg = alloc_ireg (cfg);
11256                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, idx_reg, offset_reg, 0x3f);
11257                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
11258                                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
11259                                         array_reg = alloc_ireg (cfg);
11260                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
11261                                         offset2_reg = alloc_ireg (cfg);
11262                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, offset2_reg, offset_reg, 6);
11263                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset2_reg, 0x1ffffff);
11264                                         dreg = alloc_ireg (cfg);
11265                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, array_reg, offset2_reg);
11266                                 } else {
11267                                         offset = (gsize)addr & 0x7fffffff;
11268                                         idx = offset & 0x3f;
11269
11270                                         array_reg = alloc_ireg (cfg);
11271                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, idx * sizeof (gpointer));
11272                                         dreg = alloc_ireg (cfg);
11273                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_ADD_IMM, dreg, array_reg, ((offset >> 6) & 0x1ffffff));
11274                                 }
11275                         } else if ((cfg->opt & MONO_OPT_SHARED) ||
11276                                         (cfg->compile_aot && is_special_static) ||
11277                                         (context_used && is_special_static)) {
11278                                 MonoInst *iargs [2];
11279
11280                                 g_assert (field->parent);
11281                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11282                                 if (context_used) {
11283                                         iargs [1] = emit_get_rgctx_field (cfg, context_used,
11284                                                 field, MONO_RGCTX_INFO_CLASS_FIELD);
11285                                 } else {
11286                                         EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
11287                                 }
11288                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
11289                         } else if (context_used) {
11290                                 MonoInst *static_data;
11291
11292                                 /*
11293                                 g_print ("sharing static field access in %s.%s.%s - depth %d offset %d\n",
11294                                         method->klass->name_space, method->klass->name, method->name,
11295                                         depth, field->offset);
11296                                 */
11297
11298                                 if (mono_class_needs_cctor_run (klass, method))
11299                                         emit_class_init (cfg, klass);
11300
11301                                 /*
11302                                  * The pointer we're computing here is
11303                                  *
11304                                  *   super_info.static_data + field->offset
11305                                  */
11306                                 static_data = emit_get_rgctx_klass (cfg, context_used,
11307                                         klass, MONO_RGCTX_INFO_STATIC_DATA);
11308
11309                                 if (mini_is_gsharedvt_klass (klass)) {
11310                                         MonoInst *offset_ins;
11311
11312                                         offset_ins = emit_get_rgctx_field (cfg, context_used, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11313                                         dreg = alloc_ireg_mp (cfg);
11314                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, static_data->dreg, offset_ins->dreg);
11315                                 } else if (field->offset == 0) {
11316                                         ins = static_data;
11317                                 } else {
11318                                         int addr_reg = mono_alloc_preg (cfg);
11319                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, addr_reg, static_data->dreg, field->offset);
11320                                 }
11321                                 } else if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
11322                                 MonoInst *iargs [2];
11323
11324                                 g_assert (field->parent);
11325                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11326                                 EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
11327                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
11328                         } else {
11329                                 MonoVTable *vtable = NULL;
11330
11331                                 if (!cfg->compile_aot)
11332                                         vtable = mono_class_vtable (cfg->domain, klass);
11333                                 CHECK_TYPELOAD (klass);
11334
11335                                 if (!addr) {
11336                                         if (mini_field_access_needs_cctor_run (cfg, method, klass, vtable)) {
11337                                                 if (!(g_slist_find (class_inits, klass))) {
11338                                                         emit_class_init (cfg, klass);
11339                                                         if (cfg->verbose_level > 2)
11340                                                                 printf ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, mono_field_get_name (field));
11341                                                         class_inits = g_slist_prepend (class_inits, klass);
11342                                                 }
11343                                         } else {
11344                                                 if (cfg->run_cctors) {
11345                                                         MonoException *ex;
11346                                                         /* This makes so that inline cannot trigger */
11347                                                         /* .cctors: too many apps depend on them */
11348                                                         /* running with a specific order... */
11349                                                         g_assert (vtable);
11350                                                         if (! vtable->initialized)
11351                                                                 INLINE_FAILURE ("class init");
11352                                                         ex = mono_runtime_class_init_full (vtable, FALSE);
11353                                                         if (ex) {
11354                                                                 set_exception_object (cfg, ex);
11355                                                                 goto exception_exit;
11356                                                         }
11357                                                 }
11358                                         }
11359                                         if (cfg->compile_aot)
11360                                                 EMIT_NEW_SFLDACONST (cfg, ins, field);
11361                                         else {
11362                                                 g_assert (vtable);
11363                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11364                                                 g_assert (addr);
11365                                                 EMIT_NEW_PCONST (cfg, ins, addr);
11366                                         }
11367                                 } else {
11368                                         MonoInst *iargs [1];
11369                                         EMIT_NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
11370                                         ins = mono_emit_jit_icall (cfg, mono_get_special_static_data, iargs);
11371                                 }
11372                         }
11373
11374                         /* Generate IR to do the actual load/store operation */
11375
11376                         if ((op == CEE_STFLD || op == CEE_STSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11377                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11378                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11379                         }
11380
11381                         if (op == CEE_LDSFLDA) {
11382                                 ins->klass = mono_class_from_mono_type (ftype);
11383                                 ins->type = STACK_PTR;
11384                                 *sp++ = ins;
11385                         } else if (op == CEE_STSFLD) {
11386                                 MonoInst *store;
11387
11388                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, ftype, ins->dreg, 0, store_val->dreg);
11389                                 store->flags |= ins_flag;
11390                         } else {
11391                                 gboolean is_const = FALSE;
11392                                 MonoVTable *vtable = NULL;
11393                                 gpointer addr = NULL;
11394
11395                                 if (!context_used) {
11396                                         vtable = mono_class_vtable (cfg->domain, klass);
11397                                         CHECK_TYPELOAD (klass);
11398                                 }
11399                                 if ((ftype->attrs & FIELD_ATTRIBUTE_INIT_ONLY) && (((addr = mono_aot_readonly_field_override (field)) != NULL) ||
11400                                                 (!context_used && !((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && vtable->initialized))) {
11401                                         int ro_type = ftype->type;
11402                                         if (!addr)
11403                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11404                                         if (ro_type == MONO_TYPE_VALUETYPE && ftype->data.klass->enumtype) {
11405                                                 ro_type = mono_class_enum_basetype (ftype->data.klass)->type;
11406                                         }
11407
11408                                         GSHAREDVT_FAILURE (op);
11409
11410                                         /* printf ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, mono_field_get_name (field));*/
11411                                         is_const = TRUE;
11412                                         switch (ro_type) {
11413                                         case MONO_TYPE_BOOLEAN:
11414                                         case MONO_TYPE_U1:
11415                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint8 *)addr));
11416                                                 sp++;
11417                                                 break;
11418                                         case MONO_TYPE_I1:
11419                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint8 *)addr));
11420                                                 sp++;
11421                                                 break;                                          
11422                                         case MONO_TYPE_CHAR:
11423                                         case MONO_TYPE_U2:
11424                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint16 *)addr));
11425                                                 sp++;
11426                                                 break;
11427                                         case MONO_TYPE_I2:
11428                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint16 *)addr));
11429                                                 sp++;
11430                                                 break;
11431                                                 break;
11432                                         case MONO_TYPE_I4:
11433                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint32 *)addr));
11434                                                 sp++;
11435                                                 break;                                          
11436                                         case MONO_TYPE_U4:
11437                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint32 *)addr));
11438                                                 sp++;
11439                                                 break;
11440                                         case MONO_TYPE_I:
11441                                         case MONO_TYPE_U:
11442                                         case MONO_TYPE_PTR:
11443                                         case MONO_TYPE_FNPTR:
11444                                                 EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11445                                                 type_to_eval_stack_type ((cfg), field->type, *sp);
11446                                                 sp++;
11447                                                 break;
11448                                         case MONO_TYPE_STRING:
11449                                         case MONO_TYPE_OBJECT:
11450                                         case MONO_TYPE_CLASS:
11451                                         case MONO_TYPE_SZARRAY:
11452                                         case MONO_TYPE_ARRAY:
11453                                                 if (!mono_gc_is_moving ()) {
11454                                                         EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11455                                                         type_to_eval_stack_type ((cfg), field->type, *sp);
11456                                                         sp++;
11457                                                 } else {
11458                                                         is_const = FALSE;
11459                                                 }
11460                                                 break;
11461                                         case MONO_TYPE_I8:
11462                                         case MONO_TYPE_U8:
11463                                                 EMIT_NEW_I8CONST (cfg, *sp, *((gint64 *)addr));
11464                                                 sp++;
11465                                                 break;
11466                                         case MONO_TYPE_R4:
11467                                         case MONO_TYPE_R8:
11468                                         case MONO_TYPE_VALUETYPE:
11469                                         default:
11470                                                 is_const = FALSE;
11471                                                 break;
11472                                         }
11473                                 }
11474
11475                                 if (!is_const) {
11476                                         MonoInst *load;
11477
11478                                         CHECK_STACK_OVF (1);
11479
11480                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, ins->dreg, 0);
11481                                         load->flags |= ins_flag;
11482                                         ins_flag = 0;
11483                                         *sp++ = load;
11484                                 }
11485                         }
11486
11487                         if ((op == CEE_LDFLD || op == CEE_LDSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11488                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
11489                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
11490                         }
11491
11492                         ins_flag = 0;
11493                         ip += 5;
11494                         break;
11495                 }
11496                 case CEE_STOBJ:
11497                         CHECK_STACK (2);
11498                         sp -= 2;
11499                         CHECK_OPSIZE (5);
11500                         token = read32 (ip + 1);
11501                         klass = mini_get_class (method, token, generic_context);
11502                         CHECK_TYPELOAD (klass);
11503                         if (ins_flag & MONO_INST_VOLATILE) {
11504                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11505                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11506                         }
11507                         /* FIXME: should check item at sp [1] is compatible with the type of the store. */
11508                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0, sp [1]->dreg);
11509                         ins->flags |= ins_flag;
11510                         if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER &&
11511                                         generic_class_is_reference_type (cfg, klass)) {
11512                                 /* insert call to write barrier */
11513                                 emit_write_barrier (cfg, sp [0], sp [1]);
11514                         }
11515                         ins_flag = 0;
11516                         ip += 5;
11517                         inline_costs += 1;
11518                         break;
11519
11520                         /*
11521                          * Array opcodes
11522                          */
11523                 case CEE_NEWARR: {
11524                         MonoInst *len_ins;
11525                         const char *data_ptr;
11526                         int data_size = 0;
11527                         guint32 field_token;
11528
11529                         CHECK_STACK (1);
11530                         --sp;
11531
11532                         CHECK_OPSIZE (5);
11533                         token = read32 (ip + 1);
11534
11535                         klass = mini_get_class (method, token, generic_context);
11536                         CHECK_TYPELOAD (klass);
11537
11538                         context_used = mini_class_check_context_used (cfg, klass);
11539
11540                         if (sp [0]->type == STACK_I8 || (SIZEOF_VOID_P == 8 && sp [0]->type == STACK_PTR)) {
11541                                 MONO_INST_NEW (cfg, ins, OP_LCONV_TO_OVF_U4);
11542                                 ins->sreg1 = sp [0]->dreg;
11543                                 ins->type = STACK_I4;
11544                                 ins->dreg = alloc_ireg (cfg);
11545                                 MONO_ADD_INS (cfg->cbb, ins);
11546                                 *sp = mono_decompose_opcode (cfg, ins);
11547                         }
11548
11549                         if (context_used) {
11550                                 MonoInst *args [3];
11551                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11552                                 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
11553
11554                                 /* FIXME: Use OP_NEWARR and decompose later to help abcrem */
11555
11556                                 /* vtable */
11557                                 args [0] = emit_get_rgctx_klass (cfg, context_used,
11558                                         array_class, MONO_RGCTX_INFO_VTABLE);
11559                                 /* array len */
11560                                 args [1] = sp [0];
11561
11562                                 if (managed_alloc)
11563                                         ins = mono_emit_method_call (cfg, managed_alloc, args, NULL);
11564                                 else
11565                                         ins = mono_emit_jit_icall (cfg, mono_array_new_specific, args);
11566                         } else {
11567                                 if (cfg->opt & MONO_OPT_SHARED) {
11568                                         /* Decompose now to avoid problems with references to the domainvar */
11569                                         MonoInst *iargs [3];
11570
11571                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11572                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11573                                         iargs [2] = sp [0];
11574
11575                                         ins = mono_emit_jit_icall (cfg, mono_array_new, iargs);
11576                                 } else {
11577                                         /* Decompose later since it is needed by abcrem */
11578                                         MonoClass *array_type = mono_array_class_get (klass, 1);
11579                                         mono_class_vtable (cfg->domain, array_type);
11580                                         CHECK_TYPELOAD (array_type);
11581
11582                                         MONO_INST_NEW (cfg, ins, OP_NEWARR);
11583                                         ins->dreg = alloc_ireg_ref (cfg);
11584                                         ins->sreg1 = sp [0]->dreg;
11585                                         ins->inst_newa_class = klass;
11586                                         ins->type = STACK_OBJ;
11587                                         ins->klass = array_type;
11588                                         MONO_ADD_INS (cfg->cbb, ins);
11589                                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11590                                         cfg->cbb->has_array_access = TRUE;
11591
11592                                         /* Needed so mono_emit_load_get_addr () gets called */
11593                                         mono_get_got_var (cfg);
11594                                 }
11595                         }
11596
11597                         len_ins = sp [0];
11598                         ip += 5;
11599                         *sp++ = ins;
11600                         inline_costs += 1;
11601
11602                         /* 
11603                          * we inline/optimize the initialization sequence if possible.
11604                          * we should also allocate the array as not cleared, since we spend as much time clearing to 0 as initializing
11605                          * for small sizes open code the memcpy
11606                          * ensure the rva field is big enough
11607                          */
11608                         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))) {
11609                                 MonoMethod *memcpy_method = get_memcpy_method ();
11610                                 MonoInst *iargs [3];
11611                                 int add_reg = alloc_ireg_mp (cfg);
11612
11613                                 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, add_reg, ins->dreg, MONO_STRUCT_OFFSET (MonoArray, vector));
11614                                 if (cfg->compile_aot) {
11615                                         EMIT_NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(field_token), STACK_PTR, NULL);
11616                                 } else {
11617                                         EMIT_NEW_PCONST (cfg, iargs [1], (char*)data_ptr);
11618                                 }
11619                                 EMIT_NEW_ICONST (cfg, iargs [2], data_size);
11620                                 mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
11621                                 ip += 11;
11622                         }
11623
11624                         break;
11625                 }
11626                 case CEE_LDLEN:
11627                         CHECK_STACK (1);
11628                         --sp;
11629                         if (sp [0]->type != STACK_OBJ)
11630                                 UNVERIFIED;
11631
11632                         MONO_INST_NEW (cfg, ins, OP_LDLEN);
11633                         ins->dreg = alloc_preg (cfg);
11634                         ins->sreg1 = sp [0]->dreg;
11635                         ins->type = STACK_I4;
11636                         /* This flag will be inherited by the decomposition */
11637                         ins->flags |= MONO_INST_FAULT;
11638                         MONO_ADD_INS (cfg->cbb, ins);
11639                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11640                         cfg->cbb->has_array_access = TRUE;
11641                         ip ++;
11642                         *sp++ = ins;
11643                         break;
11644                 case CEE_LDELEMA:
11645                         CHECK_STACK (2);
11646                         sp -= 2;
11647                         CHECK_OPSIZE (5);
11648                         if (sp [0]->type != STACK_OBJ)
11649                                 UNVERIFIED;
11650
11651                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11652
11653                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11654                         CHECK_TYPELOAD (klass);
11655                         /* we need to make sure that this array is exactly the type it needs
11656                          * to be for correctness. the wrappers are lax with their usage
11657                          * so we need to ignore them here
11658                          */
11659                         if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE && !readonly) {
11660                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11661                                 mini_emit_check_array_type (cfg, sp [0], array_class);
11662                                 CHECK_TYPELOAD (array_class);
11663                         }
11664
11665                         readonly = FALSE;
11666                         ins = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11667                         *sp++ = ins;
11668                         ip += 5;
11669                         break;
11670                 case CEE_LDELEM:
11671                 case CEE_LDELEM_I1:
11672                 case CEE_LDELEM_U1:
11673                 case CEE_LDELEM_I2:
11674                 case CEE_LDELEM_U2:
11675                 case CEE_LDELEM_I4:
11676                 case CEE_LDELEM_U4:
11677                 case CEE_LDELEM_I8:
11678                 case CEE_LDELEM_I:
11679                 case CEE_LDELEM_R4:
11680                 case CEE_LDELEM_R8:
11681                 case CEE_LDELEM_REF: {
11682                         MonoInst *addr;
11683
11684                         CHECK_STACK (2);
11685                         sp -= 2;
11686
11687                         if (*ip == CEE_LDELEM) {
11688                                 CHECK_OPSIZE (5);
11689                                 token = read32 (ip + 1);
11690                                 klass = mini_get_class (method, token, generic_context);
11691                                 CHECK_TYPELOAD (klass);
11692                                 mono_class_init (klass);
11693                         }
11694                         else
11695                                 klass = array_access_to_klass (*ip);
11696
11697                         if (sp [0]->type != STACK_OBJ)
11698                                 UNVERIFIED;
11699
11700                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11701
11702                         if (mini_is_gsharedvt_variable_klass (klass)) {
11703                                 // FIXME-VT: OP_ICONST optimization
11704                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11705                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11706                                 ins->opcode = OP_LOADV_MEMBASE;
11707                         } else if (sp [1]->opcode == OP_ICONST) {
11708                                 int array_reg = sp [0]->dreg;
11709                                 int index_reg = sp [1]->dreg;
11710                                 int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
11711
11712                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
11713                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset);
11714                         } else {
11715                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11716                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11717                         }
11718                         *sp++ = ins;
11719                         if (*ip == CEE_LDELEM)
11720                                 ip += 5;
11721                         else
11722                                 ++ip;
11723                         break;
11724                 }
11725                 case CEE_STELEM_I:
11726                 case CEE_STELEM_I1:
11727                 case CEE_STELEM_I2:
11728                 case CEE_STELEM_I4:
11729                 case CEE_STELEM_I8:
11730                 case CEE_STELEM_R4:
11731                 case CEE_STELEM_R8:
11732                 case CEE_STELEM_REF:
11733                 case CEE_STELEM: {
11734                         CHECK_STACK (3);
11735                         sp -= 3;
11736
11737                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11738
11739                         if (*ip == CEE_STELEM) {
11740                                 CHECK_OPSIZE (5);
11741                                 token = read32 (ip + 1);
11742                                 klass = mini_get_class (method, token, generic_context);
11743                                 CHECK_TYPELOAD (klass);
11744                                 mono_class_init (klass);
11745                         }
11746                         else
11747                                 klass = array_access_to_klass (*ip);
11748
11749                         if (sp [0]->type != STACK_OBJ)
11750                                 UNVERIFIED;
11751
11752                         emit_array_store (cfg, klass, sp, TRUE);
11753
11754                         if (*ip == CEE_STELEM)
11755                                 ip += 5;
11756                         else
11757                                 ++ip;
11758                         inline_costs += 1;
11759                         break;
11760                 }
11761                 case CEE_CKFINITE: {
11762                         CHECK_STACK (1);
11763                         --sp;
11764
11765                         if (cfg->llvm_only) {
11766                                 MonoInst *iargs [1];
11767
11768                                 iargs [0] = sp [0];
11769                                 *sp++ = mono_emit_jit_icall (cfg, mono_ckfinite, iargs);
11770                         } else  {
11771                                 MONO_INST_NEW (cfg, ins, OP_CKFINITE);
11772                                 ins->sreg1 = sp [0]->dreg;
11773                                 ins->dreg = alloc_freg (cfg);
11774                                 ins->type = STACK_R8;
11775                                 MONO_ADD_INS (cfg->cbb, ins);
11776
11777                                 *sp++ = mono_decompose_opcode (cfg, ins);
11778                         }
11779
11780                         ++ip;
11781                         break;
11782                 }
11783                 case CEE_REFANYVAL: {
11784                         MonoInst *src_var, *src;
11785
11786                         int klass_reg = alloc_preg (cfg);
11787                         int dreg = alloc_preg (cfg);
11788
11789                         GSHAREDVT_FAILURE (*ip);
11790
11791                         CHECK_STACK (1);
11792                         MONO_INST_NEW (cfg, ins, *ip);
11793                         --sp;
11794                         CHECK_OPSIZE (5);
11795                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11796                         CHECK_TYPELOAD (klass);
11797
11798                         context_used = mini_class_check_context_used (cfg, klass);
11799
11800                         // FIXME:
11801                         src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
11802                         if (!src_var)
11803                                 src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
11804                         EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
11805                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass));
11806
11807                         if (context_used) {
11808                                 MonoInst *klass_ins;
11809
11810                                 klass_ins = emit_get_rgctx_klass (cfg, context_used,
11811                                                 klass, MONO_RGCTX_INFO_KLASS);
11812
11813                                 // FIXME:
11814                                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_ins->dreg);
11815                                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
11816                         } else {
11817                                 mini_emit_class_check (cfg, klass_reg, klass);
11818                         }
11819                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value));
11820                         ins->type = STACK_MP;
11821                         ins->klass = klass;
11822                         *sp++ = ins;
11823                         ip += 5;
11824                         break;
11825                 }
11826                 case CEE_MKREFANY: {
11827                         MonoInst *loc, *addr;
11828
11829                         GSHAREDVT_FAILURE (*ip);
11830
11831                         CHECK_STACK (1);
11832                         MONO_INST_NEW (cfg, ins, *ip);
11833                         --sp;
11834                         CHECK_OPSIZE (5);
11835                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11836                         CHECK_TYPELOAD (klass);
11837
11838                         context_used = mini_class_check_context_used (cfg, klass);
11839
11840                         loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
11841                         EMIT_NEW_TEMPLOADA (cfg, addr, loc->inst_c0);
11842
11843                         if (context_used) {
11844                                 MonoInst *const_ins;
11845                                 int type_reg = alloc_preg (cfg);
11846
11847                                 const_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
11848                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_ins->dreg);
11849                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_ins->dreg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
11850                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
11851                         } else if (cfg->compile_aot) {
11852                                 int const_reg = alloc_preg (cfg);
11853                                 int type_reg = alloc_preg (cfg);
11854
11855                                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
11856                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_reg);
11857                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_reg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
11858                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
11859                         } else {
11860                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), &klass->byval_arg);
11861                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), klass);
11862                         }
11863                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value), sp [0]->dreg);
11864
11865                         EMIT_NEW_TEMPLOAD (cfg, ins, loc->inst_c0);
11866                         ins->type = STACK_VTYPE;
11867                         ins->klass = mono_defaults.typed_reference_class;
11868                         *sp++ = ins;
11869                         ip += 5;
11870                         break;
11871                 }
11872                 case CEE_LDTOKEN: {
11873                         gpointer handle;
11874                         MonoClass *handle_class;
11875
11876                         CHECK_STACK_OVF (1);
11877
11878                         CHECK_OPSIZE (5);
11879                         n = read32 (ip + 1);
11880
11881                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD ||
11882                                         method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
11883                                 handle = mono_method_get_wrapper_data (method, n);
11884                                 handle_class = mono_method_get_wrapper_data (method, n + 1);
11885                                 if (handle_class == mono_defaults.typehandle_class)
11886                                         handle = &((MonoClass*)handle)->byval_arg;
11887                         }
11888                         else {
11889                                 handle = mono_ldtoken_checked (image, n, &handle_class, generic_context, &cfg->error);
11890                                 CHECK_CFG_ERROR;
11891                         }
11892                         if (!handle)
11893                                 LOAD_ERROR;
11894                         mono_class_init (handle_class);
11895                         if (cfg->gshared) {
11896                                 if (mono_metadata_token_table (n) == MONO_TABLE_TYPEDEF ||
11897                                                 mono_metadata_token_table (n) == MONO_TABLE_TYPEREF) {
11898                                         /* This case handles ldtoken
11899                                            of an open type, like for
11900                                            typeof(Gen<>). */
11901                                         context_used = 0;
11902                                 } else if (handle_class == mono_defaults.typehandle_class) {
11903                                         context_used = mini_class_check_context_used (cfg, mono_class_from_mono_type (handle));
11904                                 } else if (handle_class == mono_defaults.fieldhandle_class)
11905                                         context_used = mini_class_check_context_used (cfg, ((MonoClassField*)handle)->parent);
11906                                 else if (handle_class == mono_defaults.methodhandle_class)
11907                                         context_used = mini_method_check_context_used (cfg, handle);
11908                                 else
11909                                         g_assert_not_reached ();
11910                         }
11911
11912                         if ((cfg->opt & MONO_OPT_SHARED) &&
11913                                         method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD &&
11914                                         method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED) {
11915                                 MonoInst *addr, *vtvar, *iargs [3];
11916                                 int method_context_used;
11917
11918                                 method_context_used = mini_method_check_context_used (cfg, method);
11919
11920                                 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL); 
11921
11922                                 EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
11923                                 EMIT_NEW_ICONST (cfg, iargs [1], n);
11924                                 if (method_context_used) {
11925                                         iargs [2] = emit_get_rgctx_method (cfg, method_context_used,
11926                                                 method, MONO_RGCTX_INFO_METHOD);
11927                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper_generic_shared, iargs);
11928                                 } else {
11929                                         EMIT_NEW_PCONST (cfg, iargs [2], generic_context);
11930                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper, iargs);
11931                                 }
11932                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
11933
11934                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
11935
11936                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
11937                         } else {
11938                                 if ((ip + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 5) && 
11939                                         ((ip [5] == CEE_CALL) || (ip [5] == CEE_CALLVIRT)) && 
11940                                         (cmethod = mini_get_method (cfg, method, read32 (ip + 6), NULL, generic_context)) &&
11941                                         (cmethod->klass == mono_defaults.systemtype_class) &&
11942                                         (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
11943                                         MonoClass *tclass = mono_class_from_mono_type (handle);
11944
11945                                         mono_class_init (tclass);
11946                                         if (context_used) {
11947                                                 ins = emit_get_rgctx_klass (cfg, context_used,
11948                                                         tclass, MONO_RGCTX_INFO_REFLECTION_TYPE);
11949                                         } else if (cfg->compile_aot) {
11950                                                 if (method->wrapper_type) {
11951                                                         mono_error_init (&error); //got to do it since there are multiple conditionals below
11952                                                         if (mono_class_get_checked (tclass->image, tclass->type_token, &error) == tclass && !generic_context) {
11953                                                                 /* Special case for static synchronized wrappers */
11954                                                                 EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, tclass->image, tclass->type_token, generic_context);
11955                                                         } else {
11956                                                                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
11957                                                                 /* FIXME: n is not a normal token */
11958                                                                 DISABLE_AOT (cfg);
11959                                                                 EMIT_NEW_PCONST (cfg, ins, NULL);
11960                                                         }
11961                                                 } else {
11962                                                         EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n, generic_context);
11963                                                 }
11964                                         } else {
11965                                                 EMIT_NEW_PCONST (cfg, ins, mono_type_get_object (cfg->domain, handle));
11966                                         }
11967                                         ins->type = STACK_OBJ;
11968                                         ins->klass = cmethod->klass;
11969                                         ip += 5;
11970                                 } else {
11971                                         MonoInst *addr, *vtvar;
11972
11973                                         vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
11974
11975                                         if (context_used) {
11976                                                 if (handle_class == mono_defaults.typehandle_class) {
11977                                                         ins = emit_get_rgctx_klass (cfg, context_used,
11978                                                                         mono_class_from_mono_type (handle),
11979                                                                         MONO_RGCTX_INFO_TYPE);
11980                                                 } else if (handle_class == mono_defaults.methodhandle_class) {
11981                                                         ins = emit_get_rgctx_method (cfg, context_used,
11982                                                                         handle, MONO_RGCTX_INFO_METHOD);
11983                                                 } else if (handle_class == mono_defaults.fieldhandle_class) {
11984                                                         ins = emit_get_rgctx_field (cfg, context_used,
11985                                                                         handle, MONO_RGCTX_INFO_CLASS_FIELD);
11986                                                 } else {
11987                                                         g_assert_not_reached ();
11988                                                 }
11989                                         } else if (cfg->compile_aot) {
11990                                                 EMIT_NEW_LDTOKENCONST (cfg, ins, image, n, generic_context);
11991                                         } else {
11992                                                 EMIT_NEW_PCONST (cfg, ins, handle);
11993                                         }
11994                                         EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
11995                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
11996                                         EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
11997                                 }
11998                         }
11999
12000                         *sp++ = ins;
12001                         ip += 5;
12002                         break;
12003                 }
12004                 case CEE_THROW:
12005                         CHECK_STACK (1);
12006                         MONO_INST_NEW (cfg, ins, OP_THROW);
12007                         --sp;
12008                         ins->sreg1 = sp [0]->dreg;
12009                         ip++;
12010                         cfg->cbb->out_of_line = TRUE;
12011                         MONO_ADD_INS (cfg->cbb, ins);
12012                         MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
12013                         MONO_ADD_INS (cfg->cbb, ins);
12014                         sp = stack_start;
12015                         
12016                         link_bblock (cfg, cfg->cbb, end_bblock);
12017                         start_new_bblock = 1;
12018                         /* This can complicate code generation for llvm since the return value might not be defined */
12019                         if (COMPILE_LLVM (cfg))
12020                                 INLINE_FAILURE ("throw");
12021                         break;
12022                 case CEE_ENDFINALLY:
12023                         /* mono_save_seq_point_info () depends on this */
12024                         if (sp != stack_start)
12025                                 emit_seq_point (cfg, method, ip, FALSE, FALSE);
12026                         MONO_INST_NEW (cfg, ins, OP_ENDFINALLY);
12027                         MONO_ADD_INS (cfg->cbb, ins);
12028                         ip++;
12029                         start_new_bblock = 1;
12030
12031                         /*
12032                          * Control will leave the method so empty the stack, otherwise
12033                          * the next basic block will start with a nonempty stack.
12034                          */
12035                         while (sp != stack_start) {
12036                                 sp--;
12037                         }
12038                         break;
12039                 case CEE_LEAVE:
12040                 case CEE_LEAVE_S: {
12041                         GList *handlers;
12042
12043                         if (*ip == CEE_LEAVE) {
12044                                 CHECK_OPSIZE (5);
12045                                 target = ip + 5 + (gint32)read32(ip + 1);
12046                         } else {
12047                                 CHECK_OPSIZE (2);
12048                                 target = ip + 2 + (signed char)(ip [1]);
12049                         }
12050
12051                         /* empty the stack */
12052                         while (sp != stack_start) {
12053                                 sp--;
12054                         }
12055
12056                         /* 
12057                          * If this leave statement is in a catch block, check for a
12058                          * pending exception, and rethrow it if necessary.
12059                          * We avoid doing this in runtime invoke wrappers, since those are called
12060                          * by native code which excepts the wrapper to catch all exceptions.
12061                          */
12062                         for (i = 0; i < header->num_clauses; ++i) {
12063                                 MonoExceptionClause *clause = &header->clauses [i];
12064
12065                                 /* 
12066                                  * Use <= in the final comparison to handle clauses with multiple
12067                                  * leave statements, like in bug #78024.
12068                                  * The ordering of the exception clauses guarantees that we find the
12069                                  * innermost clause.
12070                                  */
12071                                 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) {
12072                                         MonoInst *exc_ins;
12073                                         MonoBasicBlock *dont_throw;
12074
12075                                         /*
12076                                           MonoInst *load;
12077
12078                                           NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, clause->handler_offset)->inst_c0);
12079                                         */
12080
12081                                         exc_ins = mono_emit_jit_icall (cfg, mono_thread_get_undeniable_exception, NULL);
12082
12083                                         NEW_BBLOCK (cfg, dont_throw);
12084
12085                                         /*
12086                                          * Currently, we always rethrow the abort exception, despite the 
12087                                          * fact that this is not correct. See thread6.cs for an example. 
12088                                          * But propagating the abort exception is more important than 
12089                                          * getting the sematics right.
12090                                          */
12091                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, exc_ins->dreg, 0);
12092                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, dont_throw);
12093                                         MONO_EMIT_NEW_UNALU (cfg, OP_THROW, -1, exc_ins->dreg);
12094
12095                                         MONO_START_BB (cfg, dont_throw);
12096                                 }
12097                         }
12098
12099 #ifdef ENABLE_LLVM
12100                         cfg->cbb->try_end = (intptr_t)(ip - header->code);
12101 #endif
12102
12103                         if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
12104                                 GList *tmp;
12105                                 MonoExceptionClause *clause;
12106
12107                                 for (tmp = handlers; tmp; tmp = tmp->next) {
12108                                         clause = tmp->data;
12109                                         tblock = cfg->cil_offset_to_bb [clause->handler_offset];
12110                                         g_assert (tblock);
12111                                         link_bblock (cfg, cfg->cbb, tblock);
12112                                         MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
12113                                         ins->inst_target_bb = tblock;
12114                                         ins->inst_eh_block = clause;
12115                                         MONO_ADD_INS (cfg->cbb, ins);
12116                                         cfg->cbb->has_call_handler = 1;
12117                                         if (COMPILE_LLVM (cfg)) {
12118                                                 MonoBasicBlock *target_bb;
12119
12120                                                 /* 
12121                                                  * Link the finally bblock with the target, since it will
12122                                                  * conceptually branch there.
12123                                                  * FIXME: Have to link the bblock containing the endfinally.
12124                                                  */
12125                                                 GET_BBLOCK (cfg, target_bb, target);
12126                                                 link_bblock (cfg, tblock, target_bb);
12127                                         }
12128                                 }
12129                                 g_list_free (handlers);
12130                         } 
12131
12132                         MONO_INST_NEW (cfg, ins, OP_BR);
12133                         MONO_ADD_INS (cfg->cbb, ins);
12134                         GET_BBLOCK (cfg, tblock, target);
12135                         link_bblock (cfg, cfg->cbb, tblock);
12136                         ins->inst_target_bb = tblock;
12137
12138                         start_new_bblock = 1;
12139
12140                         if (*ip == CEE_LEAVE)
12141                                 ip += 5;
12142                         else
12143                                 ip += 2;
12144
12145                         break;
12146                 }
12147
12148                         /*
12149                          * Mono specific opcodes
12150                          */
12151                 case MONO_CUSTOM_PREFIX: {
12152
12153                         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
12154
12155                         CHECK_OPSIZE (2);
12156                         switch (ip [1]) {
12157                         case CEE_MONO_ICALL: {
12158                                 gpointer func;
12159                                 MonoJitICallInfo *info;
12160
12161                                 token = read32 (ip + 2);
12162                                 func = mono_method_get_wrapper_data (method, token);
12163                                 info = mono_find_jit_icall_by_addr (func);
12164                                 if (!info)
12165                                         g_error ("Could not find icall address in wrapper %s", mono_method_full_name (method, 1));
12166                                 g_assert (info);
12167
12168                                 CHECK_STACK (info->sig->param_count);
12169                                 sp -= info->sig->param_count;
12170
12171                                 ins = mono_emit_jit_icall (cfg, info->func, sp);
12172                                 if (!MONO_TYPE_IS_VOID (info->sig->ret))
12173                                         *sp++ = ins;
12174
12175                                 ip += 6;
12176                                 inline_costs += 10 * num_calls++;
12177
12178                                 break;
12179                         }
12180                         case CEE_MONO_LDPTR_CARD_TABLE: {
12181                                 int shift_bits;
12182                                 gpointer card_mask;
12183                                 CHECK_STACK_OVF (1);
12184
12185                                 if (cfg->compile_aot)
12186                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR, NULL);
12187                                 else
12188                                         EMIT_NEW_PCONST (cfg, ins, mono_gc_get_card_table (&shift_bits, &card_mask));
12189
12190                                 *sp++ = ins;
12191                                 ip += 2;
12192                                 inline_costs += 10 * num_calls++;
12193                                 break;
12194                         }
12195                         case CEE_MONO_LDPTR_NURSERY_START: {
12196                                 int shift_bits;
12197                                 size_t size;
12198                                 CHECK_STACK_OVF (1);
12199
12200                                 if (cfg->compile_aot)
12201                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_GC_NURSERY_START, NULL);
12202                                 else
12203                                         EMIT_NEW_PCONST (cfg, ins, mono_gc_get_nursery (&shift_bits, &size));
12204
12205                                 *sp++ = ins;
12206                                 ip += 2;
12207                                 inline_costs += 10 * num_calls++;
12208                                 break;
12209                         }
12210                         case CEE_MONO_LDPTR_INT_REQ_FLAG: {
12211                                 CHECK_STACK_OVF (1);
12212
12213                                 if (cfg->compile_aot)
12214                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG, NULL);
12215                                 else
12216                                         EMIT_NEW_PCONST (cfg, ins, mono_thread_interruption_request_flag ());
12217
12218                                 *sp++ = ins;
12219                                 ip += 2;
12220                                 inline_costs += 10 * num_calls++;
12221                                 break;
12222                         }
12223                         case CEE_MONO_LDPTR: {
12224                                 gpointer ptr;
12225
12226                                 CHECK_STACK_OVF (1);
12227                                 CHECK_OPSIZE (6);
12228                                 token = read32 (ip + 2);
12229
12230                                 ptr = mono_method_get_wrapper_data (method, token);
12231                                 EMIT_NEW_PCONST (cfg, ins, ptr);
12232                                 *sp++ = ins;
12233                                 ip += 6;
12234                                 inline_costs += 10 * num_calls++;
12235                                 /* Can't embed random pointers into AOT code */
12236                                 DISABLE_AOT (cfg);
12237                                 break;
12238                         }
12239                         case CEE_MONO_JIT_ICALL_ADDR: {
12240                                 MonoJitICallInfo *callinfo;
12241                                 gpointer ptr;
12242
12243                                 CHECK_STACK_OVF (1);
12244                                 CHECK_OPSIZE (6);
12245                                 token = read32 (ip + 2);
12246
12247                                 ptr = mono_method_get_wrapper_data (method, token);
12248                                 callinfo = mono_find_jit_icall_by_addr (ptr);
12249                                 g_assert (callinfo);
12250                                 EMIT_NEW_JIT_ICALL_ADDRCONST (cfg, ins, (char*)callinfo->name);
12251                                 *sp++ = ins;
12252                                 ip += 6;
12253                                 inline_costs += 10 * num_calls++;
12254                                 break;
12255                         }
12256                         case CEE_MONO_ICALL_ADDR: {
12257                                 MonoMethod *cmethod;
12258                                 gpointer ptr;
12259
12260                                 CHECK_STACK_OVF (1);
12261                                 CHECK_OPSIZE (6);
12262                                 token = read32 (ip + 2);
12263
12264                                 cmethod = mono_method_get_wrapper_data (method, token);
12265
12266                                 if (cfg->compile_aot) {
12267                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, cmethod);
12268                                 } else {
12269                                         ptr = mono_lookup_internal_call (cmethod);
12270                                         g_assert (ptr);
12271                                         EMIT_NEW_PCONST (cfg, ins, ptr);
12272                                 }
12273                                 *sp++ = ins;
12274                                 ip += 6;
12275                                 break;
12276                         }
12277                         case CEE_MONO_VTADDR: {
12278                                 MonoInst *src_var, *src;
12279
12280                                 CHECK_STACK (1);
12281                                 --sp;
12282
12283                                 // FIXME:
12284                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
12285                                 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
12286                                 *sp++ = src;
12287                                 ip += 2;
12288                                 break;
12289                         }
12290                         case CEE_MONO_NEWOBJ: {
12291                                 MonoInst *iargs [2];
12292
12293                                 CHECK_STACK_OVF (1);
12294                                 CHECK_OPSIZE (6);
12295                                 token = read32 (ip + 2);
12296                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12297                                 mono_class_init (klass);
12298                                 NEW_DOMAINCONST (cfg, iargs [0]);
12299                                 MONO_ADD_INS (cfg->cbb, iargs [0]);
12300                                 NEW_CLASSCONST (cfg, iargs [1], klass);
12301                                 MONO_ADD_INS (cfg->cbb, iargs [1]);
12302                                 *sp++ = mono_emit_jit_icall (cfg, mono_object_new, iargs);
12303                                 ip += 6;
12304                                 inline_costs += 10 * num_calls++;
12305                                 break;
12306                         }
12307                         case CEE_MONO_OBJADDR:
12308                                 CHECK_STACK (1);
12309                                 --sp;
12310                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
12311                                 ins->dreg = alloc_ireg_mp (cfg);
12312                                 ins->sreg1 = sp [0]->dreg;
12313                                 ins->type = STACK_MP;
12314                                 MONO_ADD_INS (cfg->cbb, ins);
12315                                 *sp++ = ins;
12316                                 ip += 2;
12317                                 break;
12318                         case CEE_MONO_LDNATIVEOBJ:
12319                                 /*
12320                                  * Similar to LDOBJ, but instead load the unmanaged 
12321                                  * representation of the vtype to the stack.
12322                                  */
12323                                 CHECK_STACK (1);
12324                                 CHECK_OPSIZE (6);
12325                                 --sp;
12326                                 token = read32 (ip + 2);
12327                                 klass = mono_method_get_wrapper_data (method, token);
12328                                 g_assert (klass->valuetype);
12329                                 mono_class_init (klass);
12330
12331                                 {
12332                                         MonoInst *src, *dest, *temp;
12333
12334                                         src = sp [0];
12335                                         temp = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
12336                                         temp->backend.is_pinvoke = 1;
12337                                         EMIT_NEW_TEMPLOADA (cfg, dest, temp->inst_c0);
12338                                         mini_emit_stobj (cfg, dest, src, klass, TRUE);
12339
12340                                         EMIT_NEW_TEMPLOAD (cfg, dest, temp->inst_c0);
12341                                         dest->type = STACK_VTYPE;
12342                                         dest->klass = klass;
12343
12344                                         *sp ++ = dest;
12345                                         ip += 6;
12346                                 }
12347                                 break;
12348                         case CEE_MONO_RETOBJ: {
12349                                 /*
12350                                  * Same as RET, but return the native representation of a vtype
12351                                  * to the caller.
12352                                  */
12353                                 g_assert (cfg->ret);
12354                                 g_assert (mono_method_signature (method)->pinvoke); 
12355                                 CHECK_STACK (1);
12356                                 --sp;
12357                                 
12358                                 CHECK_OPSIZE (6);
12359                                 token = read32 (ip + 2);    
12360                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12361
12362                                 if (!cfg->vret_addr) {
12363                                         g_assert (cfg->ret_var_is_local);
12364
12365                                         EMIT_NEW_VARLOADA (cfg, ins, cfg->ret, cfg->ret->inst_vtype);
12366                                 } else {
12367                                         EMIT_NEW_RETLOADA (cfg, ins);
12368                                 }
12369                                 mini_emit_stobj (cfg, ins, sp [0], klass, TRUE);
12370                                 
12371                                 if (sp != stack_start)
12372                                         UNVERIFIED;
12373                                 
12374                                 MONO_INST_NEW (cfg, ins, OP_BR);
12375                                 ins->inst_target_bb = end_bblock;
12376                                 MONO_ADD_INS (cfg->cbb, ins);
12377                                 link_bblock (cfg, cfg->cbb, end_bblock);
12378                                 start_new_bblock = 1;
12379                                 ip += 6;
12380                                 break;
12381                         }
12382                         case CEE_MONO_CISINST:
12383                         case CEE_MONO_CCASTCLASS: {
12384                                 int token;
12385                                 CHECK_STACK (1);
12386                                 --sp;
12387                                 CHECK_OPSIZE (6);
12388                                 token = read32 (ip + 2);
12389                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12390                                 if (ip [1] == CEE_MONO_CISINST)
12391                                         ins = handle_cisinst (cfg, klass, sp [0]);
12392                                 else
12393                                         ins = handle_ccastclass (cfg, klass, sp [0]);
12394                                 *sp++ = ins;
12395                                 ip += 6;
12396                                 break;
12397                         }
12398                         case CEE_MONO_SAVE_LMF:
12399                         case CEE_MONO_RESTORE_LMF:
12400                                 ip += 2;
12401                                 break;
12402                         case CEE_MONO_CLASSCONST:
12403                                 CHECK_STACK_OVF (1);
12404                                 CHECK_OPSIZE (6);
12405                                 token = read32 (ip + 2);
12406                                 EMIT_NEW_CLASSCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
12407                                 *sp++ = ins;
12408                                 ip += 6;
12409                                 inline_costs += 10 * num_calls++;
12410                                 break;
12411                         case CEE_MONO_NOT_TAKEN:
12412                                 cfg->cbb->out_of_line = TRUE;
12413                                 ip += 2;
12414                                 break;
12415                         case CEE_MONO_TLS: {
12416                                 int key;
12417
12418                                 CHECK_STACK_OVF (1);
12419                                 CHECK_OPSIZE (6);
12420                                 key = (gint32)read32 (ip + 2);
12421                                 g_assert (key < TLS_KEY_NUM);
12422
12423                                 ins = mono_create_tls_get (cfg, key);
12424                                 if (!ins) {
12425                                         if (cfg->compile_aot) {
12426                                                 DISABLE_AOT (cfg);
12427                                                 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
12428                                                 ins->dreg = alloc_preg (cfg);
12429                                                 ins->type = STACK_PTR;
12430                                         } else {
12431                                                 g_assert_not_reached ();
12432                                         }
12433                                 }
12434                                 ins->type = STACK_PTR;
12435                                 MONO_ADD_INS (cfg->cbb, ins);
12436                                 *sp++ = ins;
12437                                 ip += 6;
12438                                 break;
12439                         }
12440                         case CEE_MONO_DYN_CALL: {
12441                                 MonoCallInst *call;
12442
12443                                 /* It would be easier to call a trampoline, but that would put an
12444                                  * extra frame on the stack, confusing exception handling. So
12445                                  * implement it inline using an opcode for now.
12446                                  */
12447
12448                                 if (!cfg->dyn_call_var) {
12449                                         cfg->dyn_call_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12450                                         /* prevent it from being register allocated */
12451                                         cfg->dyn_call_var->flags |= MONO_INST_VOLATILE;
12452                                 }
12453
12454                                 /* Has to use a call inst since it local regalloc expects it */
12455                                 MONO_INST_NEW_CALL (cfg, call, OP_DYN_CALL);
12456                                 ins = (MonoInst*)call;
12457                                 sp -= 2;
12458                                 ins->sreg1 = sp [0]->dreg;
12459                                 ins->sreg2 = sp [1]->dreg;
12460                                 MONO_ADD_INS (cfg->cbb, ins);
12461
12462                                 cfg->param_area = MAX (cfg->param_area, MONO_ARCH_DYN_CALL_PARAM_AREA);
12463
12464                                 ip += 2;
12465                                 inline_costs += 10 * num_calls++;
12466
12467                                 break;
12468                         }
12469                         case CEE_MONO_MEMORY_BARRIER: {
12470                                 CHECK_OPSIZE (6);
12471                                 emit_memory_barrier (cfg, (int)read32 (ip + 2));
12472                                 ip += 6;
12473                                 break;
12474                         }
12475                         case CEE_MONO_JIT_ATTACH: {
12476                                 MonoInst *args [16], *domain_ins;
12477                                 MonoInst *ad_ins, *jit_tls_ins;
12478                                 MonoBasicBlock *next_bb = NULL, *call_bb = NULL;
12479
12480                                 cfg->orig_domain_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12481
12482                                 EMIT_NEW_PCONST (cfg, ins, NULL);
12483                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12484
12485                                 ad_ins = mono_get_domain_intrinsic (cfg);
12486                                 jit_tls_ins = mono_get_jit_tls_intrinsic (cfg);
12487
12488                                 if (MONO_ARCH_HAVE_TLS_GET && ad_ins && jit_tls_ins) {
12489                                         NEW_BBLOCK (cfg, next_bb);
12490                                         NEW_BBLOCK (cfg, call_bb);
12491
12492                                         if (cfg->compile_aot) {
12493                                                 /* AOT code is only used in the root domain */
12494                                                 EMIT_NEW_PCONST (cfg, domain_ins, NULL);
12495                                         } else {
12496                                                 EMIT_NEW_PCONST (cfg, domain_ins, cfg->domain);
12497                                         }
12498                                         MONO_ADD_INS (cfg->cbb, ad_ins);
12499                                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, ad_ins->dreg, domain_ins->dreg);
12500                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, call_bb);
12501
12502                                         MONO_ADD_INS (cfg->cbb, jit_tls_ins);
12503                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, jit_tls_ins->dreg, 0);
12504                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, call_bb);
12505
12506                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, next_bb);
12507                                         MONO_START_BB (cfg, call_bb);
12508                                 }
12509
12510                                 if (cfg->compile_aot) {
12511                                         /* AOT code is only used in the root domain */
12512                                         EMIT_NEW_PCONST (cfg, args [0], NULL);
12513                                 } else {
12514                                         EMIT_NEW_PCONST (cfg, args [0], cfg->domain);
12515                                 }
12516                                 ins = mono_emit_jit_icall (cfg, mono_jit_thread_attach, args);
12517                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12518
12519                                 if (next_bb)
12520                                         MONO_START_BB (cfg, next_bb);
12521                                 ip += 2;
12522                                 break;
12523                         }
12524                         case CEE_MONO_JIT_DETACH: {
12525                                 MonoInst *args [16];
12526
12527                                 /* Restore the original domain */
12528                                 dreg = alloc_ireg (cfg);
12529                                 EMIT_NEW_UNALU (cfg, args [0], OP_MOVE, dreg, cfg->orig_domain_var->dreg);
12530                                 mono_emit_jit_icall (cfg, mono_jit_set_domain, args);
12531                                 ip += 2;
12532                                 break;
12533                         }
12534                         default:
12535                                 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
12536                                 break;
12537                         }
12538                         break;
12539                 }
12540
12541                 case CEE_PREFIX1: {
12542                         CHECK_OPSIZE (2);
12543                         switch (ip [1]) {
12544                         case CEE_ARGLIST: {
12545                                 /* somewhat similar to LDTOKEN */
12546                                 MonoInst *addr, *vtvar;
12547                                 CHECK_STACK_OVF (1);
12548                                 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL); 
12549
12550                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
12551                                 EMIT_NEW_UNALU (cfg, ins, OP_ARGLIST, -1, addr->dreg);
12552
12553                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
12554                                 ins->type = STACK_VTYPE;
12555                                 ins->klass = mono_defaults.argumenthandle_class;
12556                                 *sp++ = ins;
12557                                 ip += 2;
12558                                 break;
12559                         }
12560                         case CEE_CEQ:
12561                         case CEE_CGT:
12562                         case CEE_CGT_UN:
12563                         case CEE_CLT:
12564                         case CEE_CLT_UN: {
12565                                 MonoInst *cmp, *arg1, *arg2;
12566
12567                                 CHECK_STACK (2);
12568                                 sp -= 2;
12569                                 arg1 = sp [0];
12570                                 arg2 = sp [1];
12571
12572                                 /*
12573                                  * The following transforms:
12574                                  *    CEE_CEQ    into OP_CEQ
12575                                  *    CEE_CGT    into OP_CGT
12576                                  *    CEE_CGT_UN into OP_CGT_UN
12577                                  *    CEE_CLT    into OP_CLT
12578                                  *    CEE_CLT_UN into OP_CLT_UN
12579                                  */
12580                                 MONO_INST_NEW (cfg, cmp, (OP_CEQ - CEE_CEQ) + ip [1]);
12581
12582                                 MONO_INST_NEW (cfg, ins, cmp->opcode);
12583                                 cmp->sreg1 = arg1->dreg;
12584                                 cmp->sreg2 = arg2->dreg;
12585                                 type_from_op (cfg, cmp, arg1, arg2);
12586                                 CHECK_TYPE (cmp);
12587                                 add_widen_op (cfg, cmp, &arg1, &arg2);
12588                                 if ((arg1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((arg1->type == STACK_PTR) || (arg1->type == STACK_OBJ) || (arg1->type == STACK_MP))))
12589                                         cmp->opcode = OP_LCOMPARE;
12590                                 else if (arg1->type == STACK_R4)
12591                                         cmp->opcode = OP_RCOMPARE;
12592                                 else if (arg1->type == STACK_R8)
12593                                         cmp->opcode = OP_FCOMPARE;
12594                                 else
12595                                         cmp->opcode = OP_ICOMPARE;
12596                                 MONO_ADD_INS (cfg->cbb, cmp);
12597                                 ins->type = STACK_I4;
12598                                 ins->dreg = alloc_dreg (cfg, ins->type);
12599                                 type_from_op (cfg, ins, arg1, arg2);
12600
12601                                 if (cmp->opcode == OP_FCOMPARE || cmp->opcode == OP_RCOMPARE) {
12602                                         /*
12603                                          * The backends expect the fceq opcodes to do the
12604                                          * comparison too.
12605                                          */
12606                                         ins->sreg1 = cmp->sreg1;
12607                                         ins->sreg2 = cmp->sreg2;
12608                                         NULLIFY_INS (cmp);
12609                                 }
12610                                 MONO_ADD_INS (cfg->cbb, ins);
12611                                 *sp++ = ins;
12612                                 ip += 2;
12613                                 break;
12614                         }
12615                         case CEE_LDFTN: {
12616                                 MonoInst *argconst;
12617                                 MonoMethod *cil_method;
12618
12619                                 CHECK_STACK_OVF (1);
12620                                 CHECK_OPSIZE (6);
12621                                 n = read32 (ip + 2);
12622                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
12623                                 if (!cmethod || mono_loader_get_last_error ())
12624                                         LOAD_ERROR;
12625                                 mono_class_init (cmethod->klass);
12626
12627                                 mono_save_token_info (cfg, image, n, cmethod);
12628
12629                                 context_used = mini_method_check_context_used (cfg, cmethod);
12630
12631                                 cil_method = cmethod;
12632                                 if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
12633                                         METHOD_ACCESS_FAILURE (method, cil_method);
12634
12635                                 if (mono_security_core_clr_enabled ())
12636                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
12637
12638                                 /* 
12639                                  * Optimize the common case of ldftn+delegate creation
12640                                  */
12641                                 if ((sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 6) && (ip [6] == CEE_NEWOBJ)) {
12642                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
12643                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
12644                                                 MonoInst *target_ins, *handle_ins;
12645                                                 MonoMethod *invoke;
12646                                                 int invoke_context_used;
12647
12648                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
12649                                                 if (!invoke || !mono_method_signature (invoke))
12650                                                         LOAD_ERROR;
12651
12652                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
12653
12654                                                 target_ins = sp [-1];
12655
12656                                                 if (mono_security_core_clr_enabled ())
12657                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
12658
12659                                                 if (!(cmethod->flags & METHOD_ATTRIBUTE_STATIC)) {
12660                                                         /*LAME IMPL: We must not add a null check for virtual invoke delegates.*/
12661                                                         if (mono_method_signature (invoke)->param_count == mono_method_signature (cmethod)->param_count) {
12662                                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, target_ins->dreg, 0);
12663                                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "ArgumentException");
12664                                                         }
12665                                                 }
12666
12667                                                 /* FIXME: SGEN support */
12668                                                 if (invoke_context_used == 0) {
12669                                                         ip += 6;
12670                                                         if (cfg->verbose_level > 3)
12671                                                                 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));
12672                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, FALSE))) {
12673                                                                 sp --;
12674                                                                 *sp = handle_ins;
12675                                                                 CHECK_CFG_EXCEPTION;
12676                                                                 ip += 5;
12677                                                                 sp ++;
12678                                                                 break;
12679                                                         }
12680                                                         ip -= 6;
12681                                                 }
12682                                         }
12683                                 }
12684
12685                                 argconst = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD);
12686                                 ins = mono_emit_jit_icall (cfg, mono_ldftn, &argconst);
12687                                 *sp++ = ins;
12688                                 
12689                                 ip += 6;
12690                                 inline_costs += 10 * num_calls++;
12691                                 break;
12692                         }
12693                         case CEE_LDVIRTFTN: {
12694                                 MonoInst *args [2];
12695
12696                                 CHECK_STACK (1);
12697                                 CHECK_OPSIZE (6);
12698                                 n = read32 (ip + 2);
12699                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
12700                                 if (!cmethod || mono_loader_get_last_error ())
12701                                         LOAD_ERROR;
12702                                 mono_class_init (cmethod->klass);
12703  
12704                                 context_used = mini_method_check_context_used (cfg, cmethod);
12705
12706                                 if (mono_security_core_clr_enabled ())
12707                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
12708
12709                                 /*
12710                                  * Optimize the common case of ldvirtftn+delegate creation
12711                                  */
12712                                 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)) {
12713                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
12714                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
12715                                                 MonoInst *target_ins, *handle_ins;
12716                                                 MonoMethod *invoke;
12717                                                 int invoke_context_used;
12718                                                 gboolean is_virtual = cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL;
12719
12720                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
12721                                                 if (!invoke || !mono_method_signature (invoke))
12722                                                         LOAD_ERROR;
12723
12724                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
12725
12726                                                 target_ins = sp [-1];
12727
12728                                                 if (mono_security_core_clr_enabled ())
12729                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
12730
12731                                                 /* FIXME: SGEN support */
12732                                                 if (invoke_context_used == 0 || cfg->llvm_only) {
12733                                                         ip += 6;
12734                                                         if (cfg->verbose_level > 3)
12735                                                                 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));
12736                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, is_virtual))) {
12737                                                                 sp -= 2;
12738                                                                 *sp = handle_ins;
12739                                                                 CHECK_CFG_EXCEPTION;
12740                                                                 ip += 5;
12741                                                                 sp ++;
12742                                                                 break;
12743                                                         }
12744                                                         ip -= 6;
12745                                                 }
12746                                         }
12747                                 }
12748
12749                                 --sp;
12750                                 args [0] = *sp;
12751
12752                                 args [1] = emit_get_rgctx_method (cfg, context_used,
12753                                                                                                   cmethod, MONO_RGCTX_INFO_METHOD);
12754
12755                                 if (context_used)
12756                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn_gshared, args);
12757                                 else
12758                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn, args);
12759
12760                                 ip += 6;
12761                                 inline_costs += 10 * num_calls++;
12762                                 break;
12763                         }
12764                         case CEE_LDARG:
12765                                 CHECK_STACK_OVF (1);
12766                                 CHECK_OPSIZE (4);
12767                                 n = read16 (ip + 2);
12768                                 CHECK_ARG (n);
12769                                 EMIT_NEW_ARGLOAD (cfg, ins, n);
12770                                 *sp++ = ins;
12771                                 ip += 4;
12772                                 break;
12773                         case CEE_LDARGA:
12774                                 CHECK_STACK_OVF (1);
12775                                 CHECK_OPSIZE (4);
12776                                 n = read16 (ip + 2);
12777                                 CHECK_ARG (n);
12778                                 NEW_ARGLOADA (cfg, ins, n);
12779                                 MONO_ADD_INS (cfg->cbb, ins);
12780                                 *sp++ = ins;
12781                                 ip += 4;
12782                                 break;
12783                         case CEE_STARG:
12784                                 CHECK_STACK (1);
12785                                 --sp;
12786                                 CHECK_OPSIZE (4);
12787                                 n = read16 (ip + 2);
12788                                 CHECK_ARG (n);
12789                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
12790                                         UNVERIFIED;
12791                                 EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
12792                                 ip += 4;
12793                                 break;
12794                         case CEE_LDLOC:
12795                                 CHECK_STACK_OVF (1);
12796                                 CHECK_OPSIZE (4);
12797                                 n = read16 (ip + 2);
12798                                 CHECK_LOCAL (n);
12799                                 EMIT_NEW_LOCLOAD (cfg, ins, n);
12800                                 *sp++ = ins;
12801                                 ip += 4;
12802                                 break;
12803                         case CEE_LDLOCA: {
12804                                 unsigned char *tmp_ip;
12805                                 CHECK_STACK_OVF (1);
12806                                 CHECK_OPSIZE (4);
12807                                 n = read16 (ip + 2);
12808                                 CHECK_LOCAL (n);
12809
12810                                 if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 2))) {
12811                                         ip = tmp_ip;
12812                                         inline_costs += 1;
12813                                         break;
12814                                 }                       
12815                                 
12816                                 EMIT_NEW_LOCLOADA (cfg, ins, n);
12817                                 *sp++ = ins;
12818                                 ip += 4;
12819                                 break;
12820                         }
12821                         case CEE_STLOC:
12822                                 CHECK_STACK (1);
12823                                 --sp;
12824                                 CHECK_OPSIZE (4);
12825                                 n = read16 (ip + 2);
12826                                 CHECK_LOCAL (n);
12827                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
12828                                         UNVERIFIED;
12829                                 emit_stloc_ir (cfg, sp, header, n);
12830                                 ip += 4;
12831                                 inline_costs += 1;
12832                                 break;
12833                         case CEE_LOCALLOC:
12834                                 CHECK_STACK (1);
12835                                 --sp;
12836                                 if (sp != stack_start) 
12837                                         UNVERIFIED;
12838                                 if (cfg->method != method) 
12839                                         /* 
12840                                          * Inlining this into a loop in a parent could lead to 
12841                                          * stack overflows which is different behavior than the
12842                                          * non-inlined case, thus disable inlining in this case.
12843                                          */
12844                                         INLINE_FAILURE("localloc");
12845
12846                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
12847                                 ins->dreg = alloc_preg (cfg);
12848                                 ins->sreg1 = sp [0]->dreg;
12849                                 ins->type = STACK_PTR;
12850                                 MONO_ADD_INS (cfg->cbb, ins);
12851
12852                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12853                                 if (init_locals)
12854                                         ins->flags |= MONO_INST_INIT;
12855
12856                                 *sp++ = ins;
12857                                 ip += 2;
12858                                 break;
12859                         case CEE_ENDFILTER: {
12860                                 MonoExceptionClause *clause, *nearest;
12861                                 int cc;
12862
12863                                 CHECK_STACK (1);
12864                                 --sp;
12865                                 if ((sp != stack_start) || (sp [0]->type != STACK_I4)) 
12866                                         UNVERIFIED;
12867                                 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
12868                                 ins->sreg1 = (*sp)->dreg;
12869                                 MONO_ADD_INS (cfg->cbb, ins);
12870                                 start_new_bblock = 1;
12871                                 ip += 2;
12872
12873                                 nearest = NULL;
12874                                 for (cc = 0; cc < header->num_clauses; ++cc) {
12875                                         clause = &header->clauses [cc];
12876                                         if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
12877                                                 ((ip - header->code) > clause->data.filter_offset && (ip - header->code) <= clause->handler_offset) &&
12878                                             (!nearest || (clause->data.filter_offset < nearest->data.filter_offset)))
12879                                                 nearest = clause;
12880                                 }
12881                                 g_assert (nearest);
12882                                 if ((ip - header->code) != nearest->handler_offset)
12883                                         UNVERIFIED;
12884
12885                                 break;
12886                         }
12887                         case CEE_UNALIGNED_:
12888                                 ins_flag |= MONO_INST_UNALIGNED;
12889                                 /* FIXME: record alignment? we can assume 1 for now */
12890                                 CHECK_OPSIZE (3);
12891                                 ip += 3;
12892                                 break;
12893                         case CEE_VOLATILE_:
12894                                 ins_flag |= MONO_INST_VOLATILE;
12895                                 ip += 2;
12896                                 break;
12897                         case CEE_TAIL_:
12898                                 ins_flag   |= MONO_INST_TAILCALL;
12899                                 cfg->flags |= MONO_CFG_HAS_TAIL;
12900                                 /* Can't inline tail calls at this time */
12901                                 inline_costs += 100000;
12902                                 ip += 2;
12903                                 break;
12904                         case CEE_INITOBJ:
12905                                 CHECK_STACK (1);
12906                                 --sp;
12907                                 CHECK_OPSIZE (6);
12908                                 token = read32 (ip + 2);
12909                                 klass = mini_get_class (method, token, generic_context);
12910                                 CHECK_TYPELOAD (klass);
12911                                 if (generic_class_is_reference_type (cfg, klass))
12912                                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, sp [0]->dreg, 0, 0);
12913                                 else
12914                                         mini_emit_initobj (cfg, *sp, NULL, klass);
12915                                 ip += 6;
12916                                 inline_costs += 1;
12917                                 break;
12918                         case CEE_CONSTRAINED_:
12919                                 CHECK_OPSIZE (6);
12920                                 token = read32 (ip + 2);
12921                                 constrained_class = mini_get_class (method, token, generic_context);
12922                                 CHECK_TYPELOAD (constrained_class);
12923                                 ip += 6;
12924                                 break;
12925                         case CEE_CPBLK:
12926                         case CEE_INITBLK: {
12927                                 MonoInst *iargs [3];
12928                                 CHECK_STACK (3);
12929                                 sp -= 3;
12930
12931                                 /* Skip optimized paths for volatile operations. */
12932                                 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)) {
12933                                         mini_emit_memcpy (cfg, sp [0]->dreg, 0, sp [1]->dreg, 0, sp [2]->inst_c0, 0);
12934                                 } 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)) {
12935                                         /* emit_memset only works when val == 0 */
12936                                         mini_emit_memset (cfg, sp [0]->dreg, 0, sp [2]->inst_c0, sp [1]->inst_c0, 0);
12937                                 } else {
12938                                         MonoInst *call;
12939                                         iargs [0] = sp [0];
12940                                         iargs [1] = sp [1];
12941                                         iargs [2] = sp [2];
12942                                         if (ip [1] == CEE_CPBLK) {
12943                                                 /*
12944                                                  * FIXME: It's unclear whether we should be emitting both the acquire
12945                                                  * and release barriers for cpblk. It is technically both a load and
12946                                                  * store operation, so it seems like that's the sensible thing to do.
12947                                                  *
12948                                                  * FIXME: We emit full barriers on both sides of the operation for
12949                                                  * simplicity. We should have a separate atomic memcpy method instead.
12950                                                  */
12951                                                 MonoMethod *memcpy_method = get_memcpy_method ();
12952
12953                                                 if (ins_flag & MONO_INST_VOLATILE)
12954                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
12955
12956                                                 call = mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
12957                                                 call->flags |= ins_flag;
12958
12959                                                 if (ins_flag & MONO_INST_VOLATILE)
12960                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
12961                                         } else {
12962                                                 MonoMethod *memset_method = get_memset_method ();
12963                                                 if (ins_flag & MONO_INST_VOLATILE) {
12964                                                         /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
12965                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
12966                                                 }
12967                                                 call = mono_emit_method_call (cfg, memset_method, iargs, NULL);
12968                                                 call->flags |= ins_flag;
12969                                         }
12970                                 }
12971                                 ip += 2;
12972                                 ins_flag = 0;
12973                                 inline_costs += 1;
12974                                 break;
12975                         }
12976                         case CEE_NO_:
12977                                 CHECK_OPSIZE (3);
12978                                 if (ip [2] & 0x1)
12979                                         ins_flag |= MONO_INST_NOTYPECHECK;
12980                                 if (ip [2] & 0x2)
12981                                         ins_flag |= MONO_INST_NORANGECHECK;
12982                                 /* we ignore the no-nullcheck for now since we
12983                                  * really do it explicitly only when doing callvirt->call
12984                                  */
12985                                 ip += 3;
12986                                 break;
12987                         case CEE_RETHROW: {
12988                                 MonoInst *load;
12989                                 int handler_offset = -1;
12990
12991                                 for (i = 0; i < header->num_clauses; ++i) {
12992                                         MonoExceptionClause *clause = &header->clauses [i];
12993                                         if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
12994                                                 handler_offset = clause->handler_offset;
12995                                                 break;
12996                                         }
12997                                 }
12998
12999                                 cfg->cbb->flags |= BB_EXCEPTION_UNSAFE;
13000
13001                                 if (handler_offset == -1)
13002                                         UNVERIFIED;
13003
13004                                 EMIT_NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
13005                                 MONO_INST_NEW (cfg, ins, OP_RETHROW);
13006                                 ins->sreg1 = load->dreg;
13007                                 MONO_ADD_INS (cfg->cbb, ins);
13008
13009                                 MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
13010                                 MONO_ADD_INS (cfg->cbb, ins);
13011
13012                                 sp = stack_start;
13013                                 link_bblock (cfg, cfg->cbb, end_bblock);
13014                                 start_new_bblock = 1;
13015                                 ip += 2;
13016                                 break;
13017                         }
13018                         case CEE_SIZEOF: {
13019                                 guint32 val;
13020                                 int ialign;
13021
13022                                 CHECK_STACK_OVF (1);
13023                                 CHECK_OPSIZE (6);
13024                                 token = read32 (ip + 2);
13025                                 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC && !image_is_dynamic (method->klass->image) && !generic_context) {
13026                                         MonoType *type = mono_type_create_from_typespec_checked (image, token, &cfg->error);
13027                                         CHECK_CFG_ERROR;
13028
13029                                         val = mono_type_size (type, &ialign);
13030                                 } else {
13031                                         MonoClass *klass = mini_get_class (method, token, generic_context);
13032                                         CHECK_TYPELOAD (klass);
13033
13034                                         val = mono_type_size (&klass->byval_arg, &ialign);
13035
13036                                         if (mini_is_gsharedvt_klass (klass))
13037                                                 GSHAREDVT_FAILURE (*ip);
13038                                 }
13039                                 EMIT_NEW_ICONST (cfg, ins, val);
13040                                 *sp++= ins;
13041                                 ip += 6;
13042                                 break;
13043                         }
13044                         case CEE_REFANYTYPE: {
13045                                 MonoInst *src_var, *src;
13046
13047                                 GSHAREDVT_FAILURE (*ip);
13048
13049                                 CHECK_STACK (1);
13050                                 --sp;
13051
13052                                 // FIXME:
13053                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
13054                                 if (!src_var)
13055                                         src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
13056                                 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
13057                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &mono_defaults.typehandle_class->byval_arg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type));
13058                                 *sp++ = ins;
13059                                 ip += 2;
13060                                 break;
13061                         }
13062                         case CEE_READONLY_:
13063                                 readonly = TRUE;
13064                                 ip += 2;
13065                                 break;
13066
13067                         case CEE_UNUSED56:
13068                         case CEE_UNUSED57:
13069                         case CEE_UNUSED70:
13070                         case CEE_UNUSED:
13071                         case CEE_UNUSED99:
13072                                 UNVERIFIED;
13073                                 
13074                         default:
13075                                 g_warning ("opcode 0xfe 0x%02x not handled", ip [1]);
13076                                 UNVERIFIED;
13077                         }
13078                         break;
13079                 }
13080                 case CEE_UNUSED58:
13081                 case CEE_UNUSED1:
13082                         UNVERIFIED;
13083
13084                 default:
13085                         g_warning ("opcode 0x%02x not handled", *ip);
13086                         UNVERIFIED;
13087                 }
13088         }
13089         if (start_new_bblock != 1)
13090                 UNVERIFIED;
13091
13092         cfg->cbb->cil_length = ip - cfg->cbb->cil_code;
13093         if (cfg->cbb->next_bb) {
13094                 /* This could already be set because of inlining, #693905 */
13095                 MonoBasicBlock *bb = cfg->cbb;
13096
13097                 while (bb->next_bb)
13098                         bb = bb->next_bb;
13099                 bb->next_bb = end_bblock;
13100         } else {
13101                 cfg->cbb->next_bb = end_bblock;
13102         }
13103
13104         if (cfg->method == method && cfg->domainvar) {
13105                 MonoInst *store;
13106                 MonoInst *get_domain;
13107
13108                 cfg->cbb = init_localsbb;
13109
13110                 if ((get_domain = mono_get_domain_intrinsic (cfg))) {
13111                         MONO_ADD_INS (cfg->cbb, get_domain);
13112                 } else {
13113                         get_domain = mono_emit_jit_icall (cfg, mono_domain_get, NULL);
13114                 }
13115                 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, get_domain);
13116                 MONO_ADD_INS (cfg->cbb, store);
13117         }
13118
13119 #if defined(TARGET_POWERPC) || defined(TARGET_X86)
13120         if (cfg->compile_aot)
13121                 /* FIXME: The plt slots require a GOT var even if the method doesn't use it */
13122                 mono_get_got_var (cfg);
13123 #endif
13124
13125         if (cfg->method == method && cfg->got_var)
13126                 mono_emit_load_got_addr (cfg);
13127
13128         if (init_localsbb) {
13129                 cfg->cbb = init_localsbb;
13130                 cfg->ip = NULL;
13131                 for (i = 0; i < header->num_locals; ++i) {
13132                         emit_init_local (cfg, i, header->locals [i], init_locals);
13133                 }
13134         }
13135
13136         if (cfg->init_ref_vars && cfg->method == method) {
13137                 /* Emit initialization for ref vars */
13138                 // FIXME: Avoid duplication initialization for IL locals.
13139                 for (i = 0; i < cfg->num_varinfo; ++i) {
13140                         MonoInst *ins = cfg->varinfo [i];
13141
13142                         if (ins->opcode == OP_LOCAL && ins->type == STACK_OBJ)
13143                                 MONO_EMIT_NEW_PCONST (cfg, ins->dreg, NULL);
13144                 }
13145         }
13146
13147         if (cfg->lmf_var && cfg->method == method && !cfg->llvm_only) {
13148                 cfg->cbb = init_localsbb;
13149                 emit_push_lmf (cfg);
13150         }
13151
13152         cfg->cbb = init_localsbb;
13153         emit_instrumentation_call (cfg, mono_profiler_method_enter);
13154
13155         if (seq_points) {
13156                 MonoBasicBlock *bb;
13157
13158                 /*
13159                  * Make seq points at backward branch targets interruptable.
13160                  */
13161                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
13162                         if (bb->code && bb->in_count > 1 && bb->code->opcode == OP_SEQ_POINT)
13163                                 bb->code->flags |= MONO_INST_SINGLE_STEP_LOC;
13164         }
13165
13166         /* Add a sequence point for method entry/exit events */
13167         if (seq_points && cfg->gen_sdb_seq_points) {
13168                 NEW_SEQ_POINT (cfg, ins, METHOD_ENTRY_IL_OFFSET, FALSE);
13169                 MONO_ADD_INS (init_localsbb, ins);
13170                 NEW_SEQ_POINT (cfg, ins, METHOD_EXIT_IL_OFFSET, FALSE);
13171                 MONO_ADD_INS (cfg->bb_exit, ins);
13172         }
13173
13174         /*
13175          * Add seq points for IL offsets which have line number info, but wasn't generated a seq point during JITting because
13176          * the code they refer to was dead (#11880).
13177          */
13178         if (sym_seq_points) {
13179                 for (i = 0; i < header->code_size; ++i) {
13180                         if (mono_bitset_test_fast (seq_point_locs, i) && !mono_bitset_test_fast (seq_point_set_locs, i)) {
13181                                 MonoInst *ins;
13182
13183                                 NEW_SEQ_POINT (cfg, ins, i, FALSE);
13184                                 mono_add_seq_point (cfg, NULL, ins, SEQ_POINT_NATIVE_OFFSET_DEAD_CODE);
13185                         }
13186                 }
13187         }
13188
13189         cfg->ip = NULL;
13190
13191         if (cfg->method == method) {
13192                 MonoBasicBlock *bb;
13193                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13194                         bb->region = mono_find_block_region (cfg, bb->real_offset);
13195                         if (cfg->spvars)
13196                                 mono_create_spvar_for_region (cfg, bb->region);
13197                         if (cfg->verbose_level > 2)
13198                                 printf ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
13199                 }
13200         }
13201
13202         if (inline_costs < 0) {
13203                 char *mname;
13204
13205                 /* Method is too large */
13206                 mname = mono_method_full_name (method, TRUE);
13207                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
13208                 cfg->exception_message = g_strdup_printf ("Method %s is too complex.", mname);
13209                 g_free (mname);
13210         }
13211
13212         if ((cfg->verbose_level > 2) && (cfg->method == method)) 
13213                 mono_print_code (cfg, "AFTER METHOD-TO-IR");
13214
13215         goto cleanup;
13216
13217 mono_error_exit:
13218         g_assert (!mono_error_ok (&cfg->error));
13219         goto cleanup;
13220  
13221  exception_exit:
13222         g_assert (cfg->exception_type != MONO_EXCEPTION_NONE);
13223         goto cleanup;
13224
13225  unverified:
13226         set_exception_type_from_invalid_il (cfg, method, ip);
13227         goto cleanup;
13228
13229  cleanup:
13230         g_slist_free (class_inits);
13231         mono_basic_block_free (original_bb);
13232         cfg->dont_inline = g_list_remove (cfg->dont_inline, method);
13233         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
13234         if (cfg->exception_type)
13235                 return -1;
13236         else
13237                 return inline_costs;
13238 }
13239
13240 static int
13241 store_membase_reg_to_store_membase_imm (int opcode)
13242 {
13243         switch (opcode) {
13244         case OP_STORE_MEMBASE_REG:
13245                 return OP_STORE_MEMBASE_IMM;
13246         case OP_STOREI1_MEMBASE_REG:
13247                 return OP_STOREI1_MEMBASE_IMM;
13248         case OP_STOREI2_MEMBASE_REG:
13249                 return OP_STOREI2_MEMBASE_IMM;
13250         case OP_STOREI4_MEMBASE_REG:
13251                 return OP_STOREI4_MEMBASE_IMM;
13252         case OP_STOREI8_MEMBASE_REG:
13253                 return OP_STOREI8_MEMBASE_IMM;
13254         default:
13255                 g_assert_not_reached ();
13256         }
13257
13258         return -1;
13259 }               
13260
13261 int
13262 mono_op_to_op_imm (int opcode)
13263 {
13264         switch (opcode) {
13265         case OP_IADD:
13266                 return OP_IADD_IMM;
13267         case OP_ISUB:
13268                 return OP_ISUB_IMM;
13269         case OP_IDIV:
13270                 return OP_IDIV_IMM;
13271         case OP_IDIV_UN:
13272                 return OP_IDIV_UN_IMM;
13273         case OP_IREM:
13274                 return OP_IREM_IMM;
13275         case OP_IREM_UN:
13276                 return OP_IREM_UN_IMM;
13277         case OP_IMUL:
13278                 return OP_IMUL_IMM;
13279         case OP_IAND:
13280                 return OP_IAND_IMM;
13281         case OP_IOR:
13282                 return OP_IOR_IMM;
13283         case OP_IXOR:
13284                 return OP_IXOR_IMM;
13285         case OP_ISHL:
13286                 return OP_ISHL_IMM;
13287         case OP_ISHR:
13288                 return OP_ISHR_IMM;
13289         case OP_ISHR_UN:
13290                 return OP_ISHR_UN_IMM;
13291
13292         case OP_LADD:
13293                 return OP_LADD_IMM;
13294         case OP_LSUB:
13295                 return OP_LSUB_IMM;
13296         case OP_LAND:
13297                 return OP_LAND_IMM;
13298         case OP_LOR:
13299                 return OP_LOR_IMM;
13300         case OP_LXOR:
13301                 return OP_LXOR_IMM;
13302         case OP_LSHL:
13303                 return OP_LSHL_IMM;
13304         case OP_LSHR:
13305                 return OP_LSHR_IMM;
13306         case OP_LSHR_UN:
13307                 return OP_LSHR_UN_IMM;
13308 #if SIZEOF_REGISTER == 8
13309         case OP_LREM:
13310                 return OP_LREM_IMM;
13311 #endif
13312
13313         case OP_COMPARE:
13314                 return OP_COMPARE_IMM;
13315         case OP_ICOMPARE:
13316                 return OP_ICOMPARE_IMM;
13317         case OP_LCOMPARE:
13318                 return OP_LCOMPARE_IMM;
13319
13320         case OP_STORE_MEMBASE_REG:
13321                 return OP_STORE_MEMBASE_IMM;
13322         case OP_STOREI1_MEMBASE_REG:
13323                 return OP_STOREI1_MEMBASE_IMM;
13324         case OP_STOREI2_MEMBASE_REG:
13325                 return OP_STOREI2_MEMBASE_IMM;
13326         case OP_STOREI4_MEMBASE_REG:
13327                 return OP_STOREI4_MEMBASE_IMM;
13328
13329 #if defined(TARGET_X86) || defined (TARGET_AMD64)
13330         case OP_X86_PUSH:
13331                 return OP_X86_PUSH_IMM;
13332         case OP_X86_COMPARE_MEMBASE_REG:
13333                 return OP_X86_COMPARE_MEMBASE_IMM;
13334 #endif
13335 #if defined(TARGET_AMD64)
13336         case OP_AMD64_ICOMPARE_MEMBASE_REG:
13337                 return OP_AMD64_ICOMPARE_MEMBASE_IMM;
13338 #endif
13339         case OP_VOIDCALL_REG:
13340                 return OP_VOIDCALL;
13341         case OP_CALL_REG:
13342                 return OP_CALL;
13343         case OP_LCALL_REG:
13344                 return OP_LCALL;
13345         case OP_FCALL_REG:
13346                 return OP_FCALL;
13347         case OP_LOCALLOC:
13348                 return OP_LOCALLOC_IMM;
13349         }
13350
13351         return -1;
13352 }
13353
13354 static int
13355 ldind_to_load_membase (int opcode)
13356 {
13357         switch (opcode) {
13358         case CEE_LDIND_I1:
13359                 return OP_LOADI1_MEMBASE;
13360         case CEE_LDIND_U1:
13361                 return OP_LOADU1_MEMBASE;
13362         case CEE_LDIND_I2:
13363                 return OP_LOADI2_MEMBASE;
13364         case CEE_LDIND_U2:
13365                 return OP_LOADU2_MEMBASE;
13366         case CEE_LDIND_I4:
13367                 return OP_LOADI4_MEMBASE;
13368         case CEE_LDIND_U4:
13369                 return OP_LOADU4_MEMBASE;
13370         case CEE_LDIND_I:
13371                 return OP_LOAD_MEMBASE;
13372         case CEE_LDIND_REF:
13373                 return OP_LOAD_MEMBASE;
13374         case CEE_LDIND_I8:
13375                 return OP_LOADI8_MEMBASE;
13376         case CEE_LDIND_R4:
13377                 return OP_LOADR4_MEMBASE;
13378         case CEE_LDIND_R8:
13379                 return OP_LOADR8_MEMBASE;
13380         default:
13381                 g_assert_not_reached ();
13382         }
13383
13384         return -1;
13385 }
13386
13387 static int
13388 stind_to_store_membase (int opcode)
13389 {
13390         switch (opcode) {
13391         case CEE_STIND_I1:
13392                 return OP_STOREI1_MEMBASE_REG;
13393         case CEE_STIND_I2:
13394                 return OP_STOREI2_MEMBASE_REG;
13395         case CEE_STIND_I4:
13396                 return OP_STOREI4_MEMBASE_REG;
13397         case CEE_STIND_I:
13398         case CEE_STIND_REF:
13399                 return OP_STORE_MEMBASE_REG;
13400         case CEE_STIND_I8:
13401                 return OP_STOREI8_MEMBASE_REG;
13402         case CEE_STIND_R4:
13403                 return OP_STORER4_MEMBASE_REG;
13404         case CEE_STIND_R8:
13405                 return OP_STORER8_MEMBASE_REG;
13406         default:
13407                 g_assert_not_reached ();
13408         }
13409
13410         return -1;
13411 }
13412
13413 int
13414 mono_load_membase_to_load_mem (int opcode)
13415 {
13416         // FIXME: Add a MONO_ARCH_HAVE_LOAD_MEM macro
13417 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13418         switch (opcode) {
13419         case OP_LOAD_MEMBASE:
13420                 return OP_LOAD_MEM;
13421         case OP_LOADU1_MEMBASE:
13422                 return OP_LOADU1_MEM;
13423         case OP_LOADU2_MEMBASE:
13424                 return OP_LOADU2_MEM;
13425         case OP_LOADI4_MEMBASE:
13426                 return OP_LOADI4_MEM;
13427         case OP_LOADU4_MEMBASE:
13428                 return OP_LOADU4_MEM;
13429 #if SIZEOF_REGISTER == 8
13430         case OP_LOADI8_MEMBASE:
13431                 return OP_LOADI8_MEM;
13432 #endif
13433         }
13434 #endif
13435
13436         return -1;
13437 }
13438
13439 static inline int
13440 op_to_op_dest_membase (int store_opcode, int opcode)
13441 {
13442 #if defined(TARGET_X86)
13443         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG)))
13444                 return -1;
13445
13446         switch (opcode) {
13447         case OP_IADD:
13448                 return OP_X86_ADD_MEMBASE_REG;
13449         case OP_ISUB:
13450                 return OP_X86_SUB_MEMBASE_REG;
13451         case OP_IAND:
13452                 return OP_X86_AND_MEMBASE_REG;
13453         case OP_IOR:
13454                 return OP_X86_OR_MEMBASE_REG;
13455         case OP_IXOR:
13456                 return OP_X86_XOR_MEMBASE_REG;
13457         case OP_ADD_IMM:
13458         case OP_IADD_IMM:
13459                 return OP_X86_ADD_MEMBASE_IMM;
13460         case OP_SUB_IMM:
13461         case OP_ISUB_IMM:
13462                 return OP_X86_SUB_MEMBASE_IMM;
13463         case OP_AND_IMM:
13464         case OP_IAND_IMM:
13465                 return OP_X86_AND_MEMBASE_IMM;
13466         case OP_OR_IMM:
13467         case OP_IOR_IMM:
13468                 return OP_X86_OR_MEMBASE_IMM;
13469         case OP_XOR_IMM:
13470         case OP_IXOR_IMM:
13471                 return OP_X86_XOR_MEMBASE_IMM;
13472         case OP_MOVE:
13473                 return OP_NOP;
13474         }
13475 #endif
13476
13477 #if defined(TARGET_AMD64)
13478         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG) || (store_opcode == OP_STOREI8_MEMBASE_REG)))
13479                 return -1;
13480
13481         switch (opcode) {
13482         case OP_IADD:
13483                 return OP_X86_ADD_MEMBASE_REG;
13484         case OP_ISUB:
13485                 return OP_X86_SUB_MEMBASE_REG;
13486         case OP_IAND:
13487                 return OP_X86_AND_MEMBASE_REG;
13488         case OP_IOR:
13489                 return OP_X86_OR_MEMBASE_REG;
13490         case OP_IXOR:
13491                 return OP_X86_XOR_MEMBASE_REG;
13492         case OP_IADD_IMM:
13493                 return OP_X86_ADD_MEMBASE_IMM;
13494         case OP_ISUB_IMM:
13495                 return OP_X86_SUB_MEMBASE_IMM;
13496         case OP_IAND_IMM:
13497                 return OP_X86_AND_MEMBASE_IMM;
13498         case OP_IOR_IMM:
13499                 return OP_X86_OR_MEMBASE_IMM;
13500         case OP_IXOR_IMM:
13501                 return OP_X86_XOR_MEMBASE_IMM;
13502         case OP_LADD:
13503                 return OP_AMD64_ADD_MEMBASE_REG;
13504         case OP_LSUB:
13505                 return OP_AMD64_SUB_MEMBASE_REG;
13506         case OP_LAND:
13507                 return OP_AMD64_AND_MEMBASE_REG;
13508         case OP_LOR:
13509                 return OP_AMD64_OR_MEMBASE_REG;
13510         case OP_LXOR:
13511                 return OP_AMD64_XOR_MEMBASE_REG;
13512         case OP_ADD_IMM:
13513         case OP_LADD_IMM:
13514                 return OP_AMD64_ADD_MEMBASE_IMM;
13515         case OP_SUB_IMM:
13516         case OP_LSUB_IMM:
13517                 return OP_AMD64_SUB_MEMBASE_IMM;
13518         case OP_AND_IMM:
13519         case OP_LAND_IMM:
13520                 return OP_AMD64_AND_MEMBASE_IMM;
13521         case OP_OR_IMM:
13522         case OP_LOR_IMM:
13523                 return OP_AMD64_OR_MEMBASE_IMM;
13524         case OP_XOR_IMM:
13525         case OP_LXOR_IMM:
13526                 return OP_AMD64_XOR_MEMBASE_IMM;
13527         case OP_MOVE:
13528                 return OP_NOP;
13529         }
13530 #endif
13531
13532         return -1;
13533 }
13534
13535 static inline int
13536 op_to_op_store_membase (int store_opcode, int opcode)
13537 {
13538 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13539         switch (opcode) {
13540         case OP_ICEQ:
13541                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13542                         return OP_X86_SETEQ_MEMBASE;
13543         case OP_CNE:
13544                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13545                         return OP_X86_SETNE_MEMBASE;
13546         }
13547 #endif
13548
13549         return -1;
13550 }
13551
13552 static inline int
13553 op_to_op_src1_membase (int load_opcode, int opcode)
13554 {
13555 #ifdef TARGET_X86
13556         /* FIXME: This has sign extension issues */
13557         /*
13558         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
13559                 return OP_X86_COMPARE_MEMBASE8_IMM;
13560         */
13561
13562         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
13563                 return -1;
13564
13565         switch (opcode) {
13566         case OP_X86_PUSH:
13567                 return OP_X86_PUSH_MEMBASE;
13568         case OP_COMPARE_IMM:
13569         case OP_ICOMPARE_IMM:
13570                 return OP_X86_COMPARE_MEMBASE_IMM;
13571         case OP_COMPARE:
13572         case OP_ICOMPARE:
13573                 return OP_X86_COMPARE_MEMBASE_REG;
13574         }
13575 #endif
13576
13577 #ifdef TARGET_AMD64
13578         /* FIXME: This has sign extension issues */
13579         /*
13580         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
13581                 return OP_X86_COMPARE_MEMBASE8_IMM;
13582         */
13583
13584         switch (opcode) {
13585         case OP_X86_PUSH:
13586 #ifdef __mono_ilp32__
13587                 if (load_opcode == OP_LOADI8_MEMBASE)
13588 #else
13589                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
13590 #endif
13591                         return OP_X86_PUSH_MEMBASE;
13592                 break;
13593                 /* FIXME: This only works for 32 bit immediates
13594         case OP_COMPARE_IMM:
13595         case OP_LCOMPARE_IMM:
13596                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
13597                         return OP_AMD64_COMPARE_MEMBASE_IMM;
13598                 */
13599         case OP_ICOMPARE_IMM:
13600                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
13601                         return OP_AMD64_ICOMPARE_MEMBASE_IMM;
13602                 break;
13603         case OP_COMPARE:
13604         case OP_LCOMPARE:
13605 #ifdef __mono_ilp32__
13606                 if (load_opcode == OP_LOAD_MEMBASE)
13607                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
13608                 if (load_opcode == OP_LOADI8_MEMBASE)
13609 #else
13610                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
13611 #endif
13612                         return OP_AMD64_COMPARE_MEMBASE_REG;
13613                 break;
13614         case OP_ICOMPARE:
13615                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
13616                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
13617                 break;
13618         }
13619 #endif
13620
13621         return -1;
13622 }
13623
13624 static inline int
13625 op_to_op_src2_membase (int load_opcode, int opcode)
13626 {
13627 #ifdef TARGET_X86
13628         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
13629                 return -1;
13630         
13631         switch (opcode) {
13632         case OP_COMPARE:
13633         case OP_ICOMPARE:
13634                 return OP_X86_COMPARE_REG_MEMBASE;
13635         case OP_IADD:
13636                 return OP_X86_ADD_REG_MEMBASE;
13637         case OP_ISUB:
13638                 return OP_X86_SUB_REG_MEMBASE;
13639         case OP_IAND:
13640                 return OP_X86_AND_REG_MEMBASE;
13641         case OP_IOR:
13642                 return OP_X86_OR_REG_MEMBASE;
13643         case OP_IXOR:
13644                 return OP_X86_XOR_REG_MEMBASE;
13645         }
13646 #endif
13647
13648 #ifdef TARGET_AMD64
13649 #ifdef __mono_ilp32__
13650         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE) ) {
13651 #else
13652         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)) {
13653 #endif
13654                 switch (opcode) {
13655                 case OP_ICOMPARE:
13656                         return OP_AMD64_ICOMPARE_REG_MEMBASE;
13657                 case OP_IADD:
13658                         return OP_X86_ADD_REG_MEMBASE;
13659                 case OP_ISUB:
13660                         return OP_X86_SUB_REG_MEMBASE;
13661                 case OP_IAND:
13662                         return OP_X86_AND_REG_MEMBASE;
13663                 case OP_IOR:
13664                         return OP_X86_OR_REG_MEMBASE;
13665                 case OP_IXOR:
13666                         return OP_X86_XOR_REG_MEMBASE;
13667                 }
13668 #ifdef __mono_ilp32__
13669         } else if (load_opcode == OP_LOADI8_MEMBASE) {
13670 #else
13671         } else if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE)) {
13672 #endif
13673                 switch (opcode) {
13674                 case OP_COMPARE:
13675                 case OP_LCOMPARE:
13676                         return OP_AMD64_COMPARE_REG_MEMBASE;
13677                 case OP_LADD:
13678                         return OP_AMD64_ADD_REG_MEMBASE;
13679                 case OP_LSUB:
13680                         return OP_AMD64_SUB_REG_MEMBASE;
13681                 case OP_LAND:
13682                         return OP_AMD64_AND_REG_MEMBASE;
13683                 case OP_LOR:
13684                         return OP_AMD64_OR_REG_MEMBASE;
13685                 case OP_LXOR:
13686                         return OP_AMD64_XOR_REG_MEMBASE;
13687                 }
13688         }
13689 #endif
13690
13691         return -1;
13692 }
13693
13694 int
13695 mono_op_to_op_imm_noemul (int opcode)
13696 {
13697         switch (opcode) {
13698 #if SIZEOF_REGISTER == 4 && !defined(MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS)
13699         case OP_LSHR:
13700         case OP_LSHL:
13701         case OP_LSHR_UN:
13702                 return -1;
13703 #endif
13704 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
13705         case OP_IDIV:
13706         case OP_IDIV_UN:
13707         case OP_IREM:
13708         case OP_IREM_UN:
13709                 return -1;
13710 #endif
13711 #if defined(MONO_ARCH_EMULATE_MUL_DIV)
13712         case OP_IMUL:
13713                 return -1;
13714 #endif
13715         default:
13716                 return mono_op_to_op_imm (opcode);
13717         }
13718 }
13719
13720 /**
13721  * mono_handle_global_vregs:
13722  *
13723  *   Make vregs used in more than one bblock 'global', i.e. allocate a variable
13724  * for them.
13725  */
13726 void
13727 mono_handle_global_vregs (MonoCompile *cfg)
13728 {
13729         gint32 *vreg_to_bb;
13730         MonoBasicBlock *bb;
13731         int i, pos;
13732
13733         vreg_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (gint32*) * cfg->next_vreg + 1);
13734
13735 #ifdef MONO_ARCH_SIMD_INTRINSICS
13736         if (cfg->uses_simd_intrinsics)
13737                 mono_simd_simplify_indirection (cfg);
13738 #endif
13739
13740         /* Find local vregs used in more than one bb */
13741         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13742                 MonoInst *ins = bb->code;       
13743                 int block_num = bb->block_num;
13744
13745                 if (cfg->verbose_level > 2)
13746                         printf ("\nHANDLE-GLOBAL-VREGS BLOCK %d:\n", bb->block_num);
13747
13748                 cfg->cbb = bb;
13749                 for (; ins; ins = ins->next) {
13750                         const char *spec = INS_INFO (ins->opcode);
13751                         int regtype = 0, regindex;
13752                         gint32 prev_bb;
13753
13754                         if (G_UNLIKELY (cfg->verbose_level > 2))
13755                                 mono_print_ins (ins);
13756
13757                         g_assert (ins->opcode >= MONO_CEE_LAST);
13758
13759                         for (regindex = 0; regindex < 4; regindex ++) {
13760                                 int vreg = 0;
13761
13762                                 if (regindex == 0) {
13763                                         regtype = spec [MONO_INST_DEST];
13764                                         if (regtype == ' ')
13765                                                 continue;
13766                                         vreg = ins->dreg;
13767                                 } else if (regindex == 1) {
13768                                         regtype = spec [MONO_INST_SRC1];
13769                                         if (regtype == ' ')
13770                                                 continue;
13771                                         vreg = ins->sreg1;
13772                                 } else if (regindex == 2) {
13773                                         regtype = spec [MONO_INST_SRC2];
13774                                         if (regtype == ' ')
13775                                                 continue;
13776                                         vreg = ins->sreg2;
13777                                 } else if (regindex == 3) {
13778                                         regtype = spec [MONO_INST_SRC3];
13779                                         if (regtype == ' ')
13780                                                 continue;
13781                                         vreg = ins->sreg3;
13782                                 }
13783
13784 #if SIZEOF_REGISTER == 4
13785                                 /* In the LLVM case, the long opcodes are not decomposed */
13786                                 if (regtype == 'l' && !COMPILE_LLVM (cfg)) {
13787                                         /*
13788                                          * Since some instructions reference the original long vreg,
13789                                          * and some reference the two component vregs, it is quite hard
13790                                          * to determine when it needs to be global. So be conservative.
13791                                          */
13792                                         if (!get_vreg_to_inst (cfg, vreg)) {
13793                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
13794
13795                                                 if (cfg->verbose_level > 2)
13796                                                         printf ("LONG VREG R%d made global.\n", vreg);
13797                                         }
13798
13799                                         /*
13800                                          * Make the component vregs volatile since the optimizations can
13801                                          * get confused otherwise.
13802                                          */
13803                                         get_vreg_to_inst (cfg, vreg + 1)->flags |= MONO_INST_VOLATILE;
13804                                         get_vreg_to_inst (cfg, vreg + 2)->flags |= MONO_INST_VOLATILE;
13805                                 }
13806 #endif
13807
13808                                 g_assert (vreg != -1);
13809
13810                                 prev_bb = vreg_to_bb [vreg];
13811                                 if (prev_bb == 0) {
13812                                         /* 0 is a valid block num */
13813                                         vreg_to_bb [vreg] = block_num + 1;
13814                                 } else if ((prev_bb != block_num + 1) && (prev_bb != -1)) {
13815                                         if (((regtype == 'i' && (vreg < MONO_MAX_IREGS))) || (regtype == 'f' && (vreg < MONO_MAX_FREGS)))
13816                                                 continue;
13817
13818                                         if (!get_vreg_to_inst (cfg, vreg)) {
13819                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
13820                                                         printf ("VREG R%d used in BB%d and BB%d made global.\n", vreg, vreg_to_bb [vreg], block_num);
13821
13822                                                 switch (regtype) {
13823                                                 case 'i':
13824                                                         if (vreg_is_ref (cfg, vreg))
13825                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL, vreg);
13826                                                         else
13827                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL, vreg);
13828                                                         break;
13829                                                 case 'l':
13830                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
13831                                                         break;
13832                                                 case 'f':
13833                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL, vreg);
13834                                                         break;
13835                                                 case 'v':
13836                                                         mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, vreg);
13837                                                         break;
13838                                                 default:
13839                                                         g_assert_not_reached ();
13840                                                 }
13841                                         }
13842
13843                                         /* Flag as having been used in more than one bb */
13844                                         vreg_to_bb [vreg] = -1;
13845                                 }
13846                         }
13847                 }
13848         }
13849
13850         /* If a variable is used in only one bblock, convert it into a local vreg */
13851         for (i = 0; i < cfg->num_varinfo; i++) {
13852                 MonoInst *var = cfg->varinfo [i];
13853                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
13854
13855                 switch (var->type) {
13856                 case STACK_I4:
13857                 case STACK_OBJ:
13858                 case STACK_PTR:
13859                 case STACK_MP:
13860                 case STACK_VTYPE:
13861 #if SIZEOF_REGISTER == 8
13862                 case STACK_I8:
13863 #endif
13864 #if !defined(TARGET_X86)
13865                 /* Enabling this screws up the fp stack on x86 */
13866                 case STACK_R8:
13867 #endif
13868                         if (mono_arch_is_soft_float ())
13869                                 break;
13870
13871                         /* Arguments are implicitly global */
13872                         /* Putting R4 vars into registers doesn't work currently */
13873                         /* The gsharedvt vars are implicitly referenced by ldaddr opcodes, but those opcodes are only generated later */
13874                         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) {
13875                                 /* 
13876                                  * Make that the variable's liveness interval doesn't contain a call, since
13877                                  * that would cause the lvreg to be spilled, making the whole optimization
13878                                  * useless.
13879                                  */
13880                                 /* This is too slow for JIT compilation */
13881 #if 0
13882                                 if (cfg->compile_aot && vreg_to_bb [var->dreg]) {
13883                                         MonoInst *ins;
13884                                         int def_index, call_index, ins_index;
13885                                         gboolean spilled = FALSE;
13886
13887                                         def_index = -1;
13888                                         call_index = -1;
13889                                         ins_index = 0;
13890                                         for (ins = vreg_to_bb [var->dreg]->code; ins; ins = ins->next) {
13891                                                 const char *spec = INS_INFO (ins->opcode);
13892
13893                                                 if ((spec [MONO_INST_DEST] != ' ') && (ins->dreg == var->dreg))
13894                                                         def_index = ins_index;
13895
13896                                                 if (((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg)) ||
13897                                                         ((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg))) {
13898                                                         if (call_index > def_index) {
13899                                                                 spilled = TRUE;
13900                                                                 break;
13901                                                         }
13902                                                 }
13903
13904                                                 if (MONO_IS_CALL (ins))
13905                                                         call_index = ins_index;
13906
13907                                                 ins_index ++;
13908                                         }
13909
13910                                         if (spilled)
13911                                                 break;
13912                                 }
13913 #endif
13914
13915                                 if (G_UNLIKELY (cfg->verbose_level > 2))
13916                                         printf ("CONVERTED R%d(%d) TO VREG.\n", var->dreg, vmv->idx);
13917                                 var->flags |= MONO_INST_IS_DEAD;
13918                                 cfg->vreg_to_inst [var->dreg] = NULL;
13919                         }
13920                         break;
13921                 }
13922         }
13923
13924         /* 
13925          * Compress the varinfo and vars tables so the liveness computation is faster and
13926          * takes up less space.
13927          */
13928         pos = 0;
13929         for (i = 0; i < cfg->num_varinfo; ++i) {
13930                 MonoInst *var = cfg->varinfo [i];
13931                 if (pos < i && cfg->locals_start == i)
13932                         cfg->locals_start = pos;
13933                 if (!(var->flags & MONO_INST_IS_DEAD)) {
13934                         if (pos < i) {
13935                                 cfg->varinfo [pos] = cfg->varinfo [i];
13936                                 cfg->varinfo [pos]->inst_c0 = pos;
13937                                 memcpy (&cfg->vars [pos], &cfg->vars [i], sizeof (MonoMethodVar));
13938                                 cfg->vars [pos].idx = pos;
13939 #if SIZEOF_REGISTER == 4
13940                                 if (cfg->varinfo [pos]->type == STACK_I8) {
13941                                         /* Modify the two component vars too */
13942                                         MonoInst *var1;
13943
13944                                         var1 = get_vreg_to_inst (cfg, cfg->varinfo [pos]->dreg + 1);
13945                                         var1->inst_c0 = pos;
13946                                         var1 = get_vreg_to_inst (cfg, cfg->varinfo [pos]->dreg + 2);
13947                                         var1->inst_c0 = pos;
13948                                 }
13949 #endif
13950                         }
13951                         pos ++;
13952                 }
13953         }
13954         cfg->num_varinfo = pos;
13955         if (cfg->locals_start > cfg->num_varinfo)
13956                 cfg->locals_start = cfg->num_varinfo;
13957 }
13958
13959 /**
13960  * mono_spill_global_vars:
13961  *
13962  *   Generate spill code for variables which are not allocated to registers, 
13963  * and replace vregs with their allocated hregs. *need_local_opts is set to TRUE if
13964  * code is generated which could be optimized by the local optimization passes.
13965  */
13966 void
13967 mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
13968 {
13969         MonoBasicBlock *bb;
13970         char spec2 [16];
13971         int orig_next_vreg;
13972         guint32 *vreg_to_lvreg;
13973         guint32 *lvregs;
13974         guint32 i, lvregs_len;
13975         gboolean dest_has_lvreg = FALSE;
13976         guint32 stacktypes [128];
13977         MonoInst **live_range_start, **live_range_end;
13978         MonoBasicBlock **live_range_start_bb, **live_range_end_bb;
13979         int *gsharedvt_vreg_to_idx = NULL;
13980
13981         *need_local_opts = FALSE;
13982
13983         memset (spec2, 0, sizeof (spec2));
13984
13985         /* FIXME: Move this function to mini.c */
13986         stacktypes ['i'] = STACK_PTR;
13987         stacktypes ['l'] = STACK_I8;
13988         stacktypes ['f'] = STACK_R8;
13989 #ifdef MONO_ARCH_SIMD_INTRINSICS
13990         stacktypes ['x'] = STACK_VTYPE;
13991 #endif
13992
13993 #if SIZEOF_REGISTER == 4
13994         /* Create MonoInsts for longs */
13995         for (i = 0; i < cfg->num_varinfo; i++) {
13996                 MonoInst *ins = cfg->varinfo [i];
13997
13998                 if ((ins->opcode != OP_REGVAR) && !(ins->flags & MONO_INST_IS_DEAD)) {
13999                         switch (ins->type) {
14000                         case STACK_R8:
14001                         case STACK_I8: {
14002                                 MonoInst *tree;
14003
14004                                 if (ins->type == STACK_R8 && !COMPILE_SOFT_FLOAT (cfg))
14005                                         break;
14006
14007                                 g_assert (ins->opcode == OP_REGOFFSET);
14008
14009                                 tree = get_vreg_to_inst (cfg, ins->dreg + 1);
14010                                 g_assert (tree);
14011                                 tree->opcode = OP_REGOFFSET;
14012                                 tree->inst_basereg = ins->inst_basereg;
14013                                 tree->inst_offset = ins->inst_offset + MINI_LS_WORD_OFFSET;
14014
14015                                 tree = get_vreg_to_inst (cfg, ins->dreg + 2);
14016                                 g_assert (tree);
14017                                 tree->opcode = OP_REGOFFSET;
14018                                 tree->inst_basereg = ins->inst_basereg;
14019                                 tree->inst_offset = ins->inst_offset + MINI_MS_WORD_OFFSET;
14020                                 break;
14021                         }
14022                         default:
14023                                 break;
14024                         }
14025                 }
14026         }
14027 #endif
14028
14029         if (cfg->compute_gc_maps) {
14030                 /* registers need liveness info even for !non refs */
14031                 for (i = 0; i < cfg->num_varinfo; i++) {
14032                         MonoInst *ins = cfg->varinfo [i];
14033
14034                         if (ins->opcode == OP_REGVAR)
14035                                 ins->flags |= MONO_INST_GC_TRACK;
14036                 }
14037         }
14038
14039         if (cfg->gsharedvt) {
14040                 gsharedvt_vreg_to_idx = mono_mempool_alloc0 (cfg->mempool, sizeof (int) * cfg->next_vreg);
14041
14042                 for (i = 0; i < cfg->num_varinfo; ++i) {
14043                         MonoInst *ins = cfg->varinfo [i];
14044                         int idx;
14045
14046                         if (mini_is_gsharedvt_variable_type (ins->inst_vtype)) {
14047                                 if (i >= cfg->locals_start) {
14048                                         /* Local */
14049                                         idx = get_gsharedvt_info_slot (cfg, ins->inst_vtype, MONO_RGCTX_INFO_LOCAL_OFFSET);
14050                                         gsharedvt_vreg_to_idx [ins->dreg] = idx + 1;
14051                                         ins->opcode = OP_GSHAREDVT_LOCAL;
14052                                         ins->inst_imm = idx;
14053                                 } else {
14054                                         /* Arg */
14055                                         gsharedvt_vreg_to_idx [ins->dreg] = -1;
14056                                         ins->opcode = OP_GSHAREDVT_ARG_REGOFFSET;
14057                                 }
14058                         }
14059                 }
14060         }
14061                 
14062         /* FIXME: widening and truncation */
14063
14064         /*
14065          * As an optimization, when a variable allocated to the stack is first loaded into 
14066          * an lvreg, we will remember the lvreg and use it the next time instead of loading
14067          * the variable again.
14068          */
14069         orig_next_vreg = cfg->next_vreg;
14070         vreg_to_lvreg = mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * cfg->next_vreg);
14071         lvregs = mono_mempool_alloc (cfg->mempool, sizeof (guint32) * 1024);
14072         lvregs_len = 0;
14073
14074         /* 
14075          * These arrays contain the first and last instructions accessing a given
14076          * variable.
14077          * Since we emit bblocks in the same order we process them here, and we
14078          * don't split live ranges, these will precisely describe the live range of
14079          * the variable, i.e. the instruction range where a valid value can be found
14080          * in the variables location.
14081          * The live range is computed using the liveness info computed by the liveness pass.
14082          * We can't use vmv->range, since that is an abstract live range, and we need
14083          * one which is instruction precise.
14084          * FIXME: Variables used in out-of-line bblocks have a hole in their live range.
14085          */
14086         /* FIXME: Only do this if debugging info is requested */
14087         live_range_start = g_new0 (MonoInst*, cfg->next_vreg);
14088         live_range_end = g_new0 (MonoInst*, cfg->next_vreg);
14089         live_range_start_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
14090         live_range_end_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
14091         
14092         /* Add spill loads/stores */
14093         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
14094                 MonoInst *ins;
14095
14096                 if (cfg->verbose_level > 2)
14097                         printf ("\nSPILL BLOCK %d:\n", bb->block_num);
14098
14099                 /* Clear vreg_to_lvreg array */
14100                 for (i = 0; i < lvregs_len; i++)
14101                         vreg_to_lvreg [lvregs [i]] = 0;
14102                 lvregs_len = 0;
14103
14104                 cfg->cbb = bb;
14105                 MONO_BB_FOR_EACH_INS (bb, ins) {
14106                         const char *spec = INS_INFO (ins->opcode);
14107                         int regtype, srcindex, sreg, tmp_reg, prev_dreg, num_sregs;
14108                         gboolean store, no_lvreg;
14109                         int sregs [MONO_MAX_SRC_REGS];
14110
14111                         if (G_UNLIKELY (cfg->verbose_level > 2))
14112                                 mono_print_ins (ins);
14113
14114                         if (ins->opcode == OP_NOP)
14115                                 continue;
14116
14117                         /* 
14118                          * We handle LDADDR here as well, since it can only be decomposed
14119                          * when variable addresses are known.
14120                          */
14121                         if (ins->opcode == OP_LDADDR) {
14122                                 MonoInst *var = ins->inst_p0;
14123
14124                                 if (var->opcode == OP_VTARG_ADDR) {
14125                                         /* Happens on SPARC/S390 where vtypes are passed by reference */
14126                                         MonoInst *vtaddr = var->inst_left;
14127                                         if (vtaddr->opcode == OP_REGVAR) {
14128                                                 ins->opcode = OP_MOVE;
14129                                                 ins->sreg1 = vtaddr->dreg;
14130                                         }
14131                                         else if (var->inst_left->opcode == OP_REGOFFSET) {
14132                                                 ins->opcode = OP_LOAD_MEMBASE;
14133                                                 ins->inst_basereg = vtaddr->inst_basereg;
14134                                                 ins->inst_offset = vtaddr->inst_offset;
14135                                         } else
14136                                                 NOT_IMPLEMENTED;
14137                                 } else if (cfg->gsharedvt && gsharedvt_vreg_to_idx [var->dreg] < 0) {
14138                                         /* gsharedvt arg passed by ref */
14139                                         g_assert (var->opcode == OP_GSHAREDVT_ARG_REGOFFSET);
14140
14141                                         ins->opcode = OP_LOAD_MEMBASE;
14142                                         ins->inst_basereg = var->inst_basereg;
14143                                         ins->inst_offset = var->inst_offset;
14144                                 } else if (cfg->gsharedvt && gsharedvt_vreg_to_idx [var->dreg]) {
14145                                         MonoInst *load, *load2, *load3;
14146                                         int idx = gsharedvt_vreg_to_idx [var->dreg] - 1;
14147                                         int reg1, reg2, reg3;
14148                                         MonoInst *info_var = cfg->gsharedvt_info_var;
14149                                         MonoInst *locals_var = cfg->gsharedvt_locals_var;
14150
14151                                         /*
14152                                          * gsharedvt local.
14153                                          * Compute the address of the local as gsharedvt_locals_var + gsharedvt_info_var->locals_offsets [idx].
14154                                          */
14155
14156                                         g_assert (var->opcode == OP_GSHAREDVT_LOCAL);
14157
14158                                         g_assert (info_var);
14159                                         g_assert (locals_var);
14160
14161                                         /* Mark the instruction used to compute the locals var as used */
14162                                         cfg->gsharedvt_locals_var_ins = NULL;
14163
14164                                         /* Load the offset */
14165                                         if (info_var->opcode == OP_REGOFFSET) {
14166                                                 reg1 = alloc_ireg (cfg);
14167                                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, reg1, info_var->inst_basereg, info_var->inst_offset);
14168                                         } else if (info_var->opcode == OP_REGVAR) {
14169                                                 load = NULL;
14170                                                 reg1 = info_var->dreg;
14171                                         } else {
14172                                                 g_assert_not_reached ();
14173                                         }
14174                                         reg2 = alloc_ireg (cfg);
14175                                         NEW_LOAD_MEMBASE (cfg, load2, OP_LOADI4_MEMBASE, reg2, reg1, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
14176                                         /* Load the locals area address */
14177                                         reg3 = alloc_ireg (cfg);
14178                                         if (locals_var->opcode == OP_REGOFFSET) {
14179                                                 NEW_LOAD_MEMBASE (cfg, load3, OP_LOAD_MEMBASE, reg3, locals_var->inst_basereg, locals_var->inst_offset);
14180                                         } else if (locals_var->opcode == OP_REGVAR) {
14181                                                 NEW_UNALU (cfg, load3, OP_MOVE, reg3, locals_var->dreg);
14182                                         } else {
14183                                                 g_assert_not_reached ();
14184                                         }
14185                                         /* Compute the address */
14186                                         ins->opcode = OP_PADD;
14187                                         ins->sreg1 = reg3;
14188                                         ins->sreg2 = reg2;
14189
14190                                         mono_bblock_insert_before_ins (bb, ins, load3);
14191                                         mono_bblock_insert_before_ins (bb, load3, load2);
14192                                         if (load)
14193                                                 mono_bblock_insert_before_ins (bb, load2, load);
14194                                 } else {
14195                                         g_assert (var->opcode == OP_REGOFFSET);
14196
14197                                         ins->opcode = OP_ADD_IMM;
14198                                         ins->sreg1 = var->inst_basereg;
14199                                         ins->inst_imm = var->inst_offset;
14200                                 }
14201
14202                                 *need_local_opts = TRUE;
14203                                 spec = INS_INFO (ins->opcode);
14204                         }
14205
14206                         if (ins->opcode < MONO_CEE_LAST) {
14207                                 mono_print_ins (ins);
14208                                 g_assert_not_reached ();
14209                         }
14210
14211                         /*
14212                          * Store opcodes have destbasereg in the dreg, but in reality, it is an
14213                          * src register.
14214                          * FIXME:
14215                          */
14216                         if (MONO_IS_STORE_MEMBASE (ins)) {
14217                                 tmp_reg = ins->dreg;
14218                                 ins->dreg = ins->sreg2;
14219                                 ins->sreg2 = tmp_reg;
14220                                 store = TRUE;
14221
14222                                 spec2 [MONO_INST_DEST] = ' ';
14223                                 spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14224                                 spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14225                                 spec2 [MONO_INST_SRC3] = ' ';
14226                                 spec = spec2;
14227                         } else if (MONO_IS_STORE_MEMINDEX (ins))
14228                                 g_assert_not_reached ();
14229                         else
14230                                 store = FALSE;
14231                         no_lvreg = FALSE;
14232
14233                         if (G_UNLIKELY (cfg->verbose_level > 2)) {
14234                                 printf ("\t %.3s %d", spec, ins->dreg);
14235                                 num_sregs = mono_inst_get_src_registers (ins, sregs);
14236                                 for (srcindex = 0; srcindex < num_sregs; ++srcindex)
14237                                         printf (" %d", sregs [srcindex]);
14238                                 printf ("\n");
14239                         }
14240
14241                         /***************/
14242                         /*    DREG     */
14243                         /***************/
14244                         regtype = spec [MONO_INST_DEST];
14245                         g_assert (((ins->dreg == -1) && (regtype == ' ')) || ((ins->dreg != -1) && (regtype != ' ')));
14246                         prev_dreg = -1;
14247
14248                         if ((ins->dreg != -1) && get_vreg_to_inst (cfg, ins->dreg)) {
14249                                 MonoInst *var = get_vreg_to_inst (cfg, ins->dreg);
14250                                 MonoInst *store_ins;
14251                                 int store_opcode;
14252                                 MonoInst *def_ins = ins;
14253                                 int dreg = ins->dreg; /* The original vreg */
14254
14255                                 store_opcode = mono_type_to_store_membase (cfg, var->inst_vtype);
14256
14257                                 if (var->opcode == OP_REGVAR) {
14258                                         ins->dreg = var->dreg;
14259                                 } 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)) {
14260                                         /* 
14261                                          * Instead of emitting a load+store, use a _membase opcode.
14262                                          */
14263                                         g_assert (var->opcode == OP_REGOFFSET);
14264                                         if (ins->opcode == OP_MOVE) {
14265                                                 NULLIFY_INS (ins);
14266                                                 def_ins = NULL;
14267                                         } else {
14268                                                 ins->opcode = op_to_op_dest_membase (store_opcode, ins->opcode);
14269                                                 ins->inst_basereg = var->inst_basereg;
14270                                                 ins->inst_offset = var->inst_offset;
14271                                                 ins->dreg = -1;
14272                                         }
14273                                         spec = INS_INFO (ins->opcode);
14274                                 } else {
14275                                         guint32 lvreg;
14276
14277                                         g_assert (var->opcode == OP_REGOFFSET);
14278
14279                                         prev_dreg = ins->dreg;
14280
14281                                         /* Invalidate any previous lvreg for this vreg */
14282                                         vreg_to_lvreg [ins->dreg] = 0;
14283
14284                                         lvreg = 0;
14285
14286                                         if (COMPILE_SOFT_FLOAT (cfg) && store_opcode == OP_STORER8_MEMBASE_REG) {
14287                                                 regtype = 'l';
14288                                                 store_opcode = OP_STOREI8_MEMBASE_REG;
14289                                         }
14290
14291                                         ins->dreg = alloc_dreg (cfg, stacktypes [regtype]);
14292
14293 #if SIZEOF_REGISTER != 8
14294                                         if (regtype == 'l') {
14295                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET, ins->dreg + 1);
14296                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14297                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET, ins->dreg + 2);
14298                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14299                                                 def_ins = store_ins;
14300                                         }
14301                                         else
14302 #endif
14303                                         {
14304                                                 g_assert (store_opcode != OP_STOREV_MEMBASE);
14305
14306                                                 /* Try to fuse the store into the instruction itself */
14307                                                 /* FIXME: Add more instructions */
14308                                                 if (!lvreg && ((ins->opcode == OP_ICONST) || ((ins->opcode == OP_I8CONST) && (ins->inst_c0 == 0)))) {
14309                                                         ins->opcode = store_membase_reg_to_store_membase_imm (store_opcode);
14310                                                         ins->inst_imm = ins->inst_c0;
14311                                                         ins->inst_destbasereg = var->inst_basereg;
14312                                                         ins->inst_offset = var->inst_offset;
14313                                                         spec = INS_INFO (ins->opcode);
14314                                                 } else if (!lvreg && ((ins->opcode == OP_MOVE) || (ins->opcode == OP_FMOVE) || (ins->opcode == OP_LMOVE) || (ins->opcode == OP_RMOVE))) {
14315                                                         ins->opcode = store_opcode;
14316                                                         ins->inst_destbasereg = var->inst_basereg;
14317                                                         ins->inst_offset = var->inst_offset;
14318
14319                                                         no_lvreg = TRUE;
14320
14321                                                         tmp_reg = ins->dreg;
14322                                                         ins->dreg = ins->sreg2;
14323                                                         ins->sreg2 = tmp_reg;
14324                                                         store = TRUE;
14325
14326                                                         spec2 [MONO_INST_DEST] = ' ';
14327                                                         spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14328                                                         spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14329                                                         spec2 [MONO_INST_SRC3] = ' ';
14330                                                         spec = spec2;
14331                                                 } else if (!lvreg && (op_to_op_store_membase (store_opcode, ins->opcode) != -1)) {
14332                                                         // FIXME: The backends expect the base reg to be in inst_basereg
14333                                                         ins->opcode = op_to_op_store_membase (store_opcode, ins->opcode);
14334                                                         ins->dreg = -1;
14335                                                         ins->inst_basereg = var->inst_basereg;
14336                                                         ins->inst_offset = var->inst_offset;
14337                                                         spec = INS_INFO (ins->opcode);
14338                                                 } else {
14339                                                         /* printf ("INS: "); mono_print_ins (ins); */
14340                                                         /* Create a store instruction */
14341                                                         NEW_STORE_MEMBASE (cfg, store_ins, store_opcode, var->inst_basereg, var->inst_offset, ins->dreg);
14342
14343                                                         /* Insert it after the instruction */
14344                                                         mono_bblock_insert_after_ins (bb, ins, store_ins);
14345
14346                                                         def_ins = store_ins;
14347
14348                                                         /* 
14349                                                          * We can't assign ins->dreg to var->dreg here, since the
14350                                                          * sregs could use it. So set a flag, and do it after
14351                                                          * the sregs.
14352                                                          */
14353                                                         if ((!MONO_ARCH_USE_FPSTACK || ((store_opcode != OP_STORER8_MEMBASE_REG) && (store_opcode != OP_STORER4_MEMBASE_REG))) && !((var)->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT)))
14354                                                                 dest_has_lvreg = TRUE;
14355                                                 }
14356                                         }
14357                                 }
14358
14359                                 if (def_ins && !live_range_start [dreg]) {
14360                                         live_range_start [dreg] = def_ins;
14361                                         live_range_start_bb [dreg] = bb;
14362                                 }
14363
14364                                 if (cfg->compute_gc_maps && def_ins && (var->flags & MONO_INST_GC_TRACK)) {
14365                                         MonoInst *tmp;
14366
14367                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
14368                                         tmp->inst_c1 = dreg;
14369                                         mono_bblock_insert_after_ins (bb, def_ins, tmp);
14370                                 }
14371                         }
14372
14373                         /************/
14374                         /*  SREGS   */
14375                         /************/
14376                         num_sregs = mono_inst_get_src_registers (ins, sregs);
14377                         for (srcindex = 0; srcindex < 3; ++srcindex) {
14378                                 regtype = spec [MONO_INST_SRC1 + srcindex];
14379                                 sreg = sregs [srcindex];
14380
14381                                 g_assert (((sreg == -1) && (regtype == ' ')) || ((sreg != -1) && (regtype != ' ')));
14382                                 if ((sreg != -1) && get_vreg_to_inst (cfg, sreg)) {
14383                                         MonoInst *var = get_vreg_to_inst (cfg, sreg);
14384                                         MonoInst *use_ins = ins;
14385                                         MonoInst *load_ins;
14386                                         guint32 load_opcode;
14387
14388                                         if (var->opcode == OP_REGVAR) {
14389                                                 sregs [srcindex] = var->dreg;
14390                                                 //mono_inst_set_src_registers (ins, sregs);
14391                                                 live_range_end [sreg] = use_ins;
14392                                                 live_range_end_bb [sreg] = bb;
14393
14394                                                 if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14395                                                         MonoInst *tmp;
14396
14397                                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14398                                                         /* var->dreg is a hreg */
14399                                                         tmp->inst_c1 = sreg;
14400                                                         mono_bblock_insert_after_ins (bb, ins, tmp);
14401                                                 }
14402
14403                                                 continue;
14404                                         }
14405
14406                                         g_assert (var->opcode == OP_REGOFFSET);
14407                                                 
14408                                         load_opcode = mono_type_to_load_membase (cfg, var->inst_vtype);
14409
14410                                         g_assert (load_opcode != OP_LOADV_MEMBASE);
14411
14412                                         if (vreg_to_lvreg [sreg]) {
14413                                                 g_assert (vreg_to_lvreg [sreg] != -1);
14414
14415                                                 /* The variable is already loaded to an lvreg */
14416                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
14417                                                         printf ("\t\tUse lvreg R%d for R%d.\n", vreg_to_lvreg [sreg], sreg);
14418                                                 sregs [srcindex] = vreg_to_lvreg [sreg];
14419                                                 //mono_inst_set_src_registers (ins, sregs);
14420                                                 continue;
14421                                         }
14422
14423                                         /* Try to fuse the load into the instruction */
14424                                         if ((srcindex == 0) && (op_to_op_src1_membase (load_opcode, ins->opcode) != -1)) {
14425                                                 ins->opcode = op_to_op_src1_membase (load_opcode, ins->opcode);
14426                                                 sregs [0] = var->inst_basereg;
14427                                                 //mono_inst_set_src_registers (ins, sregs);
14428                                                 ins->inst_offset = var->inst_offset;
14429                                         } else if ((srcindex == 1) && (op_to_op_src2_membase (load_opcode, ins->opcode) != -1)) {
14430                                                 ins->opcode = op_to_op_src2_membase (load_opcode, ins->opcode);
14431                                                 sregs [1] = var->inst_basereg;
14432                                                 //mono_inst_set_src_registers (ins, sregs);
14433                                                 ins->inst_offset = var->inst_offset;
14434                                         } else {
14435                                                 if (MONO_IS_REAL_MOVE (ins)) {
14436                                                         ins->opcode = OP_NOP;
14437                                                         sreg = ins->dreg;
14438                                                 } else {
14439                                                         //printf ("%d ", srcindex); mono_print_ins (ins);
14440
14441                                                         sreg = alloc_dreg (cfg, stacktypes [regtype]);
14442
14443                                                         if ((!MONO_ARCH_USE_FPSTACK || ((load_opcode != OP_LOADR8_MEMBASE) && (load_opcode != OP_LOADR4_MEMBASE))) && !((var)->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT)) && !no_lvreg) {
14444                                                                 if (var->dreg == prev_dreg) {
14445                                                                         /*
14446                                                                          * sreg refers to the value loaded by the load
14447                                                                          * emitted below, but we need to use ins->dreg
14448                                                                          * since it refers to the store emitted earlier.
14449                                                                          */
14450                                                                         sreg = ins->dreg;
14451                                                                 }
14452                                                                 g_assert (sreg != -1);
14453                                                                 vreg_to_lvreg [var->dreg] = sreg;
14454                                                                 g_assert (lvregs_len < 1024);
14455                                                                 lvregs [lvregs_len ++] = var->dreg;
14456                                                         }
14457                                                 }
14458
14459                                                 sregs [srcindex] = sreg;
14460                                                 //mono_inst_set_src_registers (ins, sregs);
14461
14462 #if SIZEOF_REGISTER != 8
14463                                                 if (regtype == 'l') {
14464                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 2, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET);
14465                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14466                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 1, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET);
14467                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14468                                                         use_ins = load_ins;
14469                                                 }
14470                                                 else
14471 #endif
14472                                                 {
14473 #if SIZEOF_REGISTER == 4
14474                                                         g_assert (load_opcode != OP_LOADI8_MEMBASE);
14475 #endif
14476                                                         NEW_LOAD_MEMBASE (cfg, load_ins, load_opcode, sreg, var->inst_basereg, var->inst_offset);
14477                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14478                                                         use_ins = load_ins;
14479                                                 }
14480                                         }
14481
14482                                         if (var->dreg < orig_next_vreg) {
14483                                                 live_range_end [var->dreg] = use_ins;
14484                                                 live_range_end_bb [var->dreg] = bb;
14485                                         }
14486
14487                                         if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14488                                                 MonoInst *tmp;
14489
14490                                                 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14491                                                 tmp->inst_c1 = var->dreg;
14492                                                 mono_bblock_insert_after_ins (bb, ins, tmp);
14493                                         }
14494                                 }
14495                         }
14496                         mono_inst_set_src_registers (ins, sregs);
14497
14498                         if (dest_has_lvreg) {
14499                                 g_assert (ins->dreg != -1);
14500                                 vreg_to_lvreg [prev_dreg] = ins->dreg;
14501                                 g_assert (lvregs_len < 1024);
14502                                 lvregs [lvregs_len ++] = prev_dreg;
14503                                 dest_has_lvreg = FALSE;
14504                         }
14505
14506                         if (store) {
14507                                 tmp_reg = ins->dreg;
14508                                 ins->dreg = ins->sreg2;
14509                                 ins->sreg2 = tmp_reg;
14510                         }
14511
14512                         if (MONO_IS_CALL (ins)) {
14513                                 /* Clear vreg_to_lvreg array */
14514                                 for (i = 0; i < lvregs_len; i++)
14515                                         vreg_to_lvreg [lvregs [i]] = 0;
14516                                 lvregs_len = 0;
14517                         } else if (ins->opcode == OP_NOP) {
14518                                 ins->dreg = -1;
14519                                 MONO_INST_NULLIFY_SREGS (ins);
14520                         }
14521
14522                         if (cfg->verbose_level > 2)
14523                                 mono_print_ins_index (1, ins);
14524                 }
14525
14526                 /* Extend the live range based on the liveness info */
14527                 if (cfg->compute_precise_live_ranges && bb->live_out_set && bb->code) {
14528                         for (i = 0; i < cfg->num_varinfo; i ++) {
14529                                 MonoMethodVar *vi = MONO_VARINFO (cfg, i);
14530
14531                                 if (vreg_is_volatile (cfg, vi->vreg))
14532                                         /* The liveness info is incomplete */
14533                                         continue;
14534
14535                                 if (mono_bitset_test_fast (bb->live_in_set, i) && !live_range_start [vi->vreg]) {
14536                                         /* Live from at least the first ins of this bb */
14537                                         live_range_start [vi->vreg] = bb->code;
14538                                         live_range_start_bb [vi->vreg] = bb;
14539                                 }
14540
14541                                 if (mono_bitset_test_fast (bb->live_out_set, i)) {
14542                                         /* Live at least until the last ins of this bb */
14543                                         live_range_end [vi->vreg] = bb->last_ins;
14544                                         live_range_end_bb [vi->vreg] = bb;
14545                                 }
14546                         }
14547                 }
14548         }
14549         
14550 #ifdef MONO_ARCH_HAVE_LIVERANGE_OPS
14551         /*
14552          * Emit LIVERANGE_START/LIVERANGE_END opcodes, the backend will implement them
14553          * by storing the current native offset into MonoMethodVar->live_range_start/end.
14554          */
14555         if (cfg->compute_precise_live_ranges && cfg->comp_done & MONO_COMP_LIVENESS) {
14556                 for (i = 0; i < cfg->num_varinfo; ++i) {
14557                         int vreg = MONO_VARINFO (cfg, i)->vreg;
14558                         MonoInst *ins;
14559
14560                         if (live_range_start [vreg]) {
14561                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_START);
14562                                 ins->inst_c0 = i;
14563                                 ins->inst_c1 = vreg;
14564                                 mono_bblock_insert_after_ins (live_range_start_bb [vreg], live_range_start [vreg], ins);
14565                         }
14566                         if (live_range_end [vreg]) {
14567                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_END);
14568                                 ins->inst_c0 = i;
14569                                 ins->inst_c1 = vreg;
14570                                 if (live_range_end [vreg] == live_range_end_bb [vreg]->last_ins)
14571                                         mono_add_ins_to_end (live_range_end_bb [vreg], ins);
14572                                 else
14573                                         mono_bblock_insert_after_ins (live_range_end_bb [vreg], live_range_end [vreg], ins);
14574                         }
14575                 }
14576         }
14577 #endif
14578
14579         if (cfg->gsharedvt_locals_var_ins) {
14580                 /* Nullify if unused */
14581                 cfg->gsharedvt_locals_var_ins->opcode = OP_PCONST;
14582                 cfg->gsharedvt_locals_var_ins->inst_imm = 0;
14583         }
14584
14585         g_free (live_range_start);
14586         g_free (live_range_end);
14587         g_free (live_range_start_bb);
14588         g_free (live_range_end_bb);
14589 }
14590
14591 /**
14592  * FIXME:
14593  * - use 'iadd' instead of 'int_add'
14594  * - handling ovf opcodes: decompose in method_to_ir.
14595  * - unify iregs/fregs
14596  *   -> partly done, the missing parts are:
14597  *   - a more complete unification would involve unifying the hregs as well, so
14598  *     code wouldn't need if (fp) all over the place. but that would mean the hregs
14599  *     would no longer map to the machine hregs, so the code generators would need to
14600  *     be modified. Also, on ia64 for example, niregs + nfregs > 256 -> bitmasks
14601  *     wouldn't work any more. Duplicating the code in mono_local_regalloc () into
14602  *     fp/non-fp branches speeds it up by about 15%.
14603  * - use sext/zext opcodes instead of shifts
14604  * - add OP_ICALL
14605  * - get rid of TEMPLOADs if possible and use vregs instead
14606  * - clean up usage of OP_P/OP_ opcodes
14607  * - cleanup usage of DUMMY_USE
14608  * - cleanup the setting of ins->type for MonoInst's which are pushed on the 
14609  *   stack
14610  * - set the stack type and allocate a dreg in the EMIT_NEW macros
14611  * - get rid of all the <foo>2 stuff when the new JIT is ready.
14612  * - make sure handle_stack_args () is called before the branch is emitted
14613  * - when the new IR is done, get rid of all unused stuff
14614  * - COMPARE/BEQ as separate instructions or unify them ?
14615  *   - keeping them separate allows specialized compare instructions like
14616  *     compare_imm, compare_membase
14617  *   - most back ends unify fp compare+branch, fp compare+ceq
14618  * - integrate mono_save_args into inline_method
14619  * - get rid of the empty bblocks created by MONO_EMIT_NEW_BRACH_BLOCK2
14620  * - handle long shift opts on 32 bit platforms somehow: they require 
14621  *   3 sregs (2 for arg1 and 1 for arg2)
14622  * - make byref a 'normal' type.
14623  * - use vregs for bb->out_stacks if possible, handle_global_vreg will make them a
14624  *   variable if needed.
14625  * - do not start a new IL level bblock when cfg->cbb is changed by a function call
14626  *   like inline_method.
14627  * - remove inlining restrictions
14628  * - fix LNEG and enable cfold of INEG
14629  * - generalize x86 optimizations like ldelema as a peephole optimization
14630  * - add store_mem_imm for amd64
14631  * - optimize the loading of the interruption flag in the managed->native wrappers
14632  * - avoid special handling of OP_NOP in passes
14633  * - move code inserting instructions into one function/macro.
14634  * - try a coalescing phase after liveness analysis
14635  * - add float -> vreg conversion + local optimizations on !x86
14636  * - figure out how to handle decomposed branches during optimizations, ie.
14637  *   compare+branch, op_jump_table+op_br etc.
14638  * - promote RuntimeXHandles to vregs
14639  * - vtype cleanups:
14640  *   - add a NEW_VARLOADA_VREG macro
14641  * - the vtype optimizations are blocked by the LDADDR opcodes generated for 
14642  *   accessing vtype fields.
14643  * - get rid of I8CONST on 64 bit platforms
14644  * - dealing with the increase in code size due to branches created during opcode
14645  *   decomposition:
14646  *   - use extended basic blocks
14647  *     - all parts of the JIT
14648  *     - handle_global_vregs () && local regalloc
14649  *   - avoid introducing global vregs during decomposition, like 'vtable' in isinst
14650  * - sources of increase in code size:
14651  *   - vtypes
14652  *   - long compares
14653  *   - isinst and castclass
14654  *   - lvregs not allocated to global registers even if used multiple times
14655  * - call cctors outside the JIT, to make -v output more readable and JIT timings more
14656  *   meaningful.
14657  * - check for fp stack leakage in other opcodes too. (-> 'exceptions' optimization)
14658  * - add all micro optimizations from the old JIT
14659  * - put tree optimizations into the deadce pass
14660  * - decompose op_start_handler/op_endfilter/op_endfinally earlier using an arch
14661  *   specific function.
14662  * - unify the float comparison opcodes with the other comparison opcodes, i.e.
14663  *   fcompare + branchCC.
14664  * - create a helper function for allocating a stack slot, taking into account 
14665  *   MONO_CFG_HAS_SPILLUP.
14666  * - merge r68207.
14667  * - merge the ia64 switch changes.
14668  * - optimize mono_regstate2_alloc_int/float.
14669  * - fix the pessimistic handling of variables accessed in exception handler blocks.
14670  * - need to write a tree optimization pass, but the creation of trees is difficult, i.e.
14671  *   parts of the tree could be separated by other instructions, killing the tree
14672  *   arguments, or stores killing loads etc. Also, should we fold loads into other
14673  *   instructions if the result of the load is used multiple times ?
14674  * - make the REM_IMM optimization in mini-x86.c arch-independent.
14675  * - LAST MERGE: 108395.
14676  * - when returning vtypes in registers, generate IR and append it to the end of the
14677  *   last bb instead of doing it in the epilog.
14678  * - change the store opcodes so they use sreg1 instead of dreg to store the base register.
14679  */
14680
14681 /*
14682
14683 NOTES
14684 -----
14685
14686 - When to decompose opcodes:
14687   - earlier: this makes some optimizations hard to implement, since the low level IR
14688   no longer contains the neccessary information. But it is easier to do.
14689   - later: harder to implement, enables more optimizations.
14690 - Branches inside bblocks:
14691   - created when decomposing complex opcodes. 
14692     - branches to another bblock: harmless, but not tracked by the branch 
14693       optimizations, so need to branch to a label at the start of the bblock.
14694     - branches to inside the same bblock: very problematic, trips up the local
14695       reg allocator. Can be fixed by spitting the current bblock, but that is a
14696       complex operation, since some local vregs can become global vregs etc.
14697 - Local/global vregs:
14698   - local vregs: temporary vregs used inside one bblock. Assigned to hregs by the
14699     local register allocator.
14700   - global vregs: used in more than one bblock. Have an associated MonoMethodVar
14701     structure, created by mono_create_var (). Assigned to hregs or the stack by
14702     the global register allocator.
14703 - When to do optimizations like alu->alu_imm:
14704   - earlier -> saves work later on since the IR will be smaller/simpler
14705   - later -> can work on more instructions
14706 - Handling of valuetypes:
14707   - When a vtype is pushed on the stack, a new temporary is created, an 
14708     instruction computing its address (LDADDR) is emitted and pushed on
14709     the stack. Need to optimize cases when the vtype is used immediately as in
14710     argument passing, stloc etc.
14711 - Instead of the to_end stuff in the old JIT, simply call the function handling
14712   the values on the stack before emitting the last instruction of the bb.
14713 */
14714
14715 #endif /* DISABLE_JIT */