[runtime] Merge origin/kyte/llvmonly-exceptions-pr.
[mono.git] / mono / mini / method-to-ir.c
1 /*
2  * method-to-ir.c: Convert CIL to the JIT internal representation
3  *
4  * Author:
5  *   Paolo Molaro (lupus@ximian.com)
6  *   Dietmar Maurer (dietmar@ximian.com)
7  *
8  * (C) 2002 Ximian, Inc.
9  * Copyright 2003-2010 Novell, Inc (http://www.novell.com)
10  * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
11  */
12
13 #include <config.h>
14
15 #ifndef DISABLE_JIT
16
17 #include <signal.h>
18
19 #ifdef HAVE_UNISTD_H
20 #include <unistd.h>
21 #endif
22
23 #include <math.h>
24 #include <string.h>
25 #include <ctype.h>
26
27 #ifdef HAVE_SYS_TIME_H
28 #include <sys/time.h>
29 #endif
30
31 #ifdef HAVE_ALLOCA_H
32 #include <alloca.h>
33 #endif
34
35 #include <mono/utils/memcheck.h>
36 #include "mini.h"
37 #include <mono/metadata/abi-details.h>
38 #include <mono/metadata/assembly.h>
39 #include <mono/metadata/attrdefs.h>
40 #include <mono/metadata/loader.h>
41 #include <mono/metadata/tabledefs.h>
42 #include <mono/metadata/class.h>
43 #include <mono/metadata/object.h>
44 #include <mono/metadata/exception.h>
45 #include <mono/metadata/opcodes.h>
46 #include <mono/metadata/mono-endian.h>
47 #include <mono/metadata/tokentype.h>
48 #include <mono/metadata/tabledefs.h>
49 #include <mono/metadata/marshal.h>
50 #include <mono/metadata/debug-helpers.h>
51 #include <mono/metadata/mono-debug.h>
52 #include <mono/metadata/mono-debug-debugger.h>
53 #include <mono/metadata/gc-internal.h>
54 #include <mono/metadata/security-manager.h>
55 #include <mono/metadata/threads-types.h>
56 #include <mono/metadata/security-core-clr.h>
57 #include <mono/metadata/profiler-private.h>
58 #include <mono/metadata/profiler.h>
59 #include <mono/metadata/debug-mono-symfile.h>
60 #include <mono/utils/mono-compiler.h>
61 #include <mono/utils/mono-memory-model.h>
62 #include <mono/metadata/mono-basic-block.h>
63
64 #include "trace.h"
65
66 #include "ir-emit.h"
67
68 #include "jit-icalls.h"
69 #include "jit.h"
70 #include "debugger-agent.h"
71 #include "seq-points.h"
72
73 #define BRANCH_COST 10
74 #define INLINE_LENGTH_LIMIT 20
75
76 /* These have 'cfg' as an implicit argument */
77 #define INLINE_FAILURE(msg) do {                                                                        \
78         if ((cfg->method != cfg->current_method) && (cfg->current_method->wrapper_type == MONO_WRAPPER_NONE)) { \
79                 inline_failure (cfg, msg);                                                                              \
80                 goto exception_exit;                                                                                    \
81         } \
82         } while (0)
83 #define CHECK_CFG_EXCEPTION do {\
84                 if (cfg->exception_type != MONO_EXCEPTION_NONE) \
85                         goto exception_exit;                                            \
86         } while (0)
87 #define METHOD_ACCESS_FAILURE(method, cmethod) do {                     \
88                 method_access_failure ((cfg), (method), (cmethod));                     \
89                 goto exception_exit;                                                                            \
90         } while (0)
91 #define FIELD_ACCESS_FAILURE(method, field) do {                                        \
92                 field_access_failure ((cfg), (method), (field));                        \
93                 goto exception_exit;    \
94         } while (0)
95 #define GENERIC_SHARING_FAILURE(opcode) do {            \
96                 if (cfg->gshared) {                                                                     \
97                         gshared_failure (cfg, opcode, __FILE__, __LINE__);      \
98                         goto exception_exit;    \
99                 }                       \
100         } while (0)
101 #define GSHAREDVT_FAILURE(opcode) do {          \
102         if (cfg->gsharedvt) {                                                                                           \
103                 gsharedvt_failure (cfg, opcode, __FILE__, __LINE__);                    \
104                 goto exception_exit;                                                                                    \
105         }                                                                                                                                       \
106         } while (0)
107 #define OUT_OF_MEMORY_FAILURE do {      \
108                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_OUT_OF_MEMORY);             \
109                 goto exception_exit;    \
110         } while (0)
111 #define DISABLE_AOT(cfg) do { \
112                 if ((cfg)->verbose_level >= 2)                                            \
113                         printf ("AOT disabled: %s:%d\n", __FILE__, __LINE__);   \
114                 (cfg)->disable_aot = TRUE;                                                        \
115         } while (0)
116 #define LOAD_ERROR do { \
117                 break_on_unverified ();                                                         \
118                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD); \
119                 goto exception_exit;                                                                    \
120         } while (0)
121
122 #define TYPE_LOAD_ERROR(klass) do { \
123                 cfg->exception_ptr = klass; \
124                 LOAD_ERROR;                                     \
125         } while (0)
126
127 #define CHECK_CFG_ERROR do {\
128                 if (!mono_error_ok (&cfg->error)) { \
129                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);        \
130                         goto mono_error_exit; \
131                 } \
132         } while (0)
133
134 /* Determine whenever 'ins' represents a load of the 'this' argument */
135 #define MONO_CHECK_THIS(ins) (mono_method_signature (cfg->method)->hasthis && ((ins)->opcode == OP_MOVE) && ((ins)->sreg1 == cfg->args [0]->dreg))
136
137 static int ldind_to_load_membase (int opcode);
138 static int stind_to_store_membase (int opcode);
139
140 int mono_op_to_op_imm (int opcode);
141 int mono_op_to_op_imm_noemul (int opcode);
142
143 MONO_API MonoInst* mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig, MonoInst **args);
144
145 static int inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
146                                                   guchar *ip, guint real_offset, gboolean inline_always);
147
148 /* helper methods signatures */
149 static MonoMethodSignature *helper_sig_domain_get;
150 static MonoMethodSignature *helper_sig_rgctx_lazy_fetch_trampoline;
151
152 /*
153  * Instruction metadata
154  */
155 #ifdef MINI_OP
156 #undef MINI_OP
157 #endif
158 #ifdef MINI_OP3
159 #undef MINI_OP3
160 #endif
161 #define MINI_OP(a,b,dest,src1,src2) dest, src1, src2, ' ',
162 #define MINI_OP3(a,b,dest,src1,src2,src3) dest, src1, src2, src3,
163 #define NONE ' '
164 #define IREG 'i'
165 #define FREG 'f'
166 #define VREG 'v'
167 #define XREG 'x'
168 #if SIZEOF_REGISTER == 8 && SIZEOF_REGISTER == SIZEOF_VOID_P
169 #define LREG IREG
170 #else
171 #define LREG 'l'
172 #endif
173 /* keep in sync with the enum in mini.h */
174 const char
175 ins_info[] = {
176 #include "mini-ops.h"
177 };
178 #undef MINI_OP
179 #undef MINI_OP3
180
181 #define MINI_OP(a,b,dest,src1,src2) ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0)),
182 #define MINI_OP3(a,b,dest,src1,src2,src3) ((src3) != NONE ? 3 : ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0))),
183 /* 
184  * This should contain the index of the last sreg + 1. This is not the same
185  * as the number of sregs for opcodes like IA64_CMP_EQ_IMM.
186  */
187 const gint8 ins_sreg_counts[] = {
188 #include "mini-ops.h"
189 };
190 #undef MINI_OP
191 #undef MINI_OP3
192
193 #define MONO_INIT_VARINFO(vi,id) do { \
194         (vi)->range.first_use.pos.bid = 0xffff; \
195         (vi)->reg = -1; \
196         (vi)->idx = (id); \
197 } while (0)
198
199 guint32
200 mono_alloc_ireg (MonoCompile *cfg)
201 {
202         return alloc_ireg (cfg);
203 }
204
205 guint32
206 mono_alloc_lreg (MonoCompile *cfg)
207 {
208         return alloc_lreg (cfg);
209 }
210
211 guint32
212 mono_alloc_freg (MonoCompile *cfg)
213 {
214         return alloc_freg (cfg);
215 }
216
217 guint32
218 mono_alloc_preg (MonoCompile *cfg)
219 {
220         return alloc_preg (cfg);
221 }
222
223 guint32
224 mono_alloc_dreg (MonoCompile *cfg, MonoStackType stack_type)
225 {
226         return alloc_dreg (cfg, stack_type);
227 }
228
229 /*
230  * mono_alloc_ireg_ref:
231  *
232  *   Allocate an IREG, and mark it as holding a GC ref.
233  */
234 guint32
235 mono_alloc_ireg_ref (MonoCompile *cfg)
236 {
237         return alloc_ireg_ref (cfg);
238 }
239
240 /*
241  * mono_alloc_ireg_mp:
242  *
243  *   Allocate an IREG, and mark it as holding a managed pointer.
244  */
245 guint32
246 mono_alloc_ireg_mp (MonoCompile *cfg)
247 {
248         return alloc_ireg_mp (cfg);
249 }
250
251 /*
252  * mono_alloc_ireg_copy:
253  *
254  *   Allocate an IREG with the same GC type as VREG.
255  */
256 guint32
257 mono_alloc_ireg_copy (MonoCompile *cfg, guint32 vreg)
258 {
259         if (vreg_is_ref (cfg, vreg))
260                 return alloc_ireg_ref (cfg);
261         else if (vreg_is_mp (cfg, vreg))
262                 return alloc_ireg_mp (cfg);
263         else
264                 return alloc_ireg (cfg);
265 }
266
267 guint
268 mono_type_to_regmove (MonoCompile *cfg, MonoType *type)
269 {
270         if (type->byref)
271                 return OP_MOVE;
272
273         type = mini_get_underlying_type (type);
274 handle_enum:
275         switch (type->type) {
276         case MONO_TYPE_I1:
277         case MONO_TYPE_U1:
278                 return OP_MOVE;
279         case MONO_TYPE_I2:
280         case MONO_TYPE_U2:
281                 return OP_MOVE;
282         case MONO_TYPE_I4:
283         case MONO_TYPE_U4:
284                 return OP_MOVE;
285         case MONO_TYPE_I:
286         case MONO_TYPE_U:
287         case MONO_TYPE_PTR:
288         case MONO_TYPE_FNPTR:
289                 return OP_MOVE;
290         case MONO_TYPE_CLASS:
291         case MONO_TYPE_STRING:
292         case MONO_TYPE_OBJECT:
293         case MONO_TYPE_SZARRAY:
294         case MONO_TYPE_ARRAY:    
295                 return OP_MOVE;
296         case MONO_TYPE_I8:
297         case MONO_TYPE_U8:
298 #if SIZEOF_REGISTER == 8
299                 return OP_MOVE;
300 #else
301                 return OP_LMOVE;
302 #endif
303         case MONO_TYPE_R4:
304                 return cfg->r4fp ? OP_RMOVE : OP_FMOVE;
305         case MONO_TYPE_R8:
306                 return OP_FMOVE;
307         case MONO_TYPE_VALUETYPE:
308                 if (type->data.klass->enumtype) {
309                         type = mono_class_enum_basetype (type->data.klass);
310                         goto handle_enum;
311                 }
312                 if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (type)))
313                         return OP_XMOVE;
314                 return OP_VMOVE;
315         case MONO_TYPE_TYPEDBYREF:
316                 return OP_VMOVE;
317         case MONO_TYPE_GENERICINST:
318                 type = &type->data.generic_class->container_class->byval_arg;
319                 goto handle_enum;
320         case MONO_TYPE_VAR:
321         case MONO_TYPE_MVAR:
322                 g_assert (cfg->gshared);
323                 if (mini_type_var_is_vt (type))
324                         return OP_VMOVE;
325                 else
326                         return mono_type_to_regmove (cfg, mini_get_underlying_type (type));
327         default:
328                 g_error ("unknown type 0x%02x in type_to_regstore", type->type);
329         }
330         return -1;
331 }
332
333 void
334 mono_print_bb (MonoBasicBlock *bb, const char *msg)
335 {
336         int i;
337         MonoInst *tree;
338
339         printf ("\n%s %d: [IN: ", msg, bb->block_num);
340         for (i = 0; i < bb->in_count; ++i)
341                 printf (" BB%d(%d)", bb->in_bb [i]->block_num, bb->in_bb [i]->dfn);
342         printf (", OUT: ");
343         for (i = 0; i < bb->out_count; ++i)
344                 printf (" BB%d(%d)", bb->out_bb [i]->block_num, bb->out_bb [i]->dfn);
345         printf (" ]\n");
346         for (tree = bb->code; tree; tree = tree->next)
347                 mono_print_ins_index (-1, tree);
348 }
349
350 void
351 mono_create_helper_signatures (void)
352 {
353         helper_sig_domain_get = mono_create_icall_signature ("ptr");
354         helper_sig_rgctx_lazy_fetch_trampoline = mono_create_icall_signature ("ptr ptr");
355 }
356
357 static MONO_NEVER_INLINE void
358 break_on_unverified (void)
359 {
360         if (mini_get_debug_options ()->break_on_unverified)
361                 G_BREAKPOINT ();
362 }
363
364 static MONO_NEVER_INLINE void
365 method_access_failure (MonoCompile *cfg, MonoMethod *method, MonoMethod *cil_method)
366 {
367         char *method_fname = mono_method_full_name (method, TRUE);
368         char *cil_method_fname = mono_method_full_name (cil_method, TRUE);
369         mono_cfg_set_exception (cfg, MONO_EXCEPTION_METHOD_ACCESS);
370         cfg->exception_message = g_strdup_printf ("Method `%s' is inaccessible from method `%s'\n", cil_method_fname, method_fname);
371         g_free (method_fname);
372         g_free (cil_method_fname);
373 }
374
375 static MONO_NEVER_INLINE void
376 field_access_failure (MonoCompile *cfg, MonoMethod *method, MonoClassField *field)
377 {
378         char *method_fname = mono_method_full_name (method, TRUE);
379         char *field_fname = mono_field_full_name (field);
380         mono_cfg_set_exception (cfg, MONO_EXCEPTION_FIELD_ACCESS);
381         cfg->exception_message = g_strdup_printf ("Field `%s' is inaccessible from method `%s'\n", field_fname, method_fname);
382         g_free (method_fname);
383         g_free (field_fname);
384 }
385
386 static MONO_NEVER_INLINE void
387 inline_failure (MonoCompile *cfg, const char *msg)
388 {
389         if (cfg->verbose_level >= 2)
390                 printf ("inline failed: %s\n", msg);
391         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INLINE_FAILED);
392 }
393
394 static MONO_NEVER_INLINE void
395 gshared_failure (MonoCompile *cfg, int opcode, const char *file, int line)
396 {
397         if (cfg->verbose_level > 2)                                                                                     \
398                 printf ("sharing failed for method %s.%s.%s/%d opcode %s line %d\n", cfg->current_method->klass->name_space, cfg->current_method->klass->name, cfg->current_method->name, cfg->current_method->signature->param_count, mono_opcode_name ((opcode)), line);
399         mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED);
400 }
401
402 static MONO_NEVER_INLINE void
403 gsharedvt_failure (MonoCompile *cfg, int opcode, const char *file, int line)
404 {
405         cfg->exception_message = g_strdup_printf ("gsharedvt failed for method %s.%s.%s/%d opcode %s %s:%d", cfg->current_method->klass->name_space, cfg->current_method->klass->name, cfg->current_method->name, cfg->current_method->signature->param_count, mono_opcode_name ((opcode)), file, line);
406         if (cfg->verbose_level >= 2)
407                 printf ("%s\n", cfg->exception_message);
408         mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED);
409 }
410
411 /*
412  * When using gsharedvt, some instatiations might be verifiable, and some might be not. i.e. 
413  * foo<T> (int i) { ldarg.0; box T; }
414  */
415 #define UNVERIFIED do { \
416         if (cfg->gsharedvt) { \
417                 if (cfg->verbose_level > 2)                                                                     \
418                         printf ("gsharedvt method failed to verify, falling back to instantiation.\n"); \
419                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED); \
420                 goto exception_exit;                                                                                    \
421         }                                                                                                                                       \
422         break_on_unverified ();                                                                                         \
423         goto unverified;                                                                                                        \
424 } while (0)
425
426 #define GET_BBLOCK(cfg,tblock,ip) do {  \
427                 (tblock) = cfg->cil_offset_to_bb [(ip) - cfg->cil_start]; \
428                 if (!(tblock)) {        \
429                         if ((ip) >= end || (ip) < header->code) UNVERIFIED; \
430             NEW_BBLOCK (cfg, (tblock)); \
431                         (tblock)->cil_code = (ip);      \
432                         ADD_BBLOCK (cfg, (tblock));     \
433                 } \
434         } while (0)
435
436 #if defined(TARGET_X86) || defined(TARGET_AMD64)
437 #define EMIT_NEW_X86_LEA(cfg,dest,sr1,sr2,shift,imm) do { \
438                 MONO_INST_NEW (cfg, dest, OP_X86_LEA); \
439                 (dest)->dreg = alloc_ireg_mp ((cfg)); \
440                 (dest)->sreg1 = (sr1); \
441                 (dest)->sreg2 = (sr2); \
442                 (dest)->inst_imm = (imm); \
443                 (dest)->backend.shift_amount = (shift); \
444                 MONO_ADD_INS ((cfg)->cbb, (dest)); \
445         } while (0)
446 #endif
447
448 /* Emit conversions so both operands of a binary opcode are of the same type */
449 static void
450 add_widen_op (MonoCompile *cfg, MonoInst *ins, MonoInst **arg1_ref, MonoInst **arg2_ref)
451 {
452         MonoInst *arg1 = *arg1_ref;
453         MonoInst *arg2 = *arg2_ref;
454
455         if (cfg->r4fp &&
456                 ((arg1->type == STACK_R4 && arg2->type == STACK_R8) ||
457                  (arg1->type == STACK_R8 && arg2->type == STACK_R4))) {
458                 MonoInst *conv;
459
460                 /* Mixing r4/r8 is allowed by the spec */
461                 if (arg1->type == STACK_R4) {
462                         int dreg = alloc_freg (cfg);
463
464                         EMIT_NEW_UNALU (cfg, conv, OP_RCONV_TO_R8, dreg, arg1->dreg);
465                         conv->type = STACK_R8;
466                         ins->sreg1 = dreg;
467                         *arg1_ref = conv;
468                 }
469                 if (arg2->type == STACK_R4) {
470                         int dreg = alloc_freg (cfg);
471
472                         EMIT_NEW_UNALU (cfg, conv, OP_RCONV_TO_R8, dreg, arg2->dreg);
473                         conv->type = STACK_R8;
474                         ins->sreg2 = dreg;
475                         *arg2_ref = conv;
476                 }
477         }
478
479 #if SIZEOF_REGISTER == 8
480         /* FIXME: Need to add many more cases */
481         if ((arg1)->type == STACK_PTR && (arg2)->type == STACK_I4) {
482                 MonoInst *widen;
483
484                 int dr = alloc_preg (cfg);
485                 EMIT_NEW_UNALU (cfg, widen, OP_SEXT_I4, dr, (arg2)->dreg);
486                 (ins)->sreg2 = widen->dreg;
487         }
488 #endif
489 }
490
491 #define ADD_BINOP(op) do {      \
492                 MONO_INST_NEW (cfg, ins, (op)); \
493                 sp -= 2;        \
494                 ins->sreg1 = sp [0]->dreg;      \
495                 ins->sreg2 = sp [1]->dreg;      \
496                 type_from_op (cfg, ins, sp [0], sp [1]);        \
497                 CHECK_TYPE (ins);       \
498                 /* Have to insert a widening op */               \
499         add_widen_op (cfg, ins, &sp [0], &sp [1]);               \
500         ins->dreg = alloc_dreg ((cfg), (ins)->type); \
501         MONO_ADD_INS ((cfg)->cbb, (ins)); \
502         *sp++ = mono_decompose_opcode ((cfg), (ins));   \
503         } while (0)
504
505 #define ADD_UNOP(op) do {       \
506                 MONO_INST_NEW (cfg, ins, (op)); \
507                 sp--;   \
508                 ins->sreg1 = sp [0]->dreg;      \
509                 type_from_op (cfg, ins, sp [0], NULL);  \
510                 CHECK_TYPE (ins);       \
511         (ins)->dreg = alloc_dreg ((cfg), (ins)->type); \
512         MONO_ADD_INS ((cfg)->cbb, (ins)); \
513                 *sp++ = mono_decompose_opcode (cfg, ins);       \
514         } while (0)
515
516 #define ADD_BINCOND(next_block) do {    \
517                 MonoInst *cmp;  \
518                 sp -= 2; \
519                 MONO_INST_NEW(cfg, cmp, OP_COMPARE);    \
520                 cmp->sreg1 = sp [0]->dreg;      \
521                 cmp->sreg2 = sp [1]->dreg;      \
522                 type_from_op (cfg, cmp, sp [0], sp [1]);        \
523                 CHECK_TYPE (cmp);       \
524                 add_widen_op (cfg, cmp, &sp [0], &sp [1]);                                              \
525                 type_from_op (cfg, ins, sp [0], sp [1]);                                                        \
526                 ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);      \
527                 GET_BBLOCK (cfg, tblock, target);               \
528                 link_bblock (cfg, cfg->cbb, tblock);    \
529                 ins->inst_true_bb = tblock;     \
530                 if ((next_block)) {     \
531                         link_bblock (cfg, cfg->cbb, (next_block));      \
532                         ins->inst_false_bb = (next_block);      \
533                         start_new_bblock = 1;   \
534                 } else {        \
535                         GET_BBLOCK (cfg, tblock, ip);           \
536                         link_bblock (cfg, cfg->cbb, tblock);    \
537                         ins->inst_false_bb = tblock;    \
538                         start_new_bblock = 2;   \
539                 }       \
540                 if (sp != stack_start) {                                                                        \
541                     handle_stack_args (cfg, stack_start, sp - stack_start); \
542                         CHECK_UNVERIFIABLE (cfg); \
543                 } \
544         MONO_ADD_INS (cfg->cbb, cmp); \
545                 MONO_ADD_INS (cfg->cbb, ins);   \
546         } while (0)
547
548 /* *
549  * link_bblock: Links two basic blocks
550  *
551  * links two basic blocks in the control flow graph, the 'from'
552  * argument is the starting block and the 'to' argument is the block
553  * the control flow ends to after 'from'.
554  */
555 static void
556 link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
557 {
558         MonoBasicBlock **newa;
559         int i, found;
560
561 #if 0
562         if (from->cil_code) {
563                 if (to->cil_code)
564                         printf ("edge from IL%04x to IL_%04x\n", from->cil_code - cfg->cil_code, to->cil_code - cfg->cil_code);
565                 else
566                         printf ("edge from IL%04x to exit\n", from->cil_code - cfg->cil_code);
567         } else {
568                 if (to->cil_code)
569                         printf ("edge from entry to IL_%04x\n", to->cil_code - cfg->cil_code);
570                 else
571                         printf ("edge from entry to exit\n");
572         }
573 #endif
574
575         found = FALSE;
576         for (i = 0; i < from->out_count; ++i) {
577                 if (to == from->out_bb [i]) {
578                         found = TRUE;
579                         break;
580                 }
581         }
582         if (!found) {
583                 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (from->out_count + 1));
584                 for (i = 0; i < from->out_count; ++i) {
585                         newa [i] = from->out_bb [i];
586                 }
587                 newa [i] = to;
588                 from->out_count++;
589                 from->out_bb = newa;
590         }
591
592         found = FALSE;
593         for (i = 0; i < to->in_count; ++i) {
594                 if (from == to->in_bb [i]) {
595                         found = TRUE;
596                         break;
597                 }
598         }
599         if (!found) {
600                 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (to->in_count + 1));
601                 for (i = 0; i < to->in_count; ++i) {
602                         newa [i] = to->in_bb [i];
603                 }
604                 newa [i] = from;
605                 to->in_count++;
606                 to->in_bb = newa;
607         }
608 }
609
610 void
611 mono_link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
612 {
613         link_bblock (cfg, from, to);
614 }
615
616 /**
617  * mono_find_block_region:
618  *
619  *   We mark each basic block with a region ID. We use that to avoid BB
620  *   optimizations when blocks are in different regions.
621  *
622  * Returns:
623  *   A region token that encodes where this region is, and information
624  *   about the clause owner for this block.
625  *
626  *   The region encodes the try/catch/filter clause that owns this block
627  *   as well as the type.  -1 is a special value that represents a block
628  *   that is in none of try/catch/filter.
629  */
630 static int
631 mono_find_block_region (MonoCompile *cfg, int offset)
632 {
633         MonoMethodHeader *header = cfg->header;
634         MonoExceptionClause *clause;
635         int i;
636
637         for (i = 0; i < header->num_clauses; ++i) {
638                 clause = &header->clauses [i];
639                 if ((clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) && (offset >= clause->data.filter_offset) &&
640                     (offset < (clause->handler_offset)))
641                         return ((i + 1) << 8) | MONO_REGION_FILTER | clause->flags;
642                            
643                 if (MONO_OFFSET_IN_HANDLER (clause, offset)) {
644                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY)
645                                 return ((i + 1) << 8) | MONO_REGION_FINALLY | clause->flags;
646                         else if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
647                                 return ((i + 1) << 8) | MONO_REGION_FAULT | clause->flags;
648                         else
649                                 return ((i + 1) << 8) | MONO_REGION_CATCH | clause->flags;
650                 }
651         }
652         for (i = 0; i < header->num_clauses; ++i) {
653                 clause = &header->clauses [i];
654
655                 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
656                         return ((i + 1) << 8) | clause->flags;
657         }
658
659         return -1;
660 }
661
662 static GList*
663 mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *target, int type)
664 {
665         MonoMethodHeader *header = cfg->header;
666         MonoExceptionClause *clause;
667         int i;
668         GList *res = NULL;
669
670         for (i = 0; i < header->num_clauses; ++i) {
671                 clause = &header->clauses [i];
672                 if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) && 
673                     (!MONO_OFFSET_IN_CLAUSE (clause, (target - header->code)))) {
674                         if (clause->flags == type)
675                                 res = g_list_append (res, clause);
676                 }
677         }
678         return res;
679 }
680
681 static void
682 mono_create_spvar_for_region (MonoCompile *cfg, int region)
683 {
684         MonoInst *var;
685
686         var = g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
687         if (var)
688                 return;
689
690         var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
691         /* prevent it from being register allocated */
692         var->flags |= MONO_INST_VOLATILE;
693
694         g_hash_table_insert (cfg->spvars, GINT_TO_POINTER (region), var);
695 }
696
697 MonoInst *
698 mono_find_exvar_for_offset (MonoCompile *cfg, int offset)
699 {
700         return g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
701 }
702
703 static MonoInst*
704 mono_create_exvar_for_offset (MonoCompile *cfg, int offset)
705 {
706         MonoInst *var;
707
708         var = g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
709         if (var)
710                 return var;
711
712         var = mono_compile_create_var (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL);
713         /* prevent it from being register allocated */
714         var->flags |= MONO_INST_VOLATILE;
715
716         g_hash_table_insert (cfg->exvars, GINT_TO_POINTER (offset), var);
717
718         return var;
719 }
720
721 /*
722  * Returns the type used in the eval stack when @type is loaded.
723  * FIXME: return a MonoType/MonoClass for the byref and VALUETYPE cases.
724  */
725 void
726 type_to_eval_stack_type (MonoCompile *cfg, MonoType *type, MonoInst *inst)
727 {
728         MonoClass *klass;
729
730         type = mini_get_underlying_type (type);
731         inst->klass = klass = mono_class_from_mono_type (type);
732         if (type->byref) {
733                 inst->type = STACK_MP;
734                 return;
735         }
736
737 handle_enum:
738         switch (type->type) {
739         case MONO_TYPE_VOID:
740                 inst->type = STACK_INV;
741                 return;
742         case MONO_TYPE_I1:
743         case MONO_TYPE_U1:
744         case MONO_TYPE_I2:
745         case MONO_TYPE_U2:
746         case MONO_TYPE_I4:
747         case MONO_TYPE_U4:
748                 inst->type = STACK_I4;
749                 return;
750         case MONO_TYPE_I:
751         case MONO_TYPE_U:
752         case MONO_TYPE_PTR:
753         case MONO_TYPE_FNPTR:
754                 inst->type = STACK_PTR;
755                 return;
756         case MONO_TYPE_CLASS:
757         case MONO_TYPE_STRING:
758         case MONO_TYPE_OBJECT:
759         case MONO_TYPE_SZARRAY:
760         case MONO_TYPE_ARRAY:    
761                 inst->type = STACK_OBJ;
762                 return;
763         case MONO_TYPE_I8:
764         case MONO_TYPE_U8:
765                 inst->type = STACK_I8;
766                 return;
767         case MONO_TYPE_R4:
768                 inst->type = cfg->r4_stack_type;
769                 break;
770         case MONO_TYPE_R8:
771                 inst->type = STACK_R8;
772                 return;
773         case MONO_TYPE_VALUETYPE:
774                 if (type->data.klass->enumtype) {
775                         type = mono_class_enum_basetype (type->data.klass);
776                         goto handle_enum;
777                 } else {
778                         inst->klass = klass;
779                         inst->type = STACK_VTYPE;
780                         return;
781                 }
782         case MONO_TYPE_TYPEDBYREF:
783                 inst->klass = mono_defaults.typed_reference_class;
784                 inst->type = STACK_VTYPE;
785                 return;
786         case MONO_TYPE_GENERICINST:
787                 type = &type->data.generic_class->container_class->byval_arg;
788                 goto handle_enum;
789         case MONO_TYPE_VAR:
790         case MONO_TYPE_MVAR:
791                 g_assert (cfg->gshared);
792                 if (mini_is_gsharedvt_type (type)) {
793                         g_assert (cfg->gsharedvt);
794                         inst->type = STACK_VTYPE;
795                 } else {
796                         type_to_eval_stack_type (cfg, mini_get_underlying_type (type), inst);
797                 }
798                 return;
799         default:
800                 g_error ("unknown type 0x%02x in eval stack type", type->type);
801         }
802 }
803
804 /*
805  * The following tables are used to quickly validate the IL code in type_from_op ().
806  */
807 static const char
808 bin_num_table [STACK_MAX] [STACK_MAX] = {
809         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
810         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
811         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
812         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
813         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8,  STACK_INV, STACK_INV, STACK_INV, STACK_R8},
814         {STACK_INV, STACK_MP,  STACK_INV, STACK_MP,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV},
815         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
816         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
817         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8, STACK_INV, STACK_INV, STACK_INV, STACK_R4}
818 };
819
820 static const char 
821 neg_table [] = {
822         STACK_INV, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_INV, STACK_INV, STACK_INV, STACK_R4
823 };
824
825 /* reduce the size of this table */
826 static const char
827 bin_int_table [STACK_MAX] [STACK_MAX] = {
828         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
829         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
830         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
831         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
832         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
833         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
834         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
835         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
836 };
837
838 static const char
839 bin_comp_table [STACK_MAX] [STACK_MAX] = {
840 /*      Inv i  L  p  F  &  O  vt r4 */
841         {0},
842         {0, 1, 0, 1, 0, 0, 0, 0}, /* i, int32 */
843         {0, 0, 1, 0, 0, 0, 0, 0}, /* L, int64 */
844         {0, 1, 0, 1, 0, 2, 4, 0}, /* p, ptr */
845         {0, 0, 0, 0, 1, 0, 0, 0, 1}, /* F, R8 */
846         {0, 0, 0, 2, 0, 1, 0, 0}, /* &, managed pointer */
847         {0, 0, 0, 4, 0, 0, 3, 0}, /* O, reference */
848         {0, 0, 0, 0, 0, 0, 0, 0}, /* vt value type */
849         {0, 0, 0, 0, 1, 0, 0, 0, 1}, /* r, r4 */
850 };
851
852 /* reduce the size of this table */
853 static const char
854 shift_table [STACK_MAX] [STACK_MAX] = {
855         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
856         {STACK_INV, STACK_I4,  STACK_INV, STACK_I4,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
857         {STACK_INV, STACK_I8,  STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
858         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
859         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
860         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
861         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
862         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
863 };
864
865 /*
866  * Tables to map from the non-specific opcode to the matching
867  * type-specific opcode.
868  */
869 /* handles from CEE_ADD to CEE_SHR_UN (CEE_REM_UN for floats) */
870 static const guint16
871 binops_op_map [STACK_MAX] = {
872         0, OP_IADD-CEE_ADD, OP_LADD-CEE_ADD, OP_PADD-CEE_ADD, OP_FADD-CEE_ADD, OP_PADD-CEE_ADD, 0, 0, OP_RADD-CEE_ADD
873 };
874
875 /* handles from CEE_NEG to CEE_CONV_U8 */
876 static const guint16
877 unops_op_map [STACK_MAX] = {
878         0, OP_INEG-CEE_NEG, OP_LNEG-CEE_NEG, OP_PNEG-CEE_NEG, OP_FNEG-CEE_NEG, OP_PNEG-CEE_NEG, 0, 0, OP_RNEG-CEE_NEG
879 };
880
881 /* handles from CEE_CONV_U2 to CEE_SUB_OVF_UN */
882 static const guint16
883 ovfops_op_map [STACK_MAX] = {
884         0, OP_ICONV_TO_U2-CEE_CONV_U2, OP_LCONV_TO_U2-CEE_CONV_U2, OP_PCONV_TO_U2-CEE_CONV_U2, OP_FCONV_TO_U2-CEE_CONV_U2, OP_PCONV_TO_U2-CEE_CONV_U2, OP_PCONV_TO_U2-CEE_CONV_U2, 0, OP_RCONV_TO_U2-CEE_CONV_U2
885 };
886
887 /* handles from CEE_CONV_OVF_I1_UN to CEE_CONV_OVF_U_UN */
888 static const guint16
889 ovf2ops_op_map [STACK_MAX] = {
890         0, OP_ICONV_TO_OVF_I1_UN-CEE_CONV_OVF_I1_UN, OP_LCONV_TO_OVF_I1_UN-CEE_CONV_OVF_I1_UN, OP_PCONV_TO_OVF_I1_UN-CEE_CONV_OVF_I1_UN, OP_FCONV_TO_OVF_I1_UN-CEE_CONV_OVF_I1_UN, OP_PCONV_TO_OVF_I1_UN-CEE_CONV_OVF_I1_UN, 0, 0, OP_RCONV_TO_OVF_I1_UN-CEE_CONV_OVF_I1_UN
891 };
892
893 /* handles from CEE_CONV_OVF_I1 to CEE_CONV_OVF_U8 */
894 static const guint16
895 ovf3ops_op_map [STACK_MAX] = {
896         0, OP_ICONV_TO_OVF_I1-CEE_CONV_OVF_I1, OP_LCONV_TO_OVF_I1-CEE_CONV_OVF_I1, OP_PCONV_TO_OVF_I1-CEE_CONV_OVF_I1, OP_FCONV_TO_OVF_I1-CEE_CONV_OVF_I1, OP_PCONV_TO_OVF_I1-CEE_CONV_OVF_I1, 0, 0, OP_RCONV_TO_OVF_I1-CEE_CONV_OVF_I1
897 };
898
899 /* handles from CEE_BEQ to CEE_BLT_UN */
900 static const guint16
901 beqops_op_map [STACK_MAX] = {
902         0, OP_IBEQ-CEE_BEQ, OP_LBEQ-CEE_BEQ, OP_PBEQ-CEE_BEQ, OP_FBEQ-CEE_BEQ, OP_PBEQ-CEE_BEQ, OP_PBEQ-CEE_BEQ, 0, OP_FBEQ-CEE_BEQ
903 };
904
905 /* handles from CEE_CEQ to CEE_CLT_UN */
906 static const guint16
907 ceqops_op_map [STACK_MAX] = {
908         0, OP_ICEQ-OP_CEQ, OP_LCEQ-OP_CEQ, OP_PCEQ-OP_CEQ, OP_FCEQ-OP_CEQ, OP_PCEQ-OP_CEQ, OP_PCEQ-OP_CEQ, 0, OP_RCEQ-OP_CEQ
909 };
910
911 /*
912  * Sets ins->type (the type on the eval stack) according to the
913  * type of the opcode and the arguments to it.
914  * Invalid IL code is marked by setting ins->type to the invalid value STACK_INV.
915  *
916  * FIXME: this function sets ins->type unconditionally in some cases, but
917  * it should set it to invalid for some types (a conv.x on an object)
918  */
919 static void
920 type_from_op (MonoCompile *cfg, MonoInst *ins, MonoInst *src1, MonoInst *src2)
921 {
922         switch (ins->opcode) {
923         /* binops */
924         case CEE_ADD:
925         case CEE_SUB:
926         case CEE_MUL:
927         case CEE_DIV:
928         case CEE_REM:
929                 /* FIXME: check unverifiable args for STACK_MP */
930                 ins->type = bin_num_table [src1->type] [src2->type];
931                 ins->opcode += binops_op_map [ins->type];
932                 break;
933         case CEE_DIV_UN:
934         case CEE_REM_UN:
935         case CEE_AND:
936         case CEE_OR:
937         case CEE_XOR:
938                 ins->type = bin_int_table [src1->type] [src2->type];
939                 ins->opcode += binops_op_map [ins->type];
940                 break;
941         case CEE_SHL:
942         case CEE_SHR:
943         case CEE_SHR_UN:
944                 ins->type = shift_table [src1->type] [src2->type];
945                 ins->opcode += binops_op_map [ins->type];
946                 break;
947         case OP_COMPARE:
948         case OP_LCOMPARE:
949         case OP_ICOMPARE:
950                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
951                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
952                         ins->opcode = OP_LCOMPARE;
953                 else if (src1->type == STACK_R4)
954                         ins->opcode = OP_RCOMPARE;
955                 else if (src1->type == STACK_R8)
956                         ins->opcode = OP_FCOMPARE;
957                 else
958                         ins->opcode = OP_ICOMPARE;
959                 break;
960         case OP_ICOMPARE_IMM:
961                 ins->type = bin_comp_table [src1->type] [src1->type] ? STACK_I4 : STACK_INV;
962                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
963                         ins->opcode = OP_LCOMPARE_IMM;          
964                 break;
965         case CEE_BEQ:
966         case CEE_BGE:
967         case CEE_BGT:
968         case CEE_BLE:
969         case CEE_BLT:
970         case CEE_BNE_UN:
971         case CEE_BGE_UN:
972         case CEE_BGT_UN:
973         case CEE_BLE_UN:
974         case CEE_BLT_UN:
975                 ins->opcode += beqops_op_map [src1->type];
976                 break;
977         case OP_CEQ:
978                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
979                 ins->opcode += ceqops_op_map [src1->type];
980                 break;
981         case OP_CGT:
982         case OP_CGT_UN:
983         case OP_CLT:
984         case OP_CLT_UN:
985                 ins->type = (bin_comp_table [src1->type] [src2->type] & 1) ? STACK_I4: STACK_INV;
986                 ins->opcode += ceqops_op_map [src1->type];
987                 break;
988         /* unops */
989         case CEE_NEG:
990                 ins->type = neg_table [src1->type];
991                 ins->opcode += unops_op_map [ins->type];
992                 break;
993         case CEE_NOT:
994                 if (src1->type >= STACK_I4 && src1->type <= STACK_PTR)
995                         ins->type = src1->type;
996                 else
997                         ins->type = STACK_INV;
998                 ins->opcode += unops_op_map [ins->type];
999                 break;
1000         case CEE_CONV_I1:
1001         case CEE_CONV_I2:
1002         case CEE_CONV_I4:
1003         case CEE_CONV_U4:
1004                 ins->type = STACK_I4;
1005                 ins->opcode += unops_op_map [src1->type];
1006                 break;
1007         case CEE_CONV_R_UN:
1008                 ins->type = STACK_R8;
1009                 switch (src1->type) {
1010                 case STACK_I4:
1011                 case STACK_PTR:
1012                         ins->opcode = OP_ICONV_TO_R_UN;
1013                         break;
1014                 case STACK_I8:
1015                         ins->opcode = OP_LCONV_TO_R_UN; 
1016                         break;
1017                 }
1018                 break;
1019         case CEE_CONV_OVF_I1:
1020         case CEE_CONV_OVF_U1:
1021         case CEE_CONV_OVF_I2:
1022         case CEE_CONV_OVF_U2:
1023         case CEE_CONV_OVF_I4:
1024         case CEE_CONV_OVF_U4:
1025                 ins->type = STACK_I4;
1026                 ins->opcode += ovf3ops_op_map [src1->type];
1027                 break;
1028         case CEE_CONV_OVF_I_UN:
1029         case CEE_CONV_OVF_U_UN:
1030                 ins->type = STACK_PTR;
1031                 ins->opcode += ovf2ops_op_map [src1->type];
1032                 break;
1033         case CEE_CONV_OVF_I1_UN:
1034         case CEE_CONV_OVF_I2_UN:
1035         case CEE_CONV_OVF_I4_UN:
1036         case CEE_CONV_OVF_U1_UN:
1037         case CEE_CONV_OVF_U2_UN:
1038         case CEE_CONV_OVF_U4_UN:
1039                 ins->type = STACK_I4;
1040                 ins->opcode += ovf2ops_op_map [src1->type];
1041                 break;
1042         case CEE_CONV_U:
1043                 ins->type = STACK_PTR;
1044                 switch (src1->type) {
1045                 case STACK_I4:
1046                         ins->opcode = OP_ICONV_TO_U;
1047                         break;
1048                 case STACK_PTR:
1049                 case STACK_MP:
1050 #if SIZEOF_VOID_P == 8
1051                         ins->opcode = OP_LCONV_TO_U;
1052 #else
1053                         ins->opcode = OP_MOVE;
1054 #endif
1055                         break;
1056                 case STACK_I8:
1057                         ins->opcode = OP_LCONV_TO_U;
1058                         break;
1059                 case STACK_R8:
1060                         ins->opcode = OP_FCONV_TO_U;
1061                         break;
1062                 }
1063                 break;
1064         case CEE_CONV_I8:
1065         case CEE_CONV_U8:
1066                 ins->type = STACK_I8;
1067                 ins->opcode += unops_op_map [src1->type];
1068                 break;
1069         case CEE_CONV_OVF_I8:
1070         case CEE_CONV_OVF_U8:
1071                 ins->type = STACK_I8;
1072                 ins->opcode += ovf3ops_op_map [src1->type];
1073                 break;
1074         case CEE_CONV_OVF_U8_UN:
1075         case CEE_CONV_OVF_I8_UN:
1076                 ins->type = STACK_I8;
1077                 ins->opcode += ovf2ops_op_map [src1->type];
1078                 break;
1079         case CEE_CONV_R4:
1080                 ins->type = cfg->r4_stack_type;
1081                 ins->opcode += unops_op_map [src1->type];
1082                 break;
1083         case CEE_CONV_R8:
1084                 ins->type = STACK_R8;
1085                 ins->opcode += unops_op_map [src1->type];
1086                 break;
1087         case OP_CKFINITE:
1088                 ins->type = STACK_R8;           
1089                 break;
1090         case CEE_CONV_U2:
1091         case CEE_CONV_U1:
1092                 ins->type = STACK_I4;
1093                 ins->opcode += ovfops_op_map [src1->type];
1094                 break;
1095         case CEE_CONV_I:
1096         case CEE_CONV_OVF_I:
1097         case CEE_CONV_OVF_U:
1098                 ins->type = STACK_PTR;
1099                 ins->opcode += ovfops_op_map [src1->type];
1100                 break;
1101         case CEE_ADD_OVF:
1102         case CEE_ADD_OVF_UN:
1103         case CEE_MUL_OVF:
1104         case CEE_MUL_OVF_UN:
1105         case CEE_SUB_OVF:
1106         case CEE_SUB_OVF_UN:
1107                 ins->type = bin_num_table [src1->type] [src2->type];
1108                 ins->opcode += ovfops_op_map [src1->type];
1109                 if (ins->type == STACK_R8)
1110                         ins->type = STACK_INV;
1111                 break;
1112         case OP_LOAD_MEMBASE:
1113                 ins->type = STACK_PTR;
1114                 break;
1115         case OP_LOADI1_MEMBASE:
1116         case OP_LOADU1_MEMBASE:
1117         case OP_LOADI2_MEMBASE:
1118         case OP_LOADU2_MEMBASE:
1119         case OP_LOADI4_MEMBASE:
1120         case OP_LOADU4_MEMBASE:
1121                 ins->type = STACK_PTR;
1122                 break;
1123         case OP_LOADI8_MEMBASE:
1124                 ins->type = STACK_I8;
1125                 break;
1126         case OP_LOADR4_MEMBASE:
1127                 ins->type = cfg->r4_stack_type;
1128                 break;
1129         case OP_LOADR8_MEMBASE:
1130                 ins->type = STACK_R8;
1131                 break;
1132         default:
1133                 g_error ("opcode 0x%04x not handled in type from op", ins->opcode);
1134                 break;
1135         }
1136
1137         if (ins->type == STACK_MP)
1138                 ins->klass = mono_defaults.object_class;
1139 }
1140
1141 static const char 
1142 ldind_type [] = {
1143         STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_R8, STACK_OBJ
1144 };
1145
1146 #if 0
1147
1148 static const char
1149 param_table [STACK_MAX] [STACK_MAX] = {
1150         {0},
1151 };
1152
1153 static int
1154 check_values_to_signature (MonoInst *args, MonoType *this_ins, MonoMethodSignature *sig)
1155 {
1156         int i;
1157
1158         if (sig->hasthis) {
1159                 switch (args->type) {
1160                 case STACK_I4:
1161                 case STACK_I8:
1162                 case STACK_R8:
1163                 case STACK_VTYPE:
1164                 case STACK_INV:
1165                         return 0;
1166                 }
1167                 args++;
1168         }
1169         for (i = 0; i < sig->param_count; ++i) {
1170                 switch (args [i].type) {
1171                 case STACK_INV:
1172                         return 0;
1173                 case STACK_MP:
1174                         if (!sig->params [i]->byref)
1175                                 return 0;
1176                         continue;
1177                 case STACK_OBJ:
1178                         if (sig->params [i]->byref)
1179                                 return 0;
1180                         switch (sig->params [i]->type) {
1181                         case MONO_TYPE_CLASS:
1182                         case MONO_TYPE_STRING:
1183                         case MONO_TYPE_OBJECT:
1184                         case MONO_TYPE_SZARRAY:
1185                         case MONO_TYPE_ARRAY:
1186                                 break;
1187                         default:
1188                                 return 0;
1189                         }
1190                         continue;
1191                 case STACK_R8:
1192                         if (sig->params [i]->byref)
1193                                 return 0;
1194                         if (sig->params [i]->type != MONO_TYPE_R4 && sig->params [i]->type != MONO_TYPE_R8)
1195                                 return 0;
1196                         continue;
1197                 case STACK_PTR:
1198                 case STACK_I4:
1199                 case STACK_I8:
1200                 case STACK_VTYPE:
1201                         break;
1202                 }
1203                 /*if (!param_table [args [i].type] [sig->params [i]->type])
1204                         return 0;*/
1205         }
1206         return 1;
1207 }
1208 #endif
1209
1210 /*
1211  * When we need a pointer to the current domain many times in a method, we
1212  * call mono_domain_get() once and we store the result in a local variable.
1213  * This function returns the variable that represents the MonoDomain*.
1214  */
1215 inline static MonoInst *
1216 mono_get_domainvar (MonoCompile *cfg)
1217 {
1218         if (!cfg->domainvar)
1219                 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1220         return cfg->domainvar;
1221 }
1222
1223 /*
1224  * The got_var contains the address of the Global Offset Table when AOT 
1225  * compiling.
1226  */
1227 MonoInst *
1228 mono_get_got_var (MonoCompile *cfg)
1229 {
1230 #ifdef MONO_ARCH_NEED_GOT_VAR
1231         if (!cfg->compile_aot)
1232                 return NULL;
1233         if (!cfg->got_var) {
1234                 cfg->got_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1235         }
1236         return cfg->got_var;
1237 #else
1238         return NULL;
1239 #endif
1240 }
1241
1242 static MonoInst *
1243 mono_get_vtable_var (MonoCompile *cfg)
1244 {
1245         g_assert (cfg->gshared);
1246
1247         if (!cfg->rgctx_var) {
1248                 cfg->rgctx_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1249                 /* force the var to be stack allocated */
1250                 cfg->rgctx_var->flags |= MONO_INST_VOLATILE;
1251         }
1252
1253         return cfg->rgctx_var;
1254 }
1255
1256 static MonoType*
1257 type_from_stack_type (MonoInst *ins) {
1258         switch (ins->type) {
1259         case STACK_I4: return &mono_defaults.int32_class->byval_arg;
1260         case STACK_I8: return &mono_defaults.int64_class->byval_arg;
1261         case STACK_PTR: return &mono_defaults.int_class->byval_arg;
1262         case STACK_R4: return &mono_defaults.single_class->byval_arg;
1263         case STACK_R8: return &mono_defaults.double_class->byval_arg;
1264         case STACK_MP:
1265                 return &ins->klass->this_arg;
1266         case STACK_OBJ: return &mono_defaults.object_class->byval_arg;
1267         case STACK_VTYPE: return &ins->klass->byval_arg;
1268         default:
1269                 g_error ("stack type %d to monotype not handled\n", ins->type);
1270         }
1271         return NULL;
1272 }
1273
1274 static G_GNUC_UNUSED int
1275 type_to_stack_type (MonoCompile *cfg, MonoType *t)
1276 {
1277         t = mono_type_get_underlying_type (t);
1278         switch (t->type) {
1279         case MONO_TYPE_I1:
1280         case MONO_TYPE_U1:
1281         case MONO_TYPE_I2:
1282         case MONO_TYPE_U2:
1283         case MONO_TYPE_I4:
1284         case MONO_TYPE_U4:
1285                 return STACK_I4;
1286         case MONO_TYPE_I:
1287         case MONO_TYPE_U:
1288         case MONO_TYPE_PTR:
1289         case MONO_TYPE_FNPTR:
1290                 return STACK_PTR;
1291         case MONO_TYPE_CLASS:
1292         case MONO_TYPE_STRING:
1293         case MONO_TYPE_OBJECT:
1294         case MONO_TYPE_SZARRAY:
1295         case MONO_TYPE_ARRAY:    
1296                 return STACK_OBJ;
1297         case MONO_TYPE_I8:
1298         case MONO_TYPE_U8:
1299                 return STACK_I8;
1300         case MONO_TYPE_R4:
1301                 return cfg->r4_stack_type;
1302         case MONO_TYPE_R8:
1303                 return STACK_R8;
1304         case MONO_TYPE_VALUETYPE:
1305         case MONO_TYPE_TYPEDBYREF:
1306                 return STACK_VTYPE;
1307         case MONO_TYPE_GENERICINST:
1308                 if (mono_type_generic_inst_is_valuetype (t))
1309                         return STACK_VTYPE;
1310                 else
1311                         return STACK_OBJ;
1312                 break;
1313         default:
1314                 g_assert_not_reached ();
1315         }
1316
1317         return -1;
1318 }
1319
1320 static MonoClass*
1321 array_access_to_klass (int opcode)
1322 {
1323         switch (opcode) {
1324         case CEE_LDELEM_U1:
1325                 return mono_defaults.byte_class;
1326         case CEE_LDELEM_U2:
1327                 return mono_defaults.uint16_class;
1328         case CEE_LDELEM_I:
1329         case CEE_STELEM_I:
1330                 return mono_defaults.int_class;
1331         case CEE_LDELEM_I1:
1332         case CEE_STELEM_I1:
1333                 return mono_defaults.sbyte_class;
1334         case CEE_LDELEM_I2:
1335         case CEE_STELEM_I2:
1336                 return mono_defaults.int16_class;
1337         case CEE_LDELEM_I4:
1338         case CEE_STELEM_I4:
1339                 return mono_defaults.int32_class;
1340         case CEE_LDELEM_U4:
1341                 return mono_defaults.uint32_class;
1342         case CEE_LDELEM_I8:
1343         case CEE_STELEM_I8:
1344                 return mono_defaults.int64_class;
1345         case CEE_LDELEM_R4:
1346         case CEE_STELEM_R4:
1347                 return mono_defaults.single_class;
1348         case CEE_LDELEM_R8:
1349         case CEE_STELEM_R8:
1350                 return mono_defaults.double_class;
1351         case CEE_LDELEM_REF:
1352         case CEE_STELEM_REF:
1353                 return mono_defaults.object_class;
1354         default:
1355                 g_assert_not_reached ();
1356         }
1357         return NULL;
1358 }
1359
1360 /*
1361  * We try to share variables when possible
1362  */
1363 static MonoInst *
1364 mono_compile_get_interface_var (MonoCompile *cfg, int slot, MonoInst *ins)
1365 {
1366         MonoInst *res;
1367         int pos, vnum;
1368
1369         /* inlining can result in deeper stacks */ 
1370         if (slot >= cfg->header->max_stack)
1371                 return mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1372
1373         pos = ins->type - 1 + slot * STACK_MAX;
1374
1375         switch (ins->type) {
1376         case STACK_I4:
1377         case STACK_I8:
1378         case STACK_R8:
1379         case STACK_PTR:
1380         case STACK_MP:
1381         case STACK_OBJ:
1382                 if ((vnum = cfg->intvars [pos]))
1383                         return cfg->varinfo [vnum];
1384                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1385                 cfg->intvars [pos] = res->inst_c0;
1386                 break;
1387         default:
1388                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1389         }
1390         return res;
1391 }
1392
1393 static void
1394 mono_save_token_info (MonoCompile *cfg, MonoImage *image, guint32 token, gpointer key)
1395 {
1396         /* 
1397          * Don't use this if a generic_context is set, since that means AOT can't
1398          * look up the method using just the image+token.
1399          * table == 0 means this is a reference made from a wrapper.
1400          */
1401         if (cfg->compile_aot && !cfg->generic_context && (mono_metadata_token_table (token) > 0)) {
1402                 MonoJumpInfoToken *jump_info_token = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoToken));
1403                 jump_info_token->image = image;
1404                 jump_info_token->token = token;
1405                 g_hash_table_insert (cfg->token_info_hash, key, jump_info_token);
1406         }
1407 }
1408
1409 /*
1410  * This function is called to handle items that are left on the evaluation stack
1411  * at basic block boundaries. What happens is that we save the values to local variables
1412  * and we reload them later when first entering the target basic block (with the
1413  * handle_loaded_temps () function).
1414  * A single joint point will use the same variables (stored in the array bb->out_stack or
1415  * bb->in_stack, if the basic block is before or after the joint point).
1416  *
1417  * This function needs to be called _before_ emitting the last instruction of
1418  * the bb (i.e. before emitting a branch).
1419  * If the stack merge fails at a join point, cfg->unverifiable is set.
1420  */
1421 static void
1422 handle_stack_args (MonoCompile *cfg, MonoInst **sp, int count)
1423 {
1424         int i, bindex;
1425         MonoBasicBlock *bb = cfg->cbb;
1426         MonoBasicBlock *outb;
1427         MonoInst *inst, **locals;
1428         gboolean found;
1429
1430         if (!count)
1431                 return;
1432         if (cfg->verbose_level > 3)
1433                 printf ("%d item(s) on exit from B%d\n", count, bb->block_num);
1434         if (!bb->out_scount) {
1435                 bb->out_scount = count;
1436                 //printf ("bblock %d has out:", bb->block_num);
1437                 found = FALSE;
1438                 for (i = 0; i < bb->out_count; ++i) {
1439                         outb = bb->out_bb [i];
1440                         /* exception handlers are linked, but they should not be considered for stack args */
1441                         if (outb->flags & BB_EXCEPTION_HANDLER)
1442                                 continue;
1443                         //printf (" %d", outb->block_num);
1444                         if (outb->in_stack) {
1445                                 found = TRUE;
1446                                 bb->out_stack = outb->in_stack;
1447                                 break;
1448                         }
1449                 }
1450                 //printf ("\n");
1451                 if (!found) {
1452                         bb->out_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * count);
1453                         for (i = 0; i < count; ++i) {
1454                                 /* 
1455                                  * try to reuse temps already allocated for this purpouse, if they occupy the same
1456                                  * stack slot and if they are of the same type.
1457                                  * This won't cause conflicts since if 'local' is used to 
1458                                  * store one of the values in the in_stack of a bblock, then
1459                                  * the same variable will be used for the same outgoing stack 
1460                                  * slot as well. 
1461                                  * This doesn't work when inlining methods, since the bblocks
1462                                  * in the inlined methods do not inherit their in_stack from
1463                                  * the bblock they are inlined to. See bug #58863 for an
1464                                  * example.
1465                                  */
1466                                 if (cfg->inlined_method)
1467                                         bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
1468                                 else
1469                                         bb->out_stack [i] = mono_compile_get_interface_var (cfg, i, sp [i]);
1470                         }
1471                 }
1472         }
1473
1474         for (i = 0; i < bb->out_count; ++i) {
1475                 outb = bb->out_bb [i];
1476                 /* exception handlers are linked, but they should not be considered for stack args */
1477                 if (outb->flags & BB_EXCEPTION_HANDLER)
1478                         continue;
1479                 if (outb->in_scount) {
1480                         if (outb->in_scount != bb->out_scount) {
1481                                 cfg->unverifiable = TRUE;
1482                                 return;
1483                         }
1484                         continue; /* check they are the same locals */
1485                 }
1486                 outb->in_scount = count;
1487                 outb->in_stack = bb->out_stack;
1488         }
1489
1490         locals = bb->out_stack;
1491         cfg->cbb = bb;
1492         for (i = 0; i < count; ++i) {
1493                 EMIT_NEW_TEMPSTORE (cfg, inst, locals [i]->inst_c0, sp [i]);
1494                 inst->cil_code = sp [i]->cil_code;
1495                 sp [i] = locals [i];
1496                 if (cfg->verbose_level > 3)
1497                         printf ("storing %d to temp %d\n", i, (int)locals [i]->inst_c0);
1498         }
1499
1500         /*
1501          * It is possible that the out bblocks already have in_stack assigned, and
1502          * the in_stacks differ. In this case, we will store to all the different 
1503          * in_stacks.
1504          */
1505
1506         found = TRUE;
1507         bindex = 0;
1508         while (found) {
1509                 /* Find a bblock which has a different in_stack */
1510                 found = FALSE;
1511                 while (bindex < bb->out_count) {
1512                         outb = bb->out_bb [bindex];
1513                         /* exception handlers are linked, but they should not be considered for stack args */
1514                         if (outb->flags & BB_EXCEPTION_HANDLER) {
1515                                 bindex++;
1516                                 continue;
1517                         }
1518                         if (outb->in_stack != locals) {
1519                                 for (i = 0; i < count; ++i) {
1520                                         EMIT_NEW_TEMPSTORE (cfg, inst, outb->in_stack [i]->inst_c0, sp [i]);
1521                                         inst->cil_code = sp [i]->cil_code;
1522                                         sp [i] = locals [i];
1523                                         if (cfg->verbose_level > 3)
1524                                                 printf ("storing %d to temp %d\n", i, (int)outb->in_stack [i]->inst_c0);
1525                                 }
1526                                 locals = outb->in_stack;
1527                                 found = TRUE;
1528                                 break;
1529                         }
1530                         bindex ++;
1531                 }
1532         }
1533 }
1534
1535 static void
1536 mini_emit_interface_bitmap_check (MonoCompile *cfg, int intf_bit_reg, int base_reg, int offset, MonoClass *klass)
1537 {
1538         int ibitmap_reg = alloc_preg (cfg);
1539 #ifdef COMPRESSED_INTERFACE_BITMAP
1540         MonoInst *args [2];
1541         MonoInst *res, *ins;
1542         NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, ibitmap_reg, base_reg, offset);
1543         MONO_ADD_INS (cfg->cbb, ins);
1544         args [0] = ins;
1545         if (cfg->compile_aot)
1546                 EMIT_NEW_AOTCONST (cfg, args [1], MONO_PATCH_INFO_IID, klass);
1547         else
1548                 EMIT_NEW_ICONST (cfg, args [1], klass->interface_id);
1549         res = mono_emit_jit_icall (cfg, mono_class_interface_match, args);
1550         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, intf_bit_reg, res->dreg);
1551 #else
1552         int ibitmap_byte_reg = alloc_preg (cfg);
1553
1554         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, ibitmap_reg, base_reg, offset);
1555
1556         if (cfg->compile_aot) {
1557                 int iid_reg = alloc_preg (cfg);
1558                 int shifted_iid_reg = alloc_preg (cfg);
1559                 int ibitmap_byte_address_reg = alloc_preg (cfg);
1560                 int masked_iid_reg = alloc_preg (cfg);
1561                 int iid_one_bit_reg = alloc_preg (cfg);
1562                 int iid_bit_reg = alloc_preg (cfg);
1563                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1564                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, shifted_iid_reg, iid_reg, 3);
1565                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, ibitmap_byte_address_reg, ibitmap_reg, shifted_iid_reg);
1566                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, ibitmap_byte_reg, ibitmap_byte_address_reg, 0);
1567                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, masked_iid_reg, iid_reg, 7);
1568                 MONO_EMIT_NEW_ICONST (cfg, iid_one_bit_reg, 1);
1569                 MONO_EMIT_NEW_BIALU (cfg, OP_ISHL, iid_bit_reg, iid_one_bit_reg, masked_iid_reg);
1570                 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, intf_bit_reg, ibitmap_byte_reg, iid_bit_reg);
1571         } else {
1572                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, ibitmap_byte_reg, ibitmap_reg, klass->interface_id >> 3);
1573                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, intf_bit_reg, ibitmap_byte_reg, 1 << (klass->interface_id & 7));
1574         }
1575 #endif
1576 }
1577
1578 /* 
1579  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoClass
1580  * stored in "klass_reg" implements the interface "klass".
1581  */
1582 static void
1583 mini_emit_load_intf_bit_reg_class (MonoCompile *cfg, int intf_bit_reg, int klass_reg, MonoClass *klass)
1584 {
1585         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, interface_bitmap), klass);
1586 }
1587
1588 /* 
1589  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoVTable
1590  * stored in "vtable_reg" implements the interface "klass".
1591  */
1592 static void
1593 mini_emit_load_intf_bit_reg_vtable (MonoCompile *cfg, int intf_bit_reg, int vtable_reg, MonoClass *klass)
1594 {
1595         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, interface_bitmap), klass);
1596 }
1597
1598 /* 
1599  * Emit code which checks whenever the interface id of @klass is smaller than
1600  * than the value given by max_iid_reg.
1601 */
1602 static void
1603 mini_emit_max_iid_check (MonoCompile *cfg, int max_iid_reg, MonoClass *klass,
1604                                                  MonoBasicBlock *false_target)
1605 {
1606         if (cfg->compile_aot) {
1607                 int iid_reg = alloc_preg (cfg);
1608                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1609                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, max_iid_reg, iid_reg);
1610         }
1611         else
1612                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, max_iid_reg, klass->interface_id);
1613         if (false_target)
1614                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1615         else
1616                 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1617 }
1618
1619 /* Same as above, but obtains max_iid from a vtable */
1620 static void
1621 mini_emit_max_iid_check_vtable (MonoCompile *cfg, int vtable_reg, MonoClass *klass,
1622                                                                  MonoBasicBlock *false_target)
1623 {
1624         int max_iid_reg = alloc_preg (cfg);
1625                 
1626         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, max_interface_id));
1627         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1628 }
1629
1630 /* Same as above, but obtains max_iid from a klass */
1631 static void
1632 mini_emit_max_iid_check_class (MonoCompile *cfg, int klass_reg, MonoClass *klass,
1633                                                                  MonoBasicBlock *false_target)
1634 {
1635         int max_iid_reg = alloc_preg (cfg);
1636
1637         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, max_interface_id));
1638         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1639 }
1640
1641 static void
1642 mini_emit_isninst_cast_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_ins, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1643 {
1644         int idepth_reg = alloc_preg (cfg);
1645         int stypes_reg = alloc_preg (cfg);
1646         int stype = alloc_preg (cfg);
1647
1648         mono_class_setup_supertypes (klass);
1649
1650         if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1651                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth));
1652                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1653                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1654         }
1655         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes));
1656         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1657         if (klass_ins) {
1658                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, klass_ins->dreg);
1659         } else if (cfg->compile_aot) {
1660                 int const_reg = alloc_preg (cfg);
1661                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1662                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, const_reg);
1663         } else {
1664                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, stype, klass);
1665         }
1666         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, true_target);
1667 }
1668
1669 static void
1670 mini_emit_isninst_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1671 {
1672         mini_emit_isninst_cast_inst (cfg, klass_reg, klass, NULL, false_target, true_target);
1673 }
1674
1675 static void
1676 mini_emit_iface_cast (MonoCompile *cfg, int vtable_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1677 {
1678         int intf_reg = alloc_preg (cfg);
1679
1680         mini_emit_max_iid_check_vtable (cfg, vtable_reg, klass, false_target);
1681         mini_emit_load_intf_bit_reg_vtable (cfg, intf_reg, vtable_reg, klass);
1682         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_reg, 0);
1683         if (true_target)
1684                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1685         else
1686                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");               
1687 }
1688
1689 /*
1690  * Variant of the above that takes a register to the class, not the vtable.
1691  */
1692 static void
1693 mini_emit_iface_class_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1694 {
1695         int intf_bit_reg = alloc_preg (cfg);
1696
1697         mini_emit_max_iid_check_class (cfg, klass_reg, klass, false_target);
1698         mini_emit_load_intf_bit_reg_class (cfg, intf_bit_reg, klass_reg, klass);
1699         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_bit_reg, 0);
1700         if (true_target)
1701                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1702         else
1703                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
1704 }
1705
1706 static inline void
1707 mini_emit_class_check_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_inst)
1708 {
1709         if (klass_inst) {
1710                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_inst->dreg);
1711         } else if (cfg->compile_aot) {
1712                 int const_reg = alloc_preg (cfg);
1713                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1714                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, const_reg);
1715         } else {
1716                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
1717         }
1718         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1719 }
1720
1721 static inline void
1722 mini_emit_class_check (MonoCompile *cfg, int klass_reg, MonoClass *klass)
1723 {
1724         mini_emit_class_check_inst (cfg, klass_reg, klass, NULL);
1725 }
1726
1727 static inline void
1728 mini_emit_class_check_branch (MonoCompile *cfg, int klass_reg, MonoClass *klass, int branch_op, MonoBasicBlock *target)
1729 {
1730         if (cfg->compile_aot) {
1731                 int const_reg = alloc_preg (cfg);
1732                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1733                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, const_reg);
1734         } else {
1735                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
1736         }
1737         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, branch_op, target);
1738 }
1739
1740 static void
1741 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null);
1742         
1743 static void
1744 mini_emit_castclass_inst (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoInst *klass_inst, MonoBasicBlock *object_is_null)
1745 {
1746         if (klass->rank) {
1747                 int rank_reg = alloc_preg (cfg);
1748                 int eclass_reg = alloc_preg (cfg);
1749
1750                 g_assert (!klass_inst);
1751                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, rank));
1752                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
1753                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1754                 //              MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
1755                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
1756                 if (klass->cast_class == mono_defaults.object_class) {
1757                         int parent_reg = alloc_preg (cfg);
1758                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
1759                         mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, object_is_null);
1760                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1761                 } else if (klass->cast_class == mono_defaults.enum_class->parent) {
1762                         mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, object_is_null);
1763                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1764                 } else if (klass->cast_class == mono_defaults.enum_class) {
1765                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1766                 } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1767                         mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, NULL, NULL);
1768                 } else {
1769                         // Pass -1 as obj_reg to skip the check below for arrays of arrays
1770                         mini_emit_castclass (cfg, -1, eclass_reg, klass->cast_class, object_is_null);
1771                 }
1772
1773                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY) && (obj_reg != -1)) {
1774                         /* Check that the object is a vector too */
1775                         int bounds_reg = alloc_preg (cfg);
1776                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
1777                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
1778                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1779                 }
1780         } else {
1781                 int idepth_reg = alloc_preg (cfg);
1782                 int stypes_reg = alloc_preg (cfg);
1783                 int stype = alloc_preg (cfg);
1784
1785                 mono_class_setup_supertypes (klass);
1786
1787                 if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1788                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth));
1789                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1790                         MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1791                 }
1792                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes));
1793                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1794                 mini_emit_class_check_inst (cfg, stype, klass, klass_inst);
1795         }
1796 }
1797
1798 static void
1799 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null)
1800 {
1801         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, NULL, object_is_null);
1802 }
1803
1804 static void 
1805 mini_emit_memset (MonoCompile *cfg, int destreg, int offset, int size, int val, int align)
1806 {
1807         int val_reg;
1808
1809         g_assert (val == 0);
1810
1811         if (align == 0)
1812                 align = 4;
1813
1814         if ((size <= SIZEOF_REGISTER) && (size <= align)) {
1815                 switch (size) {
1816                 case 1:
1817                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, destreg, offset, val);
1818                         return;
1819                 case 2:
1820                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI2_MEMBASE_IMM, destreg, offset, val);
1821                         return;
1822                 case 4:
1823                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI4_MEMBASE_IMM, destreg, offset, val);
1824                         return;
1825 #if SIZEOF_REGISTER == 8
1826                 case 8:
1827                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI8_MEMBASE_IMM, destreg, offset, val);
1828                         return;
1829 #endif
1830                 }
1831         }
1832
1833         val_reg = alloc_preg (cfg);
1834
1835         if (SIZEOF_REGISTER == 8)
1836                 MONO_EMIT_NEW_I8CONST (cfg, val_reg, val);
1837         else
1838                 MONO_EMIT_NEW_ICONST (cfg, val_reg, val);
1839
1840         if (align < 4) {
1841                 /* This could be optimized further if neccesary */
1842                 while (size >= 1) {
1843                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1844                         offset += 1;
1845                         size -= 1;
1846                 }
1847                 return;
1848         }       
1849
1850 #if !NO_UNALIGNED_ACCESS
1851         if (SIZEOF_REGISTER == 8) {
1852                 if (offset % 8) {
1853                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1854                         offset += 4;
1855                         size -= 4;
1856                 }
1857                 while (size >= 8) {
1858                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, offset, val_reg);
1859                         offset += 8;
1860                         size -= 8;
1861                 }
1862         }       
1863 #endif
1864
1865         while (size >= 4) {
1866                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1867                 offset += 4;
1868                 size -= 4;
1869         }
1870         while (size >= 2) {
1871                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, val_reg);
1872                 offset += 2;
1873                 size -= 2;
1874         }
1875         while (size >= 1) {
1876                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1877                 offset += 1;
1878                 size -= 1;
1879         }
1880 }
1881
1882 void 
1883 mini_emit_memcpy (MonoCompile *cfg, int destreg, int doffset, int srcreg, int soffset, int size, int align)
1884 {
1885         int cur_reg;
1886
1887         if (align == 0)
1888                 align = 4;
1889
1890         /*FIXME arbitrary hack to avoid unbound code expansion.*/
1891         g_assert (size < 10000);
1892
1893         if (align < 4) {
1894                 /* This could be optimized further if neccesary */
1895                 while (size >= 1) {
1896                         cur_reg = alloc_preg (cfg);
1897                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1898                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1899                         doffset += 1;
1900                         soffset += 1;
1901                         size -= 1;
1902                 }
1903         }
1904
1905 #if !NO_UNALIGNED_ACCESS
1906         if (SIZEOF_REGISTER == 8) {
1907                 while (size >= 8) {
1908                         cur_reg = alloc_preg (cfg);
1909                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI8_MEMBASE, cur_reg, srcreg, soffset);
1910                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, doffset, cur_reg);
1911                         doffset += 8;
1912                         soffset += 8;
1913                         size -= 8;
1914                 }
1915         }       
1916 #endif
1917
1918         while (size >= 4) {
1919                 cur_reg = alloc_preg (cfg);
1920                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, cur_reg, srcreg, soffset);
1921                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, doffset, cur_reg);
1922                 doffset += 4;
1923                 soffset += 4;
1924                 size -= 4;
1925         }
1926         while (size >= 2) {
1927                 cur_reg = alloc_preg (cfg);
1928                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, cur_reg, srcreg, soffset);
1929                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, doffset, cur_reg);
1930                 doffset += 2;
1931                 soffset += 2;
1932                 size -= 2;
1933         }
1934         while (size >= 1) {
1935                 cur_reg = alloc_preg (cfg);
1936                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1937                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1938                 doffset += 1;
1939                 soffset += 1;
1940                 size -= 1;
1941         }
1942 }
1943
1944 static void
1945 emit_tls_set (MonoCompile *cfg, int sreg1, int tls_key)
1946 {
1947         MonoInst *ins, *c;
1948
1949         if (cfg->compile_aot) {
1950                 EMIT_NEW_TLS_OFFSETCONST (cfg, c, tls_key);
1951                 MONO_INST_NEW (cfg, ins, OP_TLS_SET_REG);
1952                 ins->sreg1 = sreg1;
1953                 ins->sreg2 = c->dreg;
1954                 MONO_ADD_INS (cfg->cbb, ins);
1955         } else {
1956                 MONO_INST_NEW (cfg, ins, OP_TLS_SET);
1957                 ins->sreg1 = sreg1;
1958                 ins->inst_offset = mini_get_tls_offset (tls_key);
1959                 MONO_ADD_INS (cfg->cbb, ins);
1960         }
1961 }
1962
1963 /*
1964  * emit_push_lmf:
1965  *
1966  *   Emit IR to push the current LMF onto the LMF stack.
1967  */
1968 static void
1969 emit_push_lmf (MonoCompile *cfg)
1970 {
1971         /*
1972          * Emit IR to push the LMF:
1973          * lmf_addr = <lmf_addr from tls>
1974          * lmf->lmf_addr = lmf_addr
1975          * lmf->prev_lmf = *lmf_addr
1976          * *lmf_addr = lmf
1977          */
1978         int lmf_reg, prev_lmf_reg;
1979         MonoInst *ins, *lmf_ins;
1980
1981         if (!cfg->lmf_ir)
1982                 return;
1983
1984         if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
1985                 /* Load current lmf */
1986                 lmf_ins = mono_get_lmf_intrinsic (cfg);
1987                 g_assert (lmf_ins);
1988                 MONO_ADD_INS (cfg->cbb, lmf_ins);
1989                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
1990                 lmf_reg = ins->dreg;
1991                 /* Save previous_lmf */
1992                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), lmf_ins->dreg);
1993                 /* Set new LMF */
1994                 emit_tls_set (cfg, lmf_reg, TLS_KEY_LMF);
1995         } else {
1996                 /*
1997                  * Store lmf_addr in a variable, so it can be allocated to a global register.
1998                  */
1999                 if (!cfg->lmf_addr_var)
2000                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2001
2002 #ifdef HOST_WIN32
2003                 ins = mono_get_jit_tls_intrinsic (cfg);
2004                 if (ins) {
2005                         int jit_tls_dreg = ins->dreg;
2006
2007                         MONO_ADD_INS (cfg->cbb, ins);
2008                         lmf_reg = alloc_preg (cfg);
2009                         EMIT_NEW_BIALU_IMM (cfg, lmf_ins, OP_PADD_IMM, lmf_reg, jit_tls_dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, lmf));
2010                 } else {
2011                         lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
2012                 }
2013 #else
2014                 lmf_ins = mono_get_lmf_addr_intrinsic (cfg);
2015                 if (lmf_ins) {
2016                         MONO_ADD_INS (cfg->cbb, lmf_ins);
2017                 } else {
2018 #ifdef TARGET_IOS
2019                         MonoInst *args [16], *jit_tls_ins, *ins;
2020
2021                         /* Inline mono_get_lmf_addr () */
2022                         /* jit_tls = pthread_getspecific (mono_jit_tls_id); lmf_addr = &jit_tls->lmf; */
2023
2024                         /* Load mono_jit_tls_id */
2025                         if (cfg->compile_aot)
2026                                 EMIT_NEW_AOTCONST (cfg, args [0], MONO_PATCH_INFO_JIT_TLS_ID, NULL);
2027                         else
2028                                 EMIT_NEW_ICONST (cfg, args [0], mono_jit_tls_id);
2029                         /* call pthread_getspecific () */
2030                         jit_tls_ins = mono_emit_jit_icall (cfg, pthread_getspecific, args);
2031                         /* lmf_addr = &jit_tls->lmf */
2032                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, cfg->lmf_addr_var->dreg, jit_tls_ins->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, lmf));
2033                         lmf_ins = ins;
2034 #else
2035                         lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
2036 #endif
2037                 }
2038 #endif
2039                 lmf_ins->dreg = cfg->lmf_addr_var->dreg;
2040
2041                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2042                 lmf_reg = ins->dreg;
2043
2044                 prev_lmf_reg = alloc_preg (cfg);
2045                 /* Save previous_lmf */
2046                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, cfg->lmf_addr_var->dreg, 0);
2047                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), prev_lmf_reg);
2048                 /* Set new lmf */
2049                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, cfg->lmf_addr_var->dreg, 0, lmf_reg);
2050         }
2051 }
2052
2053 /*
2054  * emit_pop_lmf:
2055  *
2056  *   Emit IR to pop the current LMF from the LMF stack.
2057  */
2058 static void
2059 emit_pop_lmf (MonoCompile *cfg)
2060 {
2061         int lmf_reg, lmf_addr_reg, prev_lmf_reg;
2062         MonoInst *ins;
2063
2064         if (!cfg->lmf_ir)
2065                 return;
2066
2067         EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2068         lmf_reg = ins->dreg;
2069
2070         if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
2071                 /* Load previous_lmf */
2072                 prev_lmf_reg = alloc_preg (cfg);
2073                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
2074                 /* Set new LMF */
2075                 emit_tls_set (cfg, prev_lmf_reg, TLS_KEY_LMF);
2076         } else {
2077                 /*
2078                  * Emit IR to pop the LMF:
2079                  * *(lmf->lmf_addr) = lmf->prev_lmf
2080                  */
2081                 /* This could be called before emit_push_lmf () */
2082                 if (!cfg->lmf_addr_var)
2083                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2084                 lmf_addr_reg = cfg->lmf_addr_var->dreg;
2085
2086                 prev_lmf_reg = alloc_preg (cfg);
2087                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
2088                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_addr_reg, 0, prev_lmf_reg);
2089         }
2090 }
2091
2092 static void
2093 emit_instrumentation_call (MonoCompile *cfg, void *func)
2094 {
2095         MonoInst *iargs [1];
2096
2097         /*
2098          * Avoid instrumenting inlined methods since it can
2099          * distort profiling results.
2100          */
2101         if (cfg->method != cfg->current_method)
2102                 return;
2103
2104         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE) {
2105                 EMIT_NEW_METHODCONST (cfg, iargs [0], cfg->method);
2106                 mono_emit_jit_icall (cfg, func, iargs);
2107         }
2108 }
2109
2110 static int
2111 ret_type_to_call_opcode (MonoCompile *cfg, MonoType *type, int calli, int virt)
2112 {
2113 handle_enum:
2114         type = mini_get_underlying_type (type);
2115         switch (type->type) {
2116         case MONO_TYPE_VOID:
2117                 return calli? OP_VOIDCALL_REG: virt? OP_VOIDCALL_MEMBASE: OP_VOIDCALL;
2118         case MONO_TYPE_I1:
2119         case MONO_TYPE_U1:
2120         case MONO_TYPE_I2:
2121         case MONO_TYPE_U2:
2122         case MONO_TYPE_I4:
2123         case MONO_TYPE_U4:
2124                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2125         case MONO_TYPE_I:
2126         case MONO_TYPE_U:
2127         case MONO_TYPE_PTR:
2128         case MONO_TYPE_FNPTR:
2129                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2130         case MONO_TYPE_CLASS:
2131         case MONO_TYPE_STRING:
2132         case MONO_TYPE_OBJECT:
2133         case MONO_TYPE_SZARRAY:
2134         case MONO_TYPE_ARRAY:    
2135                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2136         case MONO_TYPE_I8:
2137         case MONO_TYPE_U8:
2138                 return calli? OP_LCALL_REG: virt? OP_LCALL_MEMBASE: OP_LCALL;
2139         case MONO_TYPE_R4:
2140                 if (cfg->r4fp)
2141                         return calli? OP_RCALL_REG: virt? OP_RCALL_MEMBASE: OP_RCALL;
2142                 else
2143                         return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
2144         case MONO_TYPE_R8:
2145                 return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
2146         case MONO_TYPE_VALUETYPE:
2147                 if (type->data.klass->enumtype) {
2148                         type = mono_class_enum_basetype (type->data.klass);
2149                         goto handle_enum;
2150                 } else
2151                         return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2152         case MONO_TYPE_TYPEDBYREF:
2153                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2154         case MONO_TYPE_GENERICINST:
2155                 type = &type->data.generic_class->container_class->byval_arg;
2156                 goto handle_enum;
2157         case MONO_TYPE_VAR:
2158         case MONO_TYPE_MVAR:
2159                 /* gsharedvt */
2160                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2161         default:
2162                 g_error ("unknown type 0x%02x in ret_type_to_call_opcode", type->type);
2163         }
2164         return -1;
2165 }
2166
2167 /*
2168  * target_type_is_incompatible:
2169  * @cfg: MonoCompile context
2170  *
2171  * Check that the item @arg on the evaluation stack can be stored
2172  * in the target type (can be a local, or field, etc).
2173  * The cfg arg can be used to check if we need verification or just
2174  * validity checks.
2175  *
2176  * Returns: non-0 value if arg can't be stored on a target.
2177  */
2178 static int
2179 target_type_is_incompatible (MonoCompile *cfg, MonoType *target, MonoInst *arg)
2180 {
2181         MonoType *simple_type;
2182         MonoClass *klass;
2183
2184         if (target->byref) {
2185                 /* FIXME: check that the pointed to types match */
2186                 if (arg->type == STACK_MP)
2187                         return arg->klass != mono_class_from_mono_type (target);
2188                 if (arg->type == STACK_PTR)
2189                         return 0;
2190                 return 1;
2191         }
2192
2193         simple_type = mini_get_underlying_type (target);
2194         switch (simple_type->type) {
2195         case MONO_TYPE_VOID:
2196                 return 1;
2197         case MONO_TYPE_I1:
2198         case MONO_TYPE_U1:
2199         case MONO_TYPE_I2:
2200         case MONO_TYPE_U2:
2201         case MONO_TYPE_I4:
2202         case MONO_TYPE_U4:
2203                 if (arg->type != STACK_I4 && arg->type != STACK_PTR)
2204                         return 1;
2205                 return 0;
2206         case MONO_TYPE_PTR:
2207                 /* STACK_MP is needed when setting pinned locals */
2208                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2209                         return 1;
2210                 return 0;
2211         case MONO_TYPE_I:
2212         case MONO_TYPE_U:
2213         case MONO_TYPE_FNPTR:
2214                 /* 
2215                  * Some opcodes like ldloca returns 'transient pointers' which can be stored in
2216                  * in native int. (#688008).
2217                  */
2218                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2219                         return 1;
2220                 return 0;
2221         case MONO_TYPE_CLASS:
2222         case MONO_TYPE_STRING:
2223         case MONO_TYPE_OBJECT:
2224         case MONO_TYPE_SZARRAY:
2225         case MONO_TYPE_ARRAY:    
2226                 if (arg->type != STACK_OBJ)
2227                         return 1;
2228                 /* FIXME: check type compatibility */
2229                 return 0;
2230         case MONO_TYPE_I8:
2231         case MONO_TYPE_U8:
2232                 if (arg->type != STACK_I8)
2233                         return 1;
2234                 return 0;
2235         case MONO_TYPE_R4:
2236                 if (arg->type != cfg->r4_stack_type)
2237                         return 1;
2238                 return 0;
2239         case MONO_TYPE_R8:
2240                 if (arg->type != STACK_R8)
2241                         return 1;
2242                 return 0;
2243         case MONO_TYPE_VALUETYPE:
2244                 if (arg->type != STACK_VTYPE)
2245                         return 1;
2246                 klass = mono_class_from_mono_type (simple_type);
2247                 if (klass != arg->klass)
2248                         return 1;
2249                 return 0;
2250         case MONO_TYPE_TYPEDBYREF:
2251                 if (arg->type != STACK_VTYPE)
2252                         return 1;
2253                 klass = mono_class_from_mono_type (simple_type);
2254                 if (klass != arg->klass)
2255                         return 1;
2256                 return 0;
2257         case MONO_TYPE_GENERICINST:
2258                 if (mono_type_generic_inst_is_valuetype (simple_type)) {
2259                         if (arg->type != STACK_VTYPE)
2260                                 return 1;
2261                         klass = mono_class_from_mono_type (simple_type);
2262                         /* The second cases is needed when doing partial sharing */
2263                         if (klass != arg->klass && mono_class_from_mono_type (target) != arg->klass)
2264                                 return 1;
2265                         return 0;
2266                 } else {
2267                         if (arg->type != STACK_OBJ)
2268                                 return 1;
2269                         /* FIXME: check type compatibility */
2270                         return 0;
2271                 }
2272         case MONO_TYPE_VAR:
2273         case MONO_TYPE_MVAR:
2274                 g_assert (cfg->gshared);
2275                 if (mini_type_var_is_vt (simple_type)) {
2276                         if (arg->type != STACK_VTYPE)
2277                                 return 1;
2278                 } else {
2279                         if (arg->type != STACK_OBJ)
2280                                 return 1;
2281                 }
2282                 return 0;
2283         default:
2284                 g_error ("unknown type 0x%02x in target_type_is_incompatible", simple_type->type);
2285         }
2286         return 1;
2287 }
2288
2289 /*
2290  * Prepare arguments for passing to a function call.
2291  * Return a non-zero value if the arguments can't be passed to the given
2292  * signature.
2293  * The type checks are not yet complete and some conversions may need
2294  * casts on 32 or 64 bit architectures.
2295  *
2296  * FIXME: implement this using target_type_is_incompatible ()
2297  */
2298 static int
2299 check_call_signature (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args)
2300 {
2301         MonoType *simple_type;
2302         int i;
2303
2304         if (sig->hasthis) {
2305                 if (args [0]->type != STACK_OBJ && args [0]->type != STACK_MP && args [0]->type != STACK_PTR)
2306                         return 1;
2307                 args++;
2308         }
2309         for (i = 0; i < sig->param_count; ++i) {
2310                 if (sig->params [i]->byref) {
2311                         if (args [i]->type != STACK_MP && args [i]->type != STACK_PTR)
2312                                 return 1;
2313                         continue;
2314                 }
2315                 simple_type = mini_get_underlying_type (sig->params [i]);
2316 handle_enum:
2317                 switch (simple_type->type) {
2318                 case MONO_TYPE_VOID:
2319                         return 1;
2320                         continue;
2321                 case MONO_TYPE_I1:
2322                 case MONO_TYPE_U1:
2323                 case MONO_TYPE_I2:
2324                 case MONO_TYPE_U2:
2325                 case MONO_TYPE_I4:
2326                 case MONO_TYPE_U4:
2327                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR)
2328                                 return 1;
2329                         continue;
2330                 case MONO_TYPE_I:
2331                 case MONO_TYPE_U:
2332                 case MONO_TYPE_PTR:
2333                 case MONO_TYPE_FNPTR:
2334                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR && args [i]->type != STACK_MP && args [i]->type != STACK_OBJ)
2335                                 return 1;
2336                         continue;
2337                 case MONO_TYPE_CLASS:
2338                 case MONO_TYPE_STRING:
2339                 case MONO_TYPE_OBJECT:
2340                 case MONO_TYPE_SZARRAY:
2341                 case MONO_TYPE_ARRAY:    
2342                         if (args [i]->type != STACK_OBJ)
2343                                 return 1;
2344                         continue;
2345                 case MONO_TYPE_I8:
2346                 case MONO_TYPE_U8:
2347                         if (args [i]->type != STACK_I8)
2348                                 return 1;
2349                         continue;
2350                 case MONO_TYPE_R4:
2351                         if (args [i]->type != cfg->r4_stack_type)
2352                                 return 1;
2353                         continue;
2354                 case MONO_TYPE_R8:
2355                         if (args [i]->type != STACK_R8)
2356                                 return 1;
2357                         continue;
2358                 case MONO_TYPE_VALUETYPE:
2359                         if (simple_type->data.klass->enumtype) {
2360                                 simple_type = mono_class_enum_basetype (simple_type->data.klass);
2361                                 goto handle_enum;
2362                         }
2363                         if (args [i]->type != STACK_VTYPE)
2364                                 return 1;
2365                         continue;
2366                 case MONO_TYPE_TYPEDBYREF:
2367                         if (args [i]->type != STACK_VTYPE)
2368                                 return 1;
2369                         continue;
2370                 case MONO_TYPE_GENERICINST:
2371                         simple_type = &simple_type->data.generic_class->container_class->byval_arg;
2372                         goto handle_enum;
2373                 case MONO_TYPE_VAR:
2374                 case MONO_TYPE_MVAR:
2375                         /* gsharedvt */
2376                         if (args [i]->type != STACK_VTYPE)
2377                                 return 1;
2378                         continue;
2379                 default:
2380                         g_error ("unknown type 0x%02x in check_call_signature",
2381                                  simple_type->type);
2382                 }
2383         }
2384         return 0;
2385 }
2386
2387 static int
2388 callvirt_to_call (int opcode)
2389 {
2390         switch (opcode) {
2391         case OP_CALL_MEMBASE:
2392                 return OP_CALL;
2393         case OP_VOIDCALL_MEMBASE:
2394                 return OP_VOIDCALL;
2395         case OP_FCALL_MEMBASE:
2396                 return OP_FCALL;
2397         case OP_RCALL_MEMBASE:
2398                 return OP_RCALL;
2399         case OP_VCALL_MEMBASE:
2400                 return OP_VCALL;
2401         case OP_LCALL_MEMBASE:
2402                 return OP_LCALL;
2403         default:
2404                 g_assert_not_reached ();
2405         }
2406
2407         return -1;
2408 }
2409
2410 static int
2411 callvirt_to_call_reg (int opcode)
2412 {
2413         switch (opcode) {
2414         case OP_CALL_MEMBASE:
2415                 return OP_CALL_REG;
2416         case OP_VOIDCALL_MEMBASE:
2417                 return OP_VOIDCALL_REG;
2418         case OP_FCALL_MEMBASE:
2419                 return OP_FCALL_REG;
2420         case OP_RCALL_MEMBASE:
2421                 return OP_RCALL_REG;
2422         case OP_VCALL_MEMBASE:
2423                 return OP_VCALL_REG;
2424         case OP_LCALL_MEMBASE:
2425                 return OP_LCALL_REG;
2426         default:
2427                 g_assert_not_reached ();
2428         }
2429
2430         return -1;
2431 }
2432
2433 /* Either METHOD or IMT_ARG needs to be set */
2434 static void
2435 emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoMethod *method, MonoInst *imt_arg)
2436 {
2437         int method_reg;
2438
2439         if (COMPILE_LLVM (cfg)) {
2440                 method_reg = alloc_preg (cfg);
2441
2442                 if (imt_arg) {
2443                         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2444                 } else if (cfg->compile_aot) {
2445                         MONO_EMIT_NEW_AOTCONST (cfg, method_reg, method, MONO_PATCH_INFO_METHODCONST);
2446                 } else {
2447                         MonoInst *ins;
2448                         MONO_INST_NEW (cfg, ins, OP_PCONST);
2449                         ins->inst_p0 = method;
2450                         ins->dreg = method_reg;
2451                         MONO_ADD_INS (cfg->cbb, ins);
2452                 }
2453
2454 #ifdef ENABLE_LLVM
2455                 call->imt_arg_reg = method_reg;
2456 #endif
2457         mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2458                 return;
2459         }
2460
2461         method_reg = alloc_preg (cfg);
2462
2463         if (imt_arg) {
2464                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2465         } else if (cfg->compile_aot) {
2466                 MONO_EMIT_NEW_AOTCONST (cfg, method_reg, method, MONO_PATCH_INFO_METHODCONST);
2467         } else {
2468                 MonoInst *ins;
2469                 MONO_INST_NEW (cfg, ins, OP_PCONST);
2470                 ins->inst_p0 = method;
2471                 ins->dreg = method_reg;
2472                 MONO_ADD_INS (cfg->cbb, ins);
2473         }
2474
2475         mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2476 }
2477
2478 static MonoJumpInfo *
2479 mono_patch_info_new (MonoMemPool *mp, int ip, MonoJumpInfoType type, gconstpointer target)
2480 {
2481         MonoJumpInfo *ji = mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
2482
2483         ji->ip.i = ip;
2484         ji->type = type;
2485         ji->data.target = target;
2486
2487         return ji;
2488 }
2489
2490 static int
2491 mini_class_check_context_used (MonoCompile *cfg, MonoClass *klass)
2492 {
2493         if (cfg->gshared)
2494                 return mono_class_check_context_used (klass);
2495         else
2496                 return 0;
2497 }
2498
2499 static int
2500 mini_method_check_context_used (MonoCompile *cfg, MonoMethod *method)
2501 {
2502         if (cfg->gshared)
2503                 return mono_method_check_context_used (method);
2504         else
2505                 return 0;
2506 }
2507
2508 /*
2509  * check_method_sharing:
2510  *
2511  *   Check whenever the vtable or an mrgctx needs to be passed when calling CMETHOD.
2512  */
2513 static void
2514 check_method_sharing (MonoCompile *cfg, MonoMethod *cmethod, gboolean *out_pass_vtable, gboolean *out_pass_mrgctx)
2515 {
2516         gboolean pass_vtable = FALSE;
2517         gboolean pass_mrgctx = FALSE;
2518
2519         if (((cmethod->flags & METHOD_ATTRIBUTE_STATIC) || cmethod->klass->valuetype) &&
2520                 (cmethod->klass->generic_class || cmethod->klass->generic_container)) {
2521                 gboolean sharable = FALSE;
2522
2523                 if (mono_method_is_generic_sharable_full (cmethod, TRUE, TRUE, TRUE))
2524                         sharable = TRUE;
2525
2526                 /*
2527                  * Pass vtable iff target method might
2528                  * be shared, which means that sharing
2529                  * is enabled for its class and its
2530                  * context is sharable (and it's not a
2531                  * generic method).
2532                  */
2533                 if (sharable && !(mini_method_get_context (cmethod) && mini_method_get_context (cmethod)->method_inst))
2534                         pass_vtable = TRUE;
2535         }
2536
2537         if (mini_method_get_context (cmethod) &&
2538                 mini_method_get_context (cmethod)->method_inst) {
2539                 g_assert (!pass_vtable);
2540
2541                 if (mono_method_is_generic_sharable_full (cmethod, TRUE, TRUE, TRUE)) {
2542                         pass_mrgctx = TRUE;
2543                 } else {
2544                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (mono_method_signature (cmethod)))
2545                                 pass_mrgctx = TRUE;
2546                 }
2547         }
2548
2549         if (out_pass_vtable)
2550                 *out_pass_vtable = pass_vtable;
2551         if (out_pass_mrgctx)
2552                 *out_pass_mrgctx = pass_mrgctx;
2553 }
2554
2555 inline static MonoCallInst *
2556 mono_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig, 
2557                                          MonoInst **args, int calli, int virtual, int tail, int rgctx, int unbox_trampoline)
2558 {
2559         MonoType *sig_ret;
2560         MonoCallInst *call;
2561 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2562         int i;
2563 #endif
2564
2565         if (tail) {
2566                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
2567
2568                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
2569         } else
2570                 MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (cfg, sig->ret, calli, virtual));
2571
2572         call->args = args;
2573         call->signature = sig;
2574         call->rgctx_reg = rgctx;
2575         sig_ret = mini_get_underlying_type (sig->ret);
2576
2577         type_to_eval_stack_type ((cfg), sig_ret, &call->inst);
2578
2579         if (tail) {
2580                 if (mini_type_is_vtype (sig_ret)) {
2581                         call->vret_var = cfg->vret_addr;
2582                         //g_assert_not_reached ();
2583                 }
2584         } else if (mini_type_is_vtype (sig_ret)) {
2585                 MonoInst *temp = mono_compile_create_var (cfg, sig_ret, OP_LOCAL);
2586                 MonoInst *loada;
2587
2588                 temp->backend.is_pinvoke = sig->pinvoke;
2589
2590                 /*
2591                  * We use a new opcode OP_OUTARG_VTRETADDR instead of LDADDR for emitting the
2592                  * address of return value to increase optimization opportunities.
2593                  * Before vtype decomposition, the dreg of the call ins itself represents the
2594                  * fact the call modifies the return value. After decomposition, the call will
2595                  * be transformed into one of the OP_VOIDCALL opcodes, and the VTRETADDR opcode
2596                  * will be transformed into an LDADDR.
2597                  */
2598                 MONO_INST_NEW (cfg, loada, OP_OUTARG_VTRETADDR);
2599                 loada->dreg = alloc_preg (cfg);
2600                 loada->inst_p0 = temp;
2601                 /* We reference the call too since call->dreg could change during optimization */
2602                 loada->inst_p1 = call;
2603                 MONO_ADD_INS (cfg->cbb, loada);
2604
2605                 call->inst.dreg = temp->dreg;
2606
2607                 call->vret_var = loada;
2608         } else if (!MONO_TYPE_IS_VOID (sig_ret))
2609                 call->inst.dreg = alloc_dreg (cfg, call->inst.type);
2610
2611 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2612         if (COMPILE_SOFT_FLOAT (cfg)) {
2613                 /* 
2614                  * If the call has a float argument, we would need to do an r8->r4 conversion using 
2615                  * an icall, but that cannot be done during the call sequence since it would clobber
2616                  * the call registers + the stack. So we do it before emitting the call.
2617                  */
2618                 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2619                         MonoType *t;
2620                         MonoInst *in = call->args [i];
2621
2622                         if (i >= sig->hasthis)
2623                                 t = sig->params [i - sig->hasthis];
2624                         else
2625                                 t = &mono_defaults.int_class->byval_arg;
2626                         t = mono_type_get_underlying_type (t);
2627
2628                         if (!t->byref && t->type == MONO_TYPE_R4) {
2629                                 MonoInst *iargs [1];
2630                                 MonoInst *conv;
2631
2632                                 iargs [0] = in;
2633                                 conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
2634
2635                                 /* The result will be in an int vreg */
2636                                 call->args [i] = conv;
2637                         }
2638                 }
2639         }
2640 #endif
2641
2642         call->need_unbox_trampoline = unbox_trampoline;
2643
2644 #ifdef ENABLE_LLVM
2645         if (COMPILE_LLVM (cfg))
2646                 mono_llvm_emit_call (cfg, call);
2647         else
2648                 mono_arch_emit_call (cfg, call);
2649 #else
2650         mono_arch_emit_call (cfg, call);
2651 #endif
2652
2653         cfg->param_area = MAX (cfg->param_area, call->stack_usage);
2654         cfg->flags |= MONO_CFG_HAS_CALLS;
2655         
2656         return call;
2657 }
2658
2659 static void
2660 set_rgctx_arg (MonoCompile *cfg, MonoCallInst *call, int rgctx_reg, MonoInst *rgctx_arg)
2661 {
2662 #ifdef MONO_ARCH_RGCTX_REG
2663         mono_call_inst_add_outarg_reg (cfg, call, rgctx_reg, MONO_ARCH_RGCTX_REG, FALSE);
2664         cfg->uses_rgctx_reg = TRUE;
2665         call->rgctx_reg = TRUE;
2666 #ifdef ENABLE_LLVM
2667         call->rgctx_arg_reg = rgctx_reg;
2668 #endif
2669 #else
2670         NOT_IMPLEMENTED;
2671 #endif
2672 }       
2673
2674 inline static MonoInst*
2675 mono_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr, MonoInst *imt_arg, MonoInst *rgctx_arg)
2676 {
2677         MonoCallInst *call;
2678         MonoInst *ins;
2679         int rgctx_reg = -1;
2680         gboolean check_sp = FALSE;
2681
2682         if (cfg->check_pinvoke_callconv && cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
2683                 WrapperInfo *info = mono_marshal_get_wrapper_info (cfg->method);
2684
2685                 if (info && info->subtype == WRAPPER_SUBTYPE_PINVOKE)
2686                         check_sp = TRUE;
2687         }
2688
2689         if (rgctx_arg) {
2690                 rgctx_reg = mono_alloc_preg (cfg);
2691                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2692         }
2693
2694         if (check_sp) {
2695                 if (!cfg->stack_inbalance_var)
2696                         cfg->stack_inbalance_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2697
2698                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2699                 ins->dreg = cfg->stack_inbalance_var->dreg;
2700                 MONO_ADD_INS (cfg->cbb, ins);
2701         }
2702
2703         call = mono_emit_call_args (cfg, sig, args, TRUE, FALSE, FALSE, rgctx_arg ? TRUE : FALSE, FALSE);
2704
2705         call->inst.sreg1 = addr->dreg;
2706
2707         if (imt_arg)
2708                 emit_imt_argument (cfg, call, NULL, imt_arg);
2709
2710         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2711
2712         if (check_sp) {
2713                 int sp_reg;
2714
2715                 sp_reg = mono_alloc_preg (cfg);
2716
2717                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2718                 ins->dreg = sp_reg;
2719                 MONO_ADD_INS (cfg->cbb, ins);
2720
2721                 /* Restore the stack so we don't crash when throwing the exception */
2722                 MONO_INST_NEW (cfg, ins, OP_SET_SP);
2723                 ins->sreg1 = cfg->stack_inbalance_var->dreg;
2724                 MONO_ADD_INS (cfg->cbb, ins);
2725
2726                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, cfg->stack_inbalance_var->dreg, sp_reg);
2727                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ExecutionEngineException");
2728         }
2729
2730         if (rgctx_arg)
2731                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2732
2733         return (MonoInst*)call;
2734 }
2735
2736 static MonoInst*
2737 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2738
2739 static MonoInst*
2740 emit_get_rgctx_method (MonoCompile *cfg, int context_used, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type);
2741 static MonoInst*
2742 emit_get_rgctx_klass (MonoCompile *cfg, int context_used, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2743
2744 static MonoInst*
2745 mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSignature *sig, gboolean tail,
2746                                                         MonoInst **args, MonoInst *this_ins, MonoInst *imt_arg, MonoInst *rgctx_arg)
2747 {
2748 #ifndef DISABLE_REMOTING
2749         gboolean might_be_remote = FALSE;
2750 #endif
2751         gboolean virtual = this_ins != NULL;
2752         gboolean enable_for_aot = TRUE;
2753         int context_used;
2754         MonoCallInst *call;
2755         MonoInst *call_target = NULL;
2756         int rgctx_reg = 0;
2757         gboolean need_unbox_trampoline;
2758
2759         if (!sig)
2760                 sig = mono_method_signature (method);
2761
2762         if (cfg->llvm_only && (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2763                 MonoInst *icall_args [16];
2764                 MonoInst *ins;
2765
2766                 // FIXME: Optimize this
2767
2768                 guint32 imt_slot = mono_method_get_imt_slot (method);
2769
2770                 icall_args [0] = this_ins;
2771                 EMIT_NEW_ICONST (cfg, icall_args [1], imt_slot);
2772                 if (imt_arg) {
2773                         icall_args [2] = imt_arg;
2774                 } else {
2775                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_METHODCONST, method);
2776                         icall_args [2] = ins;
2777                 }
2778                 EMIT_NEW_PCONST (cfg, icall_args [3], NULL);
2779
2780                 call_target = mono_emit_jit_icall (cfg, mono_resolve_iface_call, icall_args);
2781         }
2782
2783         if (rgctx_arg) {
2784                 rgctx_reg = mono_alloc_preg (cfg);
2785                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2786         }
2787
2788         if (method->string_ctor) {
2789                 /* Create the real signature */
2790                 /* FIXME: Cache these */
2791                 MonoMethodSignature *ctor_sig = mono_metadata_signature_dup_mempool (cfg->mempool, sig);
2792                 ctor_sig->ret = &mono_defaults.string_class->byval_arg;
2793
2794                 sig = ctor_sig;
2795         }
2796
2797         context_used = mini_method_check_context_used (cfg, method);
2798
2799 #ifndef DISABLE_REMOTING
2800         might_be_remote = this_ins && sig->hasthis &&
2801                 (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) &&
2802                 !(method->flags & METHOD_ATTRIBUTE_VIRTUAL) && (!MONO_CHECK_THIS (this_ins) || context_used);
2803
2804         if (might_be_remote && context_used) {
2805                 MonoInst *addr;
2806
2807                 g_assert (cfg->gshared);
2808
2809                 addr = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK);
2810
2811                 return mono_emit_calli (cfg, sig, args, addr, NULL, NULL);
2812         }
2813 #endif
2814
2815         if (cfg->llvm_only && !call_target && virtual && (method->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
2816                 // FIXME: Vcall optimizations below
2817                 MonoInst *icall_args [16];
2818                 MonoInst *ins;
2819
2820                 if (sig->generic_param_count) {
2821                         /*
2822                          * Generic virtual call, pass the concrete method as the imt argument.
2823                          */
2824                         imt_arg = emit_get_rgctx_method (cfg, context_used,
2825                                                                                          method, MONO_RGCTX_INFO_METHOD);
2826                 }
2827
2828                 // FIXME: Optimize this
2829
2830                 int slot = mono_method_get_vtable_index (method);
2831
2832                 icall_args [0] = this_ins;
2833                 EMIT_NEW_ICONST (cfg, icall_args [1], slot);
2834                 if (imt_arg) {
2835                         icall_args [2] = imt_arg;
2836                 } else {
2837                         EMIT_NEW_PCONST (cfg, ins, NULL);
2838                         icall_args [2] = ins;
2839                 }
2840                 call_target = mono_emit_jit_icall (cfg, mono_resolve_vcall, icall_args);
2841         }
2842
2843         need_unbox_trampoline = method->klass == mono_defaults.object_class || (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE);
2844
2845         call = mono_emit_call_args (cfg, sig, args, FALSE, virtual, tail, rgctx_arg ? TRUE : FALSE, need_unbox_trampoline);
2846
2847 #ifndef DISABLE_REMOTING
2848         if (might_be_remote)
2849                 call->method = mono_marshal_get_remoting_invoke_with_check (method);
2850         else
2851 #endif
2852                 call->method = method;
2853         call->inst.flags |= MONO_INST_HAS_METHOD;
2854         call->inst.inst_left = this_ins;
2855         call->tail_call = tail;
2856
2857         if (virtual) {
2858                 int vtable_reg, slot_reg, this_reg;
2859                 int offset;
2860
2861                 this_reg = this_ins->dreg;
2862
2863                 if (!cfg->llvm_only && (method->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (method->name, "Invoke")) {
2864                         MonoInst *dummy_use;
2865
2866                         MONO_EMIT_NULL_CHECK (cfg, this_reg);
2867
2868                         /* Make a call to delegate->invoke_impl */
2869                         call->inst.inst_basereg = this_reg;
2870                         call->inst.inst_offset = MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl);
2871                         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2872
2873                         /* We must emit a dummy use here because the delegate trampoline will
2874                         replace the 'this' argument with the delegate target making this activation
2875                         no longer a root for the delegate.
2876                         This is an issue for delegates that target collectible code such as dynamic
2877                         methods of GC'able assemblies.
2878
2879                         For a test case look into #667921.
2880
2881                         FIXME: a dummy use is not the best way to do it as the local register allocator
2882                         will put it on a caller save register and spil it around the call. 
2883                         Ideally, we would either put it on a callee save register or only do the store part.  
2884                          */
2885                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, args [0]);
2886
2887                         return (MonoInst*)call;
2888                 }
2889
2890                 if ((!cfg->compile_aot || enable_for_aot) && 
2891                         (!(method->flags & METHOD_ATTRIBUTE_VIRTUAL) || 
2892                          (MONO_METHOD_IS_FINAL (method) &&
2893                           method->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)) &&
2894                         !(mono_class_is_marshalbyref (method->klass) && context_used)) {
2895                         /* 
2896                          * the method is not virtual, we just need to ensure this is not null
2897                          * and then we can call the method directly.
2898                          */
2899 #ifndef DISABLE_REMOTING
2900                         if (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) {
2901                                 /* 
2902                                  * The check above ensures method is not gshared, this is needed since
2903                                  * gshared methods can't have wrappers.
2904                                  */
2905                                 method = call->method = mono_marshal_get_remoting_invoke_with_check (method);
2906                         }
2907 #endif
2908
2909                         if (!method->string_ctor)
2910                                 MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2911
2912                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2913                 } else if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && MONO_METHOD_IS_FINAL (method)) {
2914                         /*
2915                          * the method is virtual, but we can statically dispatch since either
2916                          * it's class or the method itself are sealed.
2917                          * But first we need to ensure it's not a null reference.
2918                          */
2919                         MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2920
2921                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2922                 } else if (call_target) {
2923                         vtable_reg = alloc_preg (cfg);
2924                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
2925
2926                         call->inst.opcode = callvirt_to_call_reg (call->inst.opcode);
2927                         call->inst.sreg1 = call_target->dreg;
2928                         call->inst.flags &= !MONO_INST_HAS_METHOD;
2929                 } else {
2930                         vtable_reg = alloc_preg (cfg);
2931                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
2932                         if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2933                                 guint32 imt_slot = mono_method_get_imt_slot (method);
2934                                 emit_imt_argument (cfg, call, call->method, imt_arg);
2935                                 slot_reg = vtable_reg;
2936                                 offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
2937                         } else {
2938                                 slot_reg = vtable_reg;
2939                                 offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) +
2940                                         ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
2941                                 if (imt_arg) {
2942                                         g_assert (mono_method_signature (method)->generic_param_count);
2943                                         emit_imt_argument (cfg, call, call->method, imt_arg);
2944                                 }
2945                         }
2946
2947                         call->inst.sreg1 = slot_reg;
2948                         call->inst.inst_offset = offset;
2949                         call->virtual = TRUE;
2950                 }
2951         }
2952
2953         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2954
2955         if (rgctx_arg)
2956                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2957
2958         return (MonoInst*)call;
2959 }
2960
2961 MonoInst*
2962 mono_emit_method_call (MonoCompile *cfg, MonoMethod *method, MonoInst **args, MonoInst *this_ins)
2963 {
2964         return mono_emit_method_call_full (cfg, method, mono_method_signature (method), FALSE, args, this_ins, NULL, NULL);
2965 }
2966
2967 MonoInst*
2968 mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig,
2969                                            MonoInst **args)
2970 {
2971         MonoCallInst *call;
2972
2973         g_assert (sig);
2974
2975         call = mono_emit_call_args (cfg, sig, args, FALSE, FALSE, FALSE, FALSE, FALSE);
2976         call->fptr = func;
2977
2978         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2979
2980         return (MonoInst*)call;
2981 }
2982
2983 MonoInst*
2984 mono_emit_jit_icall (MonoCompile *cfg, gconstpointer func, MonoInst **args)
2985 {
2986         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (func);
2987
2988         g_assert (info);
2989
2990         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
2991 }
2992
2993 /*
2994  * mono_emit_abs_call:
2995  *
2996  *   Emit a call to the runtime function described by PATCH_TYPE and DATA.
2997  */
2998 inline static MonoInst*
2999 mono_emit_abs_call (MonoCompile *cfg, MonoJumpInfoType patch_type, gconstpointer data, 
3000                                         MonoMethodSignature *sig, MonoInst **args)
3001 {
3002         MonoJumpInfo *ji = mono_patch_info_new (cfg->mempool, 0, patch_type, data);
3003         MonoInst *ins;
3004
3005         /* 
3006          * We pass ji as the call address, the PATCH_INFO_ABS resolving code will
3007          * handle it.
3008          */
3009         if (cfg->abs_patches == NULL)
3010                 cfg->abs_patches = g_hash_table_new (NULL, NULL);
3011         g_hash_table_insert (cfg->abs_patches, ji, ji);
3012         ins = mono_emit_native_call (cfg, ji, sig, args);
3013         ((MonoCallInst*)ins)->fptr_is_patch = TRUE;
3014         return ins;
3015 }
3016
3017 static gboolean
3018 direct_icalls_enabled (MonoCompile *cfg)
3019 {
3020         /* LLVM on amd64 can't handle calls to non-32 bit addresses */
3021 #ifdef TARGET_AMD64
3022         if (cfg->compile_llvm)
3023                 return FALSE;
3024 #endif
3025         if (cfg->gen_sdb_seq_points || cfg->disable_direct_icalls)
3026                 return FALSE;
3027         return TRUE;
3028 }
3029
3030 MonoInst*
3031 mono_emit_jit_icall_by_info (MonoCompile *cfg, MonoJitICallInfo *info, MonoInst **args)
3032 {
3033         /*
3034          * Call the jit icall without a wrapper if possible.
3035          * The wrapper is needed for the following reasons:
3036          * - to handle exceptions thrown using mono_raise_exceptions () from the
3037          *   icall function. The EH code needs the lmf frame pushed by the
3038          *   wrapper to be able to unwind back to managed code.
3039          * - to be able to do stack walks for asynchronously suspended
3040          *   threads when debugging.
3041          */
3042         if (info->no_raise && direct_icalls_enabled (cfg)) {
3043                 char *name;
3044                 int costs;
3045
3046                 if (!info->wrapper_method) {
3047                         name = g_strdup_printf ("__icall_wrapper_%s", info->name);
3048                         info->wrapper_method = mono_marshal_get_icall_wrapper (info->sig, name, info->func, TRUE);
3049                         g_free (name);
3050                         mono_memory_barrier ();
3051                 }
3052
3053                 /*
3054                  * Inline the wrapper method, which is basically a call to the C icall, and
3055                  * an exception check.
3056                  */
3057                 costs = inline_method (cfg, info->wrapper_method, NULL,
3058                                                            args, NULL, cfg->real_offset, TRUE);
3059                 g_assert (costs > 0);
3060                 g_assert (!MONO_TYPE_IS_VOID (info->sig->ret));
3061
3062                 return args [0];
3063         } else {
3064                 return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
3065         }
3066 }
3067  
3068 static MonoInst*
3069 mono_emit_widen_call_res (MonoCompile *cfg, MonoInst *ins, MonoMethodSignature *fsig)
3070 {
3071         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
3072                 if ((fsig->pinvoke || LLVM_ENABLED) && !fsig->ret->byref) {
3073                         int widen_op = -1;
3074
3075                         /* 
3076                          * Native code might return non register sized integers 
3077                          * without initializing the upper bits.
3078                          */
3079                         switch (mono_type_to_load_membase (cfg, fsig->ret)) {
3080                         case OP_LOADI1_MEMBASE:
3081                                 widen_op = OP_ICONV_TO_I1;
3082                                 break;
3083                         case OP_LOADU1_MEMBASE:
3084                                 widen_op = OP_ICONV_TO_U1;
3085                                 break;
3086                         case OP_LOADI2_MEMBASE:
3087                                 widen_op = OP_ICONV_TO_I2;
3088                                 break;
3089                         case OP_LOADU2_MEMBASE:
3090                                 widen_op = OP_ICONV_TO_U2;
3091                                 break;
3092                         default:
3093                                 break;
3094                         }
3095
3096                         if (widen_op != -1) {
3097                                 int dreg = alloc_preg (cfg);
3098                                 MonoInst *widen;
3099
3100                                 EMIT_NEW_UNALU (cfg, widen, widen_op, dreg, ins->dreg);
3101                                 widen->type = ins->type;
3102                                 ins = widen;
3103                         }
3104                 }
3105         }
3106
3107         return ins;
3108 }
3109
3110 static MonoMethod*
3111 get_memcpy_method (void)
3112 {
3113         static MonoMethod *memcpy_method = NULL;
3114         if (!memcpy_method) {
3115                 memcpy_method = mono_class_get_method_from_name (mono_defaults.string_class, "memcpy", 3);
3116                 if (!memcpy_method)
3117                         g_error ("Old corlib found. Install a new one");
3118         }
3119         return memcpy_method;
3120 }
3121
3122 static void
3123 create_write_barrier_bitmap (MonoCompile *cfg, MonoClass *klass, unsigned *wb_bitmap, int offset)
3124 {
3125         MonoClassField *field;
3126         gpointer iter = NULL;
3127
3128         while ((field = mono_class_get_fields (klass, &iter))) {
3129                 int foffset;
3130
3131                 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
3132                         continue;
3133                 foffset = klass->valuetype ? field->offset - sizeof (MonoObject): field->offset;
3134                 if (mini_type_is_reference (mono_field_get_type (field))) {
3135                         g_assert ((foffset % SIZEOF_VOID_P) == 0);
3136                         *wb_bitmap |= 1 << ((offset + foffset) / SIZEOF_VOID_P);
3137                 } else {
3138                         MonoClass *field_class = mono_class_from_mono_type (field->type);
3139                         if (field_class->has_references)
3140                                 create_write_barrier_bitmap (cfg, field_class, wb_bitmap, offset + foffset);
3141                 }
3142         }
3143 }
3144
3145 static void
3146 emit_write_barrier (MonoCompile *cfg, MonoInst *ptr, MonoInst *value)
3147 {
3148         int card_table_shift_bits;
3149         gpointer card_table_mask;
3150         guint8 *card_table;
3151         MonoInst *dummy_use;
3152         int nursery_shift_bits;
3153         size_t nursery_size;
3154         gboolean has_card_table_wb = FALSE;
3155
3156         if (!cfg->gen_write_barriers)
3157                 return;
3158
3159         card_table = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
3160
3161         mono_gc_get_nursery (&nursery_shift_bits, &nursery_size);
3162
3163 #ifdef MONO_ARCH_HAVE_CARD_TABLE_WBARRIER
3164         has_card_table_wb = TRUE;
3165 #endif
3166
3167         if (has_card_table_wb && !cfg->compile_aot && card_table && nursery_shift_bits > 0 && !COMPILE_LLVM (cfg)) {
3168                 MonoInst *wbarrier;
3169
3170                 MONO_INST_NEW (cfg, wbarrier, OP_CARD_TABLE_WBARRIER);
3171                 wbarrier->sreg1 = ptr->dreg;
3172                 wbarrier->sreg2 = value->dreg;
3173                 MONO_ADD_INS (cfg->cbb, wbarrier);
3174         } else if (card_table && !cfg->compile_aot && !mono_gc_card_table_nursery_check ()) {
3175                 int offset_reg = alloc_preg (cfg);
3176                 int card_reg  = alloc_preg (cfg);
3177                 MonoInst *ins;
3178
3179                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, offset_reg, ptr->dreg, card_table_shift_bits);
3180                 if (card_table_mask)
3181                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, offset_reg, offset_reg, card_table_mask);
3182
3183                 /*We can't use PADD_IMM since the cardtable might end up in high addresses and amd64 doesn't support
3184                  * IMM's larger than 32bits.
3185                  */
3186                 if (cfg->compile_aot) {
3187                         MONO_EMIT_NEW_AOTCONST (cfg, card_reg, NULL, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR);
3188                 } else {
3189                         MONO_INST_NEW (cfg, ins, OP_PCONST);
3190                         ins->inst_p0 = card_table;
3191                         ins->dreg = card_reg;
3192                         MONO_ADD_INS (cfg->cbb, ins);
3193                 }
3194
3195                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, offset_reg, offset_reg, card_reg);
3196                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, offset_reg, 0, 1);
3197         } else {
3198                 MonoMethod *write_barrier = mono_gc_get_write_barrier ();
3199                 mono_emit_method_call (cfg, write_barrier, &ptr, NULL);
3200         }
3201
3202         EMIT_NEW_DUMMY_USE (cfg, dummy_use, value);
3203 }
3204
3205 static gboolean
3206 mono_emit_wb_aware_memcpy (MonoCompile *cfg, MonoClass *klass, MonoInst *iargs[4], int size, int align)
3207 {
3208         int dest_ptr_reg, tmp_reg, destreg, srcreg, offset;
3209         unsigned need_wb = 0;
3210
3211         if (align == 0)
3212                 align = 4;
3213
3214         /*types with references can't have alignment smaller than sizeof(void*) */
3215         if (align < SIZEOF_VOID_P)
3216                 return FALSE;
3217
3218         /*This value cannot be bigger than 32 due to the way we calculate the required wb bitmap.*/
3219         if (size > 32 * SIZEOF_VOID_P)
3220                 return FALSE;
3221
3222         create_write_barrier_bitmap (cfg, klass, &need_wb, 0);
3223
3224         /* We don't unroll more than 5 stores to avoid code bloat. */
3225         if (size > 5 * SIZEOF_VOID_P) {
3226                 /*This is harmless and simplify mono_gc_wbarrier_value_copy_bitmap */
3227                 size += (SIZEOF_VOID_P - 1);
3228                 size &= ~(SIZEOF_VOID_P - 1);
3229
3230                 EMIT_NEW_ICONST (cfg, iargs [2], size);
3231                 EMIT_NEW_ICONST (cfg, iargs [3], need_wb);
3232                 mono_emit_jit_icall (cfg, mono_gc_wbarrier_value_copy_bitmap, iargs);
3233                 return TRUE;
3234         }
3235
3236         destreg = iargs [0]->dreg;
3237         srcreg = iargs [1]->dreg;
3238         offset = 0;
3239
3240         dest_ptr_reg = alloc_preg (cfg);
3241         tmp_reg = alloc_preg (cfg);
3242
3243         /*tmp = dreg*/
3244         EMIT_NEW_UNALU (cfg, iargs [0], OP_MOVE, dest_ptr_reg, destreg);
3245
3246         while (size >= SIZEOF_VOID_P) {
3247                 MonoInst *load_inst;
3248                 MONO_INST_NEW (cfg, load_inst, OP_LOAD_MEMBASE);
3249                 load_inst->dreg = tmp_reg;
3250                 load_inst->inst_basereg = srcreg;
3251                 load_inst->inst_offset = offset;
3252                 MONO_ADD_INS (cfg->cbb, load_inst);
3253
3254                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, dest_ptr_reg, 0, tmp_reg);
3255
3256                 if (need_wb & 0x1)
3257                         emit_write_barrier (cfg, iargs [0], load_inst);
3258
3259                 offset += SIZEOF_VOID_P;
3260                 size -= SIZEOF_VOID_P;
3261                 need_wb >>= 1;
3262
3263                 /*tmp += sizeof (void*)*/
3264                 if (size >= SIZEOF_VOID_P) {
3265                         NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, dest_ptr_reg, dest_ptr_reg, SIZEOF_VOID_P);
3266                         MONO_ADD_INS (cfg->cbb, iargs [0]);
3267                 }
3268         }
3269
3270         /* Those cannot be references since size < sizeof (void*) */
3271         while (size >= 4) {
3272                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tmp_reg, srcreg, offset);
3273                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, tmp_reg);
3274                 offset += 4;
3275                 size -= 4;
3276         }
3277
3278         while (size >= 2) {
3279                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmp_reg, srcreg, offset);
3280                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, tmp_reg);
3281                 offset += 2;
3282                 size -= 2;
3283         }
3284
3285         while (size >= 1) {
3286                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmp_reg, srcreg, offset);
3287                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, tmp_reg);
3288                 offset += 1;
3289                 size -= 1;
3290         }
3291
3292         return TRUE;
3293 }
3294
3295 /*
3296  * Emit code to copy a valuetype of type @klass whose address is stored in
3297  * @src->dreg to memory whose address is stored at @dest->dreg.
3298  */
3299 void
3300 mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native)
3301 {
3302         MonoInst *iargs [4];
3303         int n;
3304         guint32 align = 0;
3305         MonoMethod *memcpy_method;
3306         MonoInst *size_ins = NULL;
3307         MonoInst *memcpy_ins = NULL;
3308
3309         g_assert (klass);
3310         if (cfg->gshared)
3311                 klass = mono_class_from_mono_type (mini_get_underlying_type (&klass->byval_arg));
3312
3313         /*
3314          * This check breaks with spilled vars... need to handle it during verification anyway.
3315          * g_assert (klass && klass == src->klass && klass == dest->klass);
3316          */
3317
3318         if (mini_is_gsharedvt_klass (klass)) {
3319                 g_assert (!native);
3320                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3321                 memcpy_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_MEMCPY);
3322         }
3323
3324         if (native)
3325                 n = mono_class_native_size (klass, &align);
3326         else
3327                 n = mono_class_value_size (klass, &align);
3328
3329         /* if native is true there should be no references in the struct */
3330         if (cfg->gen_write_barriers && (klass->has_references || size_ins) && !native) {
3331                 /* Avoid barriers when storing to the stack */
3332                 if (!((dest->opcode == OP_ADD_IMM && dest->sreg1 == cfg->frame_reg) ||
3333                           (dest->opcode == OP_LDADDR))) {
3334                         int context_used;
3335
3336                         iargs [0] = dest;
3337                         iargs [1] = src;
3338
3339                         context_used = mini_class_check_context_used (cfg, klass);
3340
3341                         /* It's ok to intrinsify under gsharing since shared code types are layout stable. */
3342                         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && mono_emit_wb_aware_memcpy (cfg, klass, iargs, n, align)) {
3343                                 return;
3344                         } else if (context_used) {
3345                                 iargs [2] = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3346                         }  else {
3347                                 if (cfg->compile_aot) {
3348                                         EMIT_NEW_CLASSCONST (cfg, iargs [2], klass);
3349                                 } else {
3350                                         EMIT_NEW_PCONST (cfg, iargs [2], klass);
3351                                         mono_class_compute_gc_descriptor (klass);
3352                                 }
3353                         }
3354
3355                         if (size_ins)
3356                                 mono_emit_jit_icall (cfg, mono_gsharedvt_value_copy, iargs);
3357                         else
3358                                 mono_emit_jit_icall (cfg, mono_value_copy, iargs);
3359                         return;
3360                 }
3361         }
3362
3363         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 8) {
3364                 /* FIXME: Optimize the case when src/dest is OP_LDADDR */
3365                 mini_emit_memcpy (cfg, dest->dreg, 0, src->dreg, 0, n, align);
3366         } else {
3367                 iargs [0] = dest;
3368                 iargs [1] = src;
3369                 if (size_ins)
3370                         iargs [2] = size_ins;
3371                 else
3372                         EMIT_NEW_ICONST (cfg, iargs [2], n);
3373                 
3374                 memcpy_method = get_memcpy_method ();
3375                 if (memcpy_ins)
3376                         mono_emit_calli (cfg, mono_method_signature (memcpy_method), iargs, memcpy_ins, NULL, NULL);
3377                 else
3378                         mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
3379         }
3380 }
3381
3382 static MonoMethod*
3383 get_memset_method (void)
3384 {
3385         static MonoMethod *memset_method = NULL;
3386         if (!memset_method) {
3387                 memset_method = mono_class_get_method_from_name (mono_defaults.string_class, "memset", 3);
3388                 if (!memset_method)
3389                         g_error ("Old corlib found. Install a new one");
3390         }
3391         return memset_method;
3392 }
3393
3394 void
3395 mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass)
3396 {
3397         MonoInst *iargs [3];
3398         int n;
3399         guint32 align;
3400         MonoMethod *memset_method;
3401         MonoInst *size_ins = NULL;
3402         MonoInst *bzero_ins = NULL;
3403         static MonoMethod *bzero_method;
3404
3405         /* FIXME: Optimize this for the case when dest is an LDADDR */
3406         mono_class_init (klass);
3407         if (mini_is_gsharedvt_klass (klass)) {
3408                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3409                 bzero_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_BZERO);
3410                 if (!bzero_method)
3411                         bzero_method = mono_class_get_method_from_name (mono_defaults.string_class, "bzero_aligned_1", 2);
3412                 g_assert (bzero_method);
3413                 iargs [0] = dest;
3414                 iargs [1] = size_ins;
3415                 mono_emit_calli (cfg, mono_method_signature (bzero_method), iargs, bzero_ins, NULL, NULL);
3416                 return;
3417         }
3418
3419         n = mono_class_value_size (klass, &align);
3420
3421         if (n <= sizeof (gpointer) * 8) {
3422                 mini_emit_memset (cfg, dest->dreg, 0, n, 0, align);
3423         }
3424         else {
3425                 memset_method = get_memset_method ();
3426                 iargs [0] = dest;
3427                 EMIT_NEW_ICONST (cfg, iargs [1], 0);
3428                 EMIT_NEW_ICONST (cfg, iargs [2], n);
3429                 mono_emit_method_call (cfg, memset_method, iargs, NULL);
3430         }
3431 }
3432
3433 /*
3434  * emit_get_rgctx:
3435  *
3436  *   Emit IR to return either the this pointer for instance method,
3437  * or the mrgctx for static methods.
3438  */
3439 static MonoInst*
3440 emit_get_rgctx (MonoCompile *cfg, MonoMethod *method, int context_used)
3441 {
3442         MonoInst *this_ins = NULL;
3443
3444         g_assert (cfg->gshared);
3445
3446         if (!(method->flags & METHOD_ATTRIBUTE_STATIC) &&
3447                         !(context_used & MONO_GENERIC_CONTEXT_USED_METHOD) &&
3448                         !method->klass->valuetype)
3449                 EMIT_NEW_ARGLOAD (cfg, this_ins, 0);
3450
3451         if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD) {
3452                 MonoInst *mrgctx_loc, *mrgctx_var;
3453
3454                 g_assert (!this_ins);
3455                 g_assert (method->is_inflated && mono_method_get_context (method)->method_inst);
3456
3457                 mrgctx_loc = mono_get_vtable_var (cfg);
3458                 EMIT_NEW_TEMPLOAD (cfg, mrgctx_var, mrgctx_loc->inst_c0);
3459
3460                 return mrgctx_var;
3461         } else if (method->flags & METHOD_ATTRIBUTE_STATIC || method->klass->valuetype) {
3462                 MonoInst *vtable_loc, *vtable_var;
3463
3464                 g_assert (!this_ins);
3465
3466                 vtable_loc = mono_get_vtable_var (cfg);
3467                 EMIT_NEW_TEMPLOAD (cfg, vtable_var, vtable_loc->inst_c0);
3468
3469                 if (method->is_inflated && mono_method_get_context (method)->method_inst) {
3470                         MonoInst *mrgctx_var = vtable_var;
3471                         int vtable_reg;
3472
3473                         vtable_reg = alloc_preg (cfg);
3474                         EMIT_NEW_LOAD_MEMBASE (cfg, vtable_var, OP_LOAD_MEMBASE, vtable_reg, mrgctx_var->dreg, MONO_STRUCT_OFFSET (MonoMethodRuntimeGenericContext, class_vtable));
3475                         vtable_var->type = STACK_PTR;
3476                 }
3477
3478                 return vtable_var;
3479         } else {
3480                 MonoInst *ins;
3481                 int vtable_reg;
3482         
3483                 vtable_reg = alloc_preg (cfg);
3484                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, vtable_reg, this_ins->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3485                 return ins;
3486         }
3487 }
3488
3489 static MonoJumpInfoRgctxEntry *
3490 mono_patch_info_rgctx_entry_new (MonoMemPool *mp, MonoMethod *method, gboolean in_mrgctx, MonoJumpInfoType patch_type, gconstpointer patch_data, MonoRgctxInfoType info_type)
3491 {
3492         MonoJumpInfoRgctxEntry *res = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoRgctxEntry));
3493         res->method = method;
3494         res->in_mrgctx = in_mrgctx;
3495         res->data = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo));
3496         res->data->type = patch_type;
3497         res->data->data.target = patch_data;
3498         res->info_type = info_type;
3499
3500         return res;
3501 }
3502
3503 static inline MonoInst*
3504 emit_rgctx_fetch_inline (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
3505 {
3506         MonoInst *args [16];
3507         MonoInst *call;
3508
3509         // FIXME: No fastpath since the slot is not a compile time constant
3510         args [0] = rgctx;
3511         EMIT_NEW_AOTCONST (cfg, args [1], MONO_PATCH_INFO_RGCTX_SLOT_INDEX, entry);
3512         if (entry->in_mrgctx)
3513                 call = mono_emit_jit_icall (cfg, mono_fill_method_rgctx, args);
3514         else
3515                 call = mono_emit_jit_icall (cfg, mono_fill_class_rgctx, args);
3516         return call;
3517 #if 0
3518         /*
3519          * FIXME: This can be called during decompose, which is a problem since it creates
3520          * new bblocks.
3521          * Also, the fastpath doesn't work since the slot number is dynamically allocated.
3522          */
3523         int i, slot, depth, index, rgctx_reg, val_reg, res_reg;
3524         gboolean mrgctx;
3525         MonoBasicBlock *is_null_bb, *end_bb;
3526         MonoInst *res, *ins, *call;
3527         MonoInst *args[16];
3528
3529         slot = mini_get_rgctx_entry_slot (entry);
3530
3531         mrgctx = MONO_RGCTX_SLOT_IS_MRGCTX (slot);
3532         index = MONO_RGCTX_SLOT_INDEX (slot);
3533         if (mrgctx)
3534                 index += MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
3535         for (depth = 0; ; ++depth) {
3536                 int size = mono_class_rgctx_get_array_size (depth, mrgctx);
3537
3538                 if (index < size - 1)
3539                         break;
3540                 index -= size - 1;
3541         }
3542
3543         NEW_BBLOCK (cfg, end_bb);
3544         NEW_BBLOCK (cfg, is_null_bb);
3545
3546         if (mrgctx) {
3547                 rgctx_reg = rgctx->dreg;
3548         } else {
3549                 rgctx_reg = alloc_preg (cfg);
3550
3551                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, rgctx_reg, rgctx->dreg, MONO_STRUCT_OFFSET (MonoVTable, runtime_generic_context));
3552                 // FIXME: Avoid this check by allocating the table when the vtable is created etc.
3553                 NEW_BBLOCK (cfg, is_null_bb);
3554
3555                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rgctx_reg, 0);
3556                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3557         }
3558
3559         for (i = 0; i < depth; ++i) {
3560                 int array_reg = alloc_preg (cfg);
3561
3562                 /* load ptr to next array */
3563                 if (mrgctx && i == 0)
3564                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, rgctx_reg, MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT);
3565                 else
3566                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, rgctx_reg, 0);
3567                 rgctx_reg = array_reg;
3568                 /* is the ptr null? */
3569                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rgctx_reg, 0);
3570                 /* if yes, jump to actual trampoline */
3571                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3572         }
3573
3574         /* fetch slot */
3575         val_reg = alloc_preg (cfg);
3576         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, val_reg, rgctx_reg, (index + 1) * sizeof (gpointer));
3577         /* is the slot null? */
3578         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, val_reg, 0);
3579         /* if yes, jump to actual trampoline */
3580         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3581
3582         /* Fastpath */
3583         res_reg = alloc_preg (cfg);
3584         MONO_INST_NEW (cfg, ins, OP_MOVE);
3585         ins->dreg = res_reg;
3586         ins->sreg1 = val_reg;
3587         MONO_ADD_INS (cfg->cbb, ins);
3588         res = ins;
3589         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3590
3591         /* Slowpath */
3592         MONO_START_BB (cfg, is_null_bb);
3593         args [0] = rgctx;
3594         EMIT_NEW_ICONST (cfg, args [1], index);
3595         if (mrgctx)
3596                 call = mono_emit_jit_icall (cfg, mono_fill_method_rgctx, args);
3597         else
3598                 call = mono_emit_jit_icall (cfg, mono_fill_class_rgctx, args);
3599         MONO_INST_NEW (cfg, ins, OP_MOVE);
3600         ins->dreg = res_reg;
3601         ins->sreg1 = call->dreg;
3602         MONO_ADD_INS (cfg->cbb, ins);
3603         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3604
3605         MONO_START_BB (cfg, end_bb);
3606
3607         return res;
3608 #endif
3609 }
3610
3611 /*
3612  * emit_rgctx_fetch:
3613  *
3614  *   Emit IR to load the value of the rgctx entry ENTRY from the rgctx
3615  * given by RGCTX.
3616  */
3617 static inline MonoInst*
3618 emit_rgctx_fetch (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
3619 {
3620         if (cfg->llvm_only)
3621                 return emit_rgctx_fetch_inline (cfg, rgctx, entry);
3622         else
3623                 return mono_emit_abs_call (cfg, MONO_PATCH_INFO_RGCTX_FETCH, entry, helper_sig_rgctx_lazy_fetch_trampoline, &rgctx);
3624 }
3625
3626 static MonoInst*
3627 emit_get_rgctx_klass (MonoCompile *cfg, int context_used,
3628                                           MonoClass *klass, MonoRgctxInfoType rgctx_type)
3629 {
3630         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);
3631         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3632
3633         return emit_rgctx_fetch (cfg, rgctx, entry);
3634 }
3635
3636 static MonoInst*
3637 emit_get_rgctx_sig (MonoCompile *cfg, int context_used,
3638                                         MonoMethodSignature *sig, MonoRgctxInfoType rgctx_type)
3639 {
3640         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);
3641         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3642
3643         return emit_rgctx_fetch (cfg, rgctx, entry);
3644 }
3645
3646 static MonoInst*
3647 emit_get_rgctx_gsharedvt_call (MonoCompile *cfg, int context_used,
3648                                                            MonoMethodSignature *sig, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3649 {
3650         MonoJumpInfoGSharedVtCall *call_info;
3651         MonoJumpInfoRgctxEntry *entry;
3652         MonoInst *rgctx;
3653
3654         call_info = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoGSharedVtCall));
3655         call_info->sig = sig;
3656         call_info->method = cmethod;
3657
3658         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);
3659         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3660
3661         return emit_rgctx_fetch (cfg, rgctx, entry);
3662 }
3663
3664 /*
3665  * emit_get_rgctx_virt_method:
3666  *
3667  *   Return data for method VIRT_METHOD for a receiver of type KLASS.
3668  */
3669 static MonoInst*
3670 emit_get_rgctx_virt_method (MonoCompile *cfg, int context_used,
3671                                                         MonoClass *klass, MonoMethod *virt_method, MonoRgctxInfoType rgctx_type)
3672 {
3673         MonoJumpInfoVirtMethod *info;
3674         MonoJumpInfoRgctxEntry *entry;
3675         MonoInst *rgctx;
3676
3677         info = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoVirtMethod));
3678         info->klass = klass;
3679         info->method = virt_method;
3680
3681         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);
3682         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3683
3684         return emit_rgctx_fetch (cfg, rgctx, entry);
3685 }
3686
3687 static MonoInst*
3688 emit_get_rgctx_gsharedvt_method (MonoCompile *cfg, int context_used,
3689                                                                  MonoMethod *cmethod, MonoGSharedVtMethodInfo *info)
3690 {
3691         MonoJumpInfoRgctxEntry *entry;
3692         MonoInst *rgctx;
3693
3694         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);
3695         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3696
3697         return emit_rgctx_fetch (cfg, rgctx, entry);
3698 }
3699
3700 /*
3701  * emit_get_rgctx_method:
3702  *
3703  *   Emit IR to load the property RGCTX_TYPE of CMETHOD. If context_used is 0, emit
3704  * normal constants, else emit a load from the rgctx.
3705  */
3706 static MonoInst*
3707 emit_get_rgctx_method (MonoCompile *cfg, int context_used,
3708                                            MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3709 {
3710         if (!context_used) {
3711                 MonoInst *ins;
3712
3713                 switch (rgctx_type) {
3714                 case MONO_RGCTX_INFO_METHOD:
3715                         EMIT_NEW_METHODCONST (cfg, ins, cmethod);
3716                         return ins;
3717                 case MONO_RGCTX_INFO_METHOD_RGCTX:
3718                         EMIT_NEW_METHOD_RGCTX_CONST (cfg, ins, cmethod);
3719                         return ins;
3720                 default:
3721                         g_assert_not_reached ();
3722                 }
3723         } else {
3724                 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);
3725                 MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3726
3727                 return emit_rgctx_fetch (cfg, rgctx, entry);
3728         }
3729 }
3730
3731 static MonoInst*
3732 emit_get_rgctx_field (MonoCompile *cfg, int context_used,
3733                                           MonoClassField *field, MonoRgctxInfoType rgctx_type)
3734 {
3735         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);
3736         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3737
3738         return emit_rgctx_fetch (cfg, rgctx, entry);
3739 }
3740
3741 static int
3742 get_gsharedvt_info_slot (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3743 {
3744         MonoGSharedVtMethodInfo *info = cfg->gsharedvt_info;
3745         MonoRuntimeGenericContextInfoTemplate *template;
3746         int i, idx;
3747
3748         g_assert (info);
3749
3750         for (i = 0; i < info->num_entries; ++i) {
3751                 MonoRuntimeGenericContextInfoTemplate *otemplate = &info->entries [i];
3752
3753                 if (otemplate->info_type == rgctx_type && otemplate->data == data && rgctx_type != MONO_RGCTX_INFO_LOCAL_OFFSET)
3754                         return i;
3755         }
3756
3757         if (info->num_entries == info->count_entries) {
3758                 MonoRuntimeGenericContextInfoTemplate *new_entries;
3759                 int new_count_entries = info->count_entries ? info->count_entries * 2 : 16;
3760
3761                 new_entries = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * new_count_entries);
3762
3763                 memcpy (new_entries, info->entries, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
3764                 info->entries = new_entries;
3765                 info->count_entries = new_count_entries;
3766         }
3767
3768         idx = info->num_entries;
3769         template = &info->entries [idx];
3770         template->info_type = rgctx_type;
3771         template->data = data;
3772
3773         info->num_entries ++;
3774
3775         return idx;
3776 }
3777
3778 /*
3779  * emit_get_gsharedvt_info:
3780  *
3781  *   This is similar to emit_get_rgctx_.., but loads the data from the gsharedvt info var instead of calling an rgctx fetch trampoline.
3782  */
3783 static MonoInst*
3784 emit_get_gsharedvt_info (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3785 {
3786         MonoInst *ins;
3787         int idx, dreg;
3788
3789         idx = get_gsharedvt_info_slot (cfg, data, rgctx_type);
3790         /* Load info->entries [idx] */
3791         dreg = alloc_preg (cfg);
3792         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, cfg->gsharedvt_info_var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
3793
3794         return ins;
3795 }
3796
3797 static MonoInst*
3798 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type)
3799 {
3800         return emit_get_gsharedvt_info (cfg, &klass->byval_arg, rgctx_type);
3801 }
3802
3803 /*
3804  * On return the caller must check @klass for load errors.
3805  */
3806 static void
3807 emit_class_init (MonoCompile *cfg, MonoClass *klass)
3808 {
3809         MonoInst *vtable_arg;
3810         int context_used;
3811         gboolean use_op_generic_class_init = FALSE;
3812
3813         context_used = mini_class_check_context_used (cfg, klass);
3814
3815         if (context_used) {
3816                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
3817                                                                                    klass, MONO_RGCTX_INFO_VTABLE);
3818         } else {
3819                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
3820
3821                 if (!vtable)
3822                         return;
3823                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
3824         }
3825
3826 #ifdef MONO_ARCH_HAVE_OP_GENERIC_CLASS_INIT
3827         if (!COMPILE_LLVM (cfg))
3828                 use_op_generic_class_init = TRUE;
3829 #endif
3830
3831         if (use_op_generic_class_init) {
3832                 MonoInst *ins;
3833
3834                 /*
3835                  * Using an opcode instead of emitting IR here allows the hiding of the call inside the opcode,
3836                  * so this doesn't have to clobber any regs and it doesn't break basic blocks.
3837                  */
3838                 MONO_INST_NEW (cfg, ins, OP_GENERIC_CLASS_INIT);
3839                 ins->sreg1 = vtable_arg->dreg;
3840                 MONO_ADD_INS (cfg->cbb, ins);
3841         } else {
3842                 static int byte_offset = -1;
3843                 static guint8 bitmask;
3844                 int bits_reg, inited_reg;
3845                 MonoBasicBlock *inited_bb;
3846                 MonoInst *args [16];
3847
3848                 if (byte_offset < 0)
3849                         mono_marshal_find_bitfield_offset (MonoVTable, initialized, &byte_offset, &bitmask);
3850
3851                 bits_reg = alloc_ireg (cfg);
3852                 inited_reg = alloc_ireg (cfg);
3853
3854                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, bits_reg, vtable_arg->dreg, byte_offset);
3855                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, inited_reg, bits_reg, bitmask);
3856
3857                 NEW_BBLOCK (cfg, inited_bb);
3858
3859                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, inited_reg, 0);
3860                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, inited_bb);
3861
3862                 args [0] = vtable_arg;
3863                 mono_emit_jit_icall (cfg, mono_generic_class_init, args);
3864
3865                 MONO_START_BB (cfg, inited_bb);
3866         }
3867 }
3868
3869 static void
3870 emit_seq_point (MonoCompile *cfg, MonoMethod *method, guint8* ip, gboolean intr_loc, gboolean nonempty_stack)
3871 {
3872         MonoInst *ins;
3873
3874         if (cfg->gen_seq_points && cfg->method == method) {
3875                 NEW_SEQ_POINT (cfg, ins, ip - cfg->header->code, intr_loc);
3876                 if (nonempty_stack)
3877                         ins->flags |= MONO_INST_NONEMPTY_STACK;
3878                 MONO_ADD_INS (cfg->cbb, ins);
3879         }
3880 }
3881
3882 static void
3883 save_cast_details (MonoCompile *cfg, MonoClass *klass, int obj_reg, gboolean null_check)
3884 {
3885         if (mini_get_debug_options ()->better_cast_details) {
3886                 int vtable_reg = alloc_preg (cfg);
3887                 int klass_reg = alloc_preg (cfg);
3888                 MonoBasicBlock *is_null_bb = NULL;
3889                 MonoInst *tls_get;
3890                 int to_klass_reg, context_used;
3891
3892                 if (null_check) {
3893                         NEW_BBLOCK (cfg, is_null_bb);
3894
3895                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
3896                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3897                 }
3898
3899                 tls_get = mono_get_jit_tls_intrinsic (cfg);
3900                 if (!tls_get) {
3901                         fprintf (stderr, "error: --debug=casts not supported on this platform.\n.");
3902                         exit (1);
3903                 }
3904
3905                 MONO_ADD_INS (cfg->cbb, tls_get);
3906                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3907                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3908
3909                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), klass_reg);
3910
3911                 context_used = mini_class_check_context_used (cfg, klass);
3912                 if (context_used) {
3913                         MonoInst *class_ins;
3914
3915                         class_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3916                         to_klass_reg = class_ins->dreg;
3917                 } else {
3918                         to_klass_reg = alloc_preg (cfg);
3919                         MONO_EMIT_NEW_CLASSCONST (cfg, to_klass_reg, klass);
3920                 }
3921                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_to), to_klass_reg);
3922
3923                 if (null_check)
3924                         MONO_START_BB (cfg, is_null_bb);
3925         }
3926 }
3927
3928 static void
3929 reset_cast_details (MonoCompile *cfg)
3930 {
3931         /* Reset the variables holding the cast details */
3932         if (mini_get_debug_options ()->better_cast_details) {
3933                 MonoInst *tls_get = mono_get_jit_tls_intrinsic (cfg);
3934
3935                 MONO_ADD_INS (cfg->cbb, tls_get);
3936                 /* It is enough to reset the from field */
3937                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), 0);
3938         }
3939 }
3940
3941 /*
3942  * On return the caller must check @array_class for load errors
3943  */
3944 static void
3945 mini_emit_check_array_type (MonoCompile *cfg, MonoInst *obj, MonoClass *array_class)
3946 {
3947         int vtable_reg = alloc_preg (cfg);
3948         int context_used;
3949
3950         context_used = mini_class_check_context_used (cfg, array_class);
3951
3952         save_cast_details (cfg, array_class, obj->dreg, FALSE);
3953
3954         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3955
3956         if (cfg->opt & MONO_OPT_SHARED) {
3957                 int class_reg = alloc_preg (cfg);
3958                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, class_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3959                 if (cfg->compile_aot) {
3960                         int klass_reg = alloc_preg (cfg);
3961                         MONO_EMIT_NEW_CLASSCONST (cfg, klass_reg, array_class);
3962                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, class_reg, klass_reg);
3963                 } else {
3964                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, class_reg, array_class);
3965                 }
3966         } else if (context_used) {
3967                 MonoInst *vtable_ins;
3968
3969                 vtable_ins = emit_get_rgctx_klass (cfg, context_used, array_class, MONO_RGCTX_INFO_VTABLE);
3970                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vtable_ins->dreg);
3971         } else {
3972                 if (cfg->compile_aot) {
3973                         int vt_reg;
3974                         MonoVTable *vtable;
3975
3976                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3977                                 return;
3978                         vt_reg = alloc_preg (cfg);
3979                         MONO_EMIT_NEW_VTABLECONST (cfg, vt_reg, vtable);
3980                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vt_reg);
3981                 } else {
3982                         MonoVTable *vtable;
3983                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3984                                 return;
3985                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vtable);
3986                 }
3987         }
3988         
3989         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ArrayTypeMismatchException");
3990
3991         reset_cast_details (cfg);
3992 }
3993
3994 /**
3995  * Handles unbox of a Nullable<T>. If context_used is non zero, then shared 
3996  * generic code is generated.
3997  */
3998 static MonoInst*
3999 handle_unbox_nullable (MonoCompile* cfg, MonoInst* val, MonoClass* klass, int context_used)
4000 {
4001         MonoMethod* method = mono_class_get_method_from_name (klass, "Unbox", 1);
4002
4003         if (context_used) {
4004                 MonoInst *rgctx, *addr;
4005
4006                 /* FIXME: What if the class is shared?  We might not
4007                    have to get the address of the method from the
4008                    RGCTX. */
4009                 addr = emit_get_rgctx_method (cfg, context_used, method,
4010                                                                           MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
4011
4012                 rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
4013
4014                 return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
4015         } else {
4016                 gboolean pass_vtable, pass_mrgctx;
4017                 MonoInst *rgctx_arg = NULL;
4018
4019                 check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
4020                 g_assert (!pass_mrgctx);
4021
4022                 if (pass_vtable) {
4023                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
4024
4025                         g_assert (vtable);
4026                         EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
4027                 }
4028
4029                 return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
4030         }
4031 }
4032
4033 static MonoInst*
4034 handle_unbox (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, int context_used)
4035 {
4036         MonoInst *add;
4037         int obj_reg;
4038         int vtable_reg = alloc_dreg (cfg ,STACK_PTR);
4039         int klass_reg = alloc_dreg (cfg ,STACK_PTR);
4040         int eclass_reg = alloc_dreg (cfg ,STACK_PTR);
4041         int rank_reg = alloc_dreg (cfg ,STACK_I4);
4042
4043         obj_reg = sp [0]->dreg;
4044         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4045         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
4046
4047         /* FIXME: generics */
4048         g_assert (klass->rank == 0);
4049                         
4050         // Check rank == 0
4051         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, 0);
4052         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4053
4054         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4055         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, element_class));
4056
4057         if (context_used) {
4058                 MonoInst *element_class;
4059
4060                 /* This assertion is from the unboxcast insn */
4061                 g_assert (klass->rank == 0);
4062
4063                 element_class = emit_get_rgctx_klass (cfg, context_used,
4064                                 klass, MONO_RGCTX_INFO_ELEMENT_KLASS);
4065
4066                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, eclass_reg, element_class->dreg);
4067                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4068         } else {
4069                 save_cast_details (cfg, klass->element_class, obj_reg, FALSE);
4070                 mini_emit_class_check (cfg, eclass_reg, klass->element_class);
4071                 reset_cast_details (cfg);
4072         }
4073
4074         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), obj_reg, sizeof (MonoObject));
4075         MONO_ADD_INS (cfg->cbb, add);
4076         add->type = STACK_MP;
4077         add->klass = klass;
4078
4079         return add;
4080 }
4081
4082 static MonoInst*
4083 handle_unbox_gsharedvt (MonoCompile *cfg, MonoClass *klass, MonoInst *obj)
4084 {
4085         MonoInst *addr, *klass_inst, *is_ref, *args[16];
4086         MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
4087         MonoInst *ins;
4088         int dreg, addr_reg;
4089
4090         klass_inst = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_KLASS);
4091
4092         /* obj */
4093         args [0] = obj;
4094
4095         /* klass */
4096         args [1] = klass_inst;
4097
4098         /* CASTCLASS */
4099         obj = mono_emit_jit_icall (cfg, mono_object_castclass_unbox, args);
4100
4101         NEW_BBLOCK (cfg, is_ref_bb);
4102         NEW_BBLOCK (cfg, is_nullable_bb);
4103         NEW_BBLOCK (cfg, end_bb);
4104         is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
4105         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 1);
4106         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
4107
4108         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 2);
4109         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
4110
4111         /* This will contain either the address of the unboxed vtype, or an address of the temporary where the ref is stored */
4112         addr_reg = alloc_dreg (cfg, STACK_MP);
4113
4114         /* Non-ref case */
4115         /* UNBOX */
4116         NEW_BIALU_IMM (cfg, addr, OP_ADD_IMM, addr_reg, obj->dreg, sizeof (MonoObject));
4117         MONO_ADD_INS (cfg->cbb, addr);
4118
4119         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4120
4121         /* Ref case */
4122         MONO_START_BB (cfg, is_ref_bb);
4123
4124         /* Save the ref to a temporary */
4125         dreg = alloc_ireg (cfg);
4126         EMIT_NEW_VARLOADA_VREG (cfg, addr, dreg, &klass->byval_arg);
4127         addr->dreg = addr_reg;
4128         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, obj->dreg);
4129         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4130
4131         /* Nullable case */
4132         MONO_START_BB (cfg, is_nullable_bb);
4133
4134         {
4135                 MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX);
4136                 MonoInst *unbox_call;
4137                 MonoMethodSignature *unbox_sig;
4138
4139                 unbox_sig = mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
4140                 unbox_sig->ret = &klass->byval_arg;
4141                 unbox_sig->param_count = 1;
4142                 unbox_sig->params [0] = &mono_defaults.object_class->byval_arg;
4143                 unbox_call = mono_emit_calli (cfg, unbox_sig, &obj, addr, NULL, NULL);
4144
4145                 EMIT_NEW_VARLOADA_VREG (cfg, addr, unbox_call->dreg, &klass->byval_arg);
4146                 addr->dreg = addr_reg;
4147         }
4148
4149         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4150
4151         /* End */
4152         MONO_START_BB (cfg, end_bb);
4153
4154         /* LDOBJ */
4155         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr_reg, 0);
4156
4157         return ins;
4158 }
4159
4160 /*
4161  * Returns NULL and set the cfg exception on error.
4162  */
4163 static MonoInst*
4164 handle_alloc (MonoCompile *cfg, MonoClass *klass, gboolean for_box, int context_used)
4165 {
4166         MonoInst *iargs [2];
4167         void *alloc_ftn;
4168
4169         if (context_used) {
4170                 MonoInst *data;
4171                 int rgctx_info;
4172                 MonoInst *iargs [2];
4173                 gboolean known_instance_size = !mini_is_gsharedvt_klass (klass);
4174
4175                 MonoMethod *managed_alloc = mono_gc_get_managed_allocator (klass, for_box, known_instance_size);
4176
4177                 if (cfg->opt & MONO_OPT_SHARED)
4178                         rgctx_info = MONO_RGCTX_INFO_KLASS;
4179                 else
4180                         rgctx_info = MONO_RGCTX_INFO_VTABLE;
4181                 data = emit_get_rgctx_klass (cfg, context_used, klass, rgctx_info);
4182
4183                 if (cfg->opt & MONO_OPT_SHARED) {
4184                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
4185                         iargs [1] = data;
4186                         alloc_ftn = mono_object_new;
4187                 } else {
4188                         iargs [0] = data;
4189                         alloc_ftn = mono_object_new_specific;
4190                 }
4191
4192                 if (managed_alloc && !(cfg->opt & MONO_OPT_SHARED)) {
4193                         if (known_instance_size) {
4194                                 int size = mono_class_instance_size (klass);
4195                                 if (size < sizeof (MonoObject))
4196                                         g_error ("Invalid size %d for class %s", size, mono_type_get_full_name (klass));
4197
4198                                 EMIT_NEW_ICONST (cfg, iargs [1], mono_gc_get_aligned_size_for_allocator (size));
4199                         }
4200                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
4201                 }
4202
4203                 return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
4204         }
4205
4206         if (cfg->opt & MONO_OPT_SHARED) {
4207                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
4208                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
4209
4210                 alloc_ftn = mono_object_new;
4211         } else if (cfg->compile_aot && cfg->cbb->out_of_line && klass->type_token && klass->image == mono_defaults.corlib && !klass->generic_class) {
4212                 /* This happens often in argument checking code, eg. throw new FooException... */
4213                 /* Avoid relocations and save some space by calling a helper function specialized to mscorlib */
4214                 EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (klass->type_token));
4215                 return mono_emit_jit_icall (cfg, mono_helper_newobj_mscorlib, iargs);
4216         } else {
4217                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
4218                 MonoMethod *managed_alloc = NULL;
4219                 gboolean pass_lw;
4220
4221                 if (!vtable) {
4222                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4223                         cfg->exception_ptr = klass;
4224                         return NULL;
4225                 }
4226
4227                 managed_alloc = mono_gc_get_managed_allocator (klass, for_box, TRUE);
4228
4229                 if (managed_alloc) {
4230                         int size = mono_class_instance_size (klass);
4231                         if (size < sizeof (MonoObject))
4232                                 g_error ("Invalid size %d for class %s", size, mono_type_get_full_name (klass));
4233
4234                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
4235                         EMIT_NEW_ICONST (cfg, iargs [1], mono_gc_get_aligned_size_for_allocator (size));
4236                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
4237                 }
4238                 alloc_ftn = mono_class_get_allocation_ftn (vtable, for_box, &pass_lw);
4239                 if (pass_lw) {
4240                         guint32 lw = vtable->klass->instance_size;
4241                         lw = ((lw + (sizeof (gpointer) - 1)) & ~(sizeof (gpointer) - 1)) / sizeof (gpointer);
4242                         EMIT_NEW_ICONST (cfg, iargs [0], lw);
4243                         EMIT_NEW_VTABLECONST (cfg, iargs [1], vtable);
4244                 }
4245                 else {
4246                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
4247                 }
4248         }
4249
4250         return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
4251 }
4252         
4253 /*
4254  * Returns NULL and set the cfg exception on error.
4255  */     
4256 static MonoInst*
4257 handle_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_used)
4258 {
4259         MonoInst *alloc, *ins;
4260
4261         if (mono_class_is_nullable (klass)) {
4262                 MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
4263
4264                 if (context_used) {
4265                         /* FIXME: What if the class is shared?  We might not
4266                            have to get the method address from the RGCTX. */
4267                         MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
4268                                                                                                         MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
4269                         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
4270
4271                         return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
4272                 } else {
4273                         gboolean pass_vtable, pass_mrgctx;
4274                         MonoInst *rgctx_arg = NULL;
4275
4276                         check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
4277                         g_assert (!pass_mrgctx);
4278
4279                         if (pass_vtable) {
4280                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
4281
4282                                 g_assert (vtable);
4283                                 EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
4284                         }
4285
4286                         return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
4287                 }
4288         }
4289
4290         if (mini_is_gsharedvt_klass (klass)) {
4291                 MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
4292                 MonoInst *res, *is_ref, *src_var, *addr;
4293                 int dreg;
4294
4295                 dreg = alloc_ireg (cfg);
4296
4297                 NEW_BBLOCK (cfg, is_ref_bb);
4298                 NEW_BBLOCK (cfg, is_nullable_bb);
4299                 NEW_BBLOCK (cfg, end_bb);
4300                 is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
4301                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 1);
4302                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
4303
4304                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 2);
4305                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
4306
4307                 /* Non-ref case */
4308                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4309                 if (!alloc)
4310                         return NULL;
4311                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4312                 ins->opcode = OP_STOREV_MEMBASE;
4313
4314                 EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, alloc->dreg);
4315                 res->type = STACK_OBJ;
4316                 res->klass = klass;
4317                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4318                 
4319                 /* Ref case */
4320                 MONO_START_BB (cfg, is_ref_bb);
4321
4322                 /* val is a vtype, so has to load the value manually */
4323                 src_var = get_vreg_to_inst (cfg, val->dreg);
4324                 if (!src_var)
4325                         src_var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, val->dreg);
4326                 EMIT_NEW_VARLOADA (cfg, addr, src_var, src_var->inst_vtype);
4327                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, addr->dreg, 0);
4328                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4329
4330                 /* Nullable case */
4331                 MONO_START_BB (cfg, is_nullable_bb);
4332
4333                 {
4334                         MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass,
4335                                                                                                         MONO_RGCTX_INFO_NULLABLE_CLASS_BOX);
4336                         MonoInst *box_call;
4337                         MonoMethodSignature *box_sig;
4338
4339                         /*
4340                          * klass is Nullable<T>, need to call Nullable<T>.Box () using a gsharedvt signature, but we cannot
4341                          * construct that method at JIT time, so have to do things by hand.
4342                          */
4343                         box_sig = mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
4344                         box_sig->ret = &mono_defaults.object_class->byval_arg;
4345                         box_sig->param_count = 1;
4346                         box_sig->params [0] = &klass->byval_arg;
4347                         box_call = mono_emit_calli (cfg, box_sig, &val, addr, NULL, NULL);
4348                         EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, box_call->dreg);
4349                         res->type = STACK_OBJ;
4350                         res->klass = klass;
4351                 }
4352
4353                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4354
4355                 MONO_START_BB (cfg, end_bb);
4356
4357                 return res;
4358         } else {
4359                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4360                 if (!alloc)
4361                         return NULL;
4362
4363                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4364                 return alloc;
4365         }
4366 }
4367
4368 static gboolean
4369 mini_class_has_reference_variant_generic_argument (MonoCompile *cfg, MonoClass *klass, int context_used)
4370 {
4371         int i;
4372         MonoGenericContainer *container;
4373         MonoGenericInst *ginst;
4374
4375         if (klass->generic_class) {
4376                 container = klass->generic_class->container_class->generic_container;
4377                 ginst = klass->generic_class->context.class_inst;
4378         } else if (klass->generic_container && context_used) {
4379                 container = klass->generic_container;
4380                 ginst = container->context.class_inst;
4381         } else {
4382                 return FALSE;
4383         }
4384
4385         for (i = 0; i < container->type_argc; ++i) {
4386                 MonoType *type;
4387                 if (!(mono_generic_container_get_param_info (container, i)->flags & (MONO_GEN_PARAM_VARIANT|MONO_GEN_PARAM_COVARIANT)))
4388                         continue;
4389                 type = ginst->type_argv [i];
4390                 if (mini_type_is_reference (type))
4391                         return TRUE;
4392         }
4393         return FALSE;
4394 }
4395
4396 static GHashTable* direct_icall_type_hash;
4397
4398 static gboolean
4399 icall_is_direct_callable (MonoCompile *cfg, MonoMethod *cmethod)
4400 {
4401         /* LLVM on amd64 can't handle calls to non-32 bit addresses */
4402         if (!direct_icalls_enabled (cfg))
4403                 return FALSE;
4404
4405         /*
4406          * An icall is directly callable if it doesn't directly or indirectly call mono_raise_exception ().
4407          * Whitelist a few icalls for now.
4408          */
4409         if (!direct_icall_type_hash) {
4410                 GHashTable *h = g_hash_table_new (g_str_hash, g_str_equal);
4411
4412                 g_hash_table_insert (h, (char*)"Decimal", GUINT_TO_POINTER (1));
4413                 g_hash_table_insert (h, (char*)"Number", GUINT_TO_POINTER (1));
4414                 g_hash_table_insert (h, (char*)"Buffer", GUINT_TO_POINTER (1));
4415                 g_hash_table_insert (h, (char*)"Monitor", GUINT_TO_POINTER (1));
4416                 mono_memory_barrier ();
4417                 direct_icall_type_hash = h;
4418         }
4419
4420         if (cmethod->klass == mono_defaults.math_class)
4421                 return TRUE;
4422         /* No locking needed */
4423         if (cmethod->klass->image == mono_defaults.corlib && g_hash_table_lookup (direct_icall_type_hash, cmethod->klass->name))
4424                 return TRUE;
4425         return FALSE;
4426 }
4427
4428 #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)
4429
4430 static MonoInst*
4431 emit_castclass_with_cache (MonoCompile *cfg, MonoClass *klass, MonoInst **args)
4432 {
4433         MonoMethod *mono_castclass;
4434         MonoInst *res;
4435
4436         mono_castclass = mono_marshal_get_castclass_with_cache ();
4437
4438         save_cast_details (cfg, klass, args [0]->dreg, TRUE);
4439         res = mono_emit_method_call (cfg, mono_castclass, args, NULL);
4440         reset_cast_details (cfg);
4441
4442         return res;
4443 }
4444
4445 static int
4446 get_castclass_cache_idx (MonoCompile *cfg)
4447 {
4448         /* Each CASTCLASS_CACHE patch needs a unique index which identifies the call site */
4449         cfg->castclass_cache_index ++;
4450         return (cfg->method_index << 16) | cfg->castclass_cache_index;
4451 }
4452
4453 static MonoInst*
4454 emit_castclass_with_cache_nonshared (MonoCompile *cfg, MonoInst *obj, MonoClass *klass)
4455 {
4456         MonoInst *args [3];
4457         int idx;
4458
4459         /* obj */
4460         args [0] = obj;
4461
4462         /* klass */
4463         EMIT_NEW_CLASSCONST (cfg, args [1], klass);
4464
4465         /* inline cache*/
4466         if (cfg->compile_aot) {
4467                 idx = get_castclass_cache_idx (cfg);
4468                 EMIT_NEW_AOTCONST (cfg, args [2], MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
4469         } else {
4470                 EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));
4471         }
4472
4473         /*The wrapper doesn't inline well so the bloat of inlining doesn't pay off.*/
4474         return emit_castclass_with_cache (cfg, klass, args);
4475 }
4476
4477 /*
4478  * Returns NULL and set the cfg exception on error.
4479  */
4480 static MonoInst*
4481 handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, guint8 *ip, int *inline_costs)
4482 {
4483         MonoBasicBlock *is_null_bb;
4484         int obj_reg = src->dreg;
4485         int vtable_reg = alloc_preg (cfg);
4486         int context_used;
4487         MonoInst *klass_inst = NULL, *res;
4488
4489         context_used = mini_class_check_context_used (cfg, klass);
4490
4491         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
4492                 res = emit_castclass_with_cache_nonshared (cfg, src, klass);
4493                 (*inline_costs) += 2;
4494                 return res;
4495         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
4496                 MonoMethod *mono_castclass;
4497                 MonoInst *iargs [1];
4498                 int costs;
4499
4500                 mono_castclass = mono_marshal_get_castclass (klass); 
4501                 iargs [0] = src;
4502                                 
4503                 save_cast_details (cfg, klass, src->dreg, TRUE);
4504                 costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), 
4505                                                            iargs, ip, cfg->real_offset, TRUE);
4506                 reset_cast_details (cfg);
4507                 CHECK_CFG_EXCEPTION;
4508                 g_assert (costs > 0);
4509                                 
4510                 cfg->real_offset += 5;
4511
4512                 (*inline_costs) += costs;
4513
4514                 return src;
4515         }
4516
4517         if (context_used) {
4518                 MonoInst *args [3];
4519
4520                 if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
4521                         MonoInst *cache_ins;
4522
4523                         cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
4524
4525                         /* obj */
4526                         args [0] = src;
4527
4528                         /* klass - it's the second element of the cache entry*/
4529                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
4530
4531                         /* cache */
4532                         args [2] = cache_ins;
4533
4534                         return emit_castclass_with_cache (cfg, klass, args);
4535                 }
4536
4537                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
4538         }
4539
4540         NEW_BBLOCK (cfg, is_null_bb);
4541
4542         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4543         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
4544
4545         save_cast_details (cfg, klass, obj_reg, FALSE);
4546
4547         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4548                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4549                 mini_emit_iface_cast (cfg, vtable_reg, klass, NULL, NULL);
4550         } else {
4551                 int klass_reg = alloc_preg (cfg);
4552
4553                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4554
4555                 if (!klass->rank && !cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
4556                         /* the remoting code is broken, access the class for now */
4557                         if (0) { /*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4558                                 MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4559                                 if (!vt) {
4560                                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4561                                         cfg->exception_ptr = klass;
4562                                         return NULL;
4563                                 }
4564                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4565                         } else {
4566                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4567                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4568                         }
4569                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4570                 } else {
4571                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4572                         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, klass_inst, is_null_bb);
4573                 }
4574         }
4575
4576         MONO_START_BB (cfg, is_null_bb);
4577
4578         reset_cast_details (cfg);
4579
4580         return src;
4581
4582 exception_exit:
4583         return NULL;
4584 }
4585
4586 /*
4587  * Returns NULL and set the cfg exception on error.
4588  */
4589 static MonoInst*
4590 handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
4591 {
4592         MonoInst *ins;
4593         MonoBasicBlock *is_null_bb, *false_bb, *end_bb;
4594         int obj_reg = src->dreg;
4595         int vtable_reg = alloc_preg (cfg);
4596         int res_reg = alloc_ireg_ref (cfg);
4597         MonoInst *klass_inst = NULL;
4598
4599         if (context_used) {
4600                 MonoInst *args [3];
4601
4602                 if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
4603                         MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
4604                         MonoInst *cache_ins;
4605
4606                         cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
4607
4608                         /* obj */
4609                         args [0] = src;
4610
4611                         /* klass - it's the second element of the cache entry*/
4612                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
4613
4614                         /* cache */
4615                         args [2] = cache_ins;
4616
4617                         return mono_emit_method_call (cfg, mono_isinst, args, NULL);
4618                 }
4619
4620                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
4621         }
4622
4623         NEW_BBLOCK (cfg, is_null_bb);
4624         NEW_BBLOCK (cfg, false_bb);
4625         NEW_BBLOCK (cfg, end_bb);
4626
4627         /* Do the assignment at the beginning, so the other assignment can be if converted */
4628         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, res_reg, obj_reg);
4629         ins->type = STACK_OBJ;
4630         ins->klass = klass;
4631
4632         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4633         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_null_bb);
4634
4635         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4636
4637         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4638                 g_assert (!context_used);
4639                 /* the is_null_bb target simply copies the input register to the output */
4640                 mini_emit_iface_cast (cfg, vtable_reg, klass, false_bb, is_null_bb);
4641         } else {
4642                 int klass_reg = alloc_preg (cfg);
4643
4644                 if (klass->rank) {
4645                         int rank_reg = alloc_preg (cfg);
4646                         int eclass_reg = alloc_preg (cfg);
4647
4648                         g_assert (!context_used);
4649                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
4650                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
4651                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4652                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4653                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
4654                         if (klass->cast_class == mono_defaults.object_class) {
4655                                 int parent_reg = alloc_preg (cfg);
4656                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
4657                                 mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, is_null_bb);
4658                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4659                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4660                         } else if (klass->cast_class == mono_defaults.enum_class->parent) {
4661                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, is_null_bb);
4662                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);                          
4663                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4664                         } else if (klass->cast_class == mono_defaults.enum_class) {
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->flags & TYPE_ATTRIBUTE_INTERFACE) {
4668                                 mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4669                         } else {
4670                                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY)) {
4671                                         /* Check that the object is a vector too */
4672                                         int bounds_reg = alloc_preg (cfg);
4673                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
4674                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
4675                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4676                                 }
4677
4678                                 /* the is_null_bb target simply copies the input register to the output */
4679                                 mini_emit_isninst_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4680                         }
4681                 } else if (mono_class_is_nullable (klass)) {
4682                         g_assert (!context_used);
4683                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4684                         /* the is_null_bb target simply copies the input register to the output */
4685                         mini_emit_isninst_cast (cfg, klass_reg, klass->cast_class, false_bb, is_null_bb);
4686                 } else {
4687                         if (!cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
4688                                 g_assert (!context_used);
4689                                 /* the remoting code is broken, access the class for now */
4690                                 if (0) {/*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4691                                         MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4692                                         if (!vt) {
4693                                                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4694                                                 cfg->exception_ptr = klass;
4695                                                 return NULL;
4696                                         }
4697                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4698                                 } else {
4699                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4700                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4701                                 }
4702                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4703                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, is_null_bb);
4704                         } else {
4705                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4706                                 /* the is_null_bb target simply copies the input register to the output */
4707                                 mini_emit_isninst_cast_inst (cfg, klass_reg, klass, klass_inst, false_bb, is_null_bb);
4708                         }
4709                 }
4710         }
4711
4712         MONO_START_BB (cfg, false_bb);
4713
4714         MONO_EMIT_NEW_PCONST (cfg, res_reg, 0);
4715         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4716
4717         MONO_START_BB (cfg, is_null_bb);
4718
4719         MONO_START_BB (cfg, end_bb);
4720
4721         return ins;
4722 }
4723
4724 static MonoInst*
4725 handle_cisinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4726 {
4727         /* This opcode takes as input an object reference and a class, and returns:
4728         0) if the object is an instance of the class,
4729         1) if the object is not instance of the class,
4730         2) if the object is a proxy whose type cannot be determined */
4731
4732         MonoInst *ins;
4733 #ifndef DISABLE_REMOTING
4734         MonoBasicBlock *true_bb, *false_bb, *false2_bb, *end_bb, *no_proxy_bb, *interface_fail_bb;
4735 #else
4736         MonoBasicBlock *true_bb, *false_bb, *end_bb;
4737 #endif
4738         int obj_reg = src->dreg;
4739         int dreg = alloc_ireg (cfg);
4740         int tmp_reg;
4741 #ifndef DISABLE_REMOTING
4742         int klass_reg = alloc_preg (cfg);
4743 #endif
4744
4745         NEW_BBLOCK (cfg, true_bb);
4746         NEW_BBLOCK (cfg, false_bb);
4747         NEW_BBLOCK (cfg, end_bb);
4748 #ifndef DISABLE_REMOTING
4749         NEW_BBLOCK (cfg, false2_bb);
4750         NEW_BBLOCK (cfg, no_proxy_bb);
4751 #endif
4752
4753         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4754         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, false_bb);
4755
4756         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4757 #ifndef DISABLE_REMOTING
4758                 NEW_BBLOCK (cfg, interface_fail_bb);
4759 #endif
4760
4761                 tmp_reg = alloc_preg (cfg);
4762                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4763 #ifndef DISABLE_REMOTING
4764                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, true_bb);
4765                 MONO_START_BB (cfg, interface_fail_bb);
4766                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4767                 
4768                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, false_bb);
4769
4770                 tmp_reg = alloc_preg (cfg);
4771                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4772                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4773                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false2_bb);                
4774 #else
4775                 mini_emit_iface_cast (cfg, tmp_reg, klass, false_bb, true_bb);
4776 #endif
4777         } else {
4778 #ifndef DISABLE_REMOTING
4779                 tmp_reg = alloc_preg (cfg);
4780                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4781                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4782
4783                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4784                 tmp_reg = alloc_preg (cfg);
4785                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4786                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4787
4788                 tmp_reg = alloc_preg (cfg);             
4789                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4790                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4791                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4792                 
4793                 mini_emit_isninst_cast (cfg, klass_reg, klass, false2_bb, true_bb);
4794                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false2_bb);
4795
4796                 MONO_START_BB (cfg, no_proxy_bb);
4797
4798                 mini_emit_isninst_cast (cfg, klass_reg, klass, false_bb, true_bb);
4799 #else
4800                 g_error ("transparent proxy support is disabled while trying to JIT code that uses it");
4801 #endif
4802         }
4803
4804         MONO_START_BB (cfg, false_bb);
4805
4806         MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4807         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4808
4809 #ifndef DISABLE_REMOTING
4810         MONO_START_BB (cfg, false2_bb);
4811
4812         MONO_EMIT_NEW_ICONST (cfg, dreg, 2);
4813         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4814 #endif
4815
4816         MONO_START_BB (cfg, true_bb);
4817
4818         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4819
4820         MONO_START_BB (cfg, end_bb);
4821
4822         /* FIXME: */
4823         MONO_INST_NEW (cfg, ins, OP_ICONST);
4824         ins->dreg = dreg;
4825         ins->type = STACK_I4;
4826
4827         return ins;
4828 }
4829
4830 static MonoInst*
4831 handle_ccastclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4832 {
4833         /* This opcode takes as input an object reference and a class, and returns:
4834         0) if the object is an instance of the class,
4835         1) if the object is a proxy whose type cannot be determined
4836         an InvalidCastException exception is thrown otherwhise*/
4837         
4838         MonoInst *ins;
4839 #ifndef DISABLE_REMOTING
4840         MonoBasicBlock *end_bb, *ok_result_bb, *no_proxy_bb, *interface_fail_bb, *fail_1_bb;
4841 #else
4842         MonoBasicBlock *ok_result_bb;
4843 #endif
4844         int obj_reg = src->dreg;
4845         int dreg = alloc_ireg (cfg);
4846         int tmp_reg = alloc_preg (cfg);
4847
4848 #ifndef DISABLE_REMOTING
4849         int klass_reg = alloc_preg (cfg);
4850         NEW_BBLOCK (cfg, end_bb);
4851 #endif
4852
4853         NEW_BBLOCK (cfg, ok_result_bb);
4854
4855         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4856         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, ok_result_bb);
4857
4858         save_cast_details (cfg, klass, obj_reg, FALSE);
4859
4860         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4861 #ifndef DISABLE_REMOTING
4862                 NEW_BBLOCK (cfg, interface_fail_bb);
4863         
4864                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4865                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, ok_result_bb);
4866                 MONO_START_BB (cfg, interface_fail_bb);
4867                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4868
4869                 mini_emit_class_check (cfg, klass_reg, mono_defaults.transparent_proxy_class);
4870
4871                 tmp_reg = alloc_preg (cfg);             
4872                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4873                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4874                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
4875                 
4876                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4877                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4878 #else
4879                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4880                 mini_emit_iface_cast (cfg, tmp_reg, klass, NULL, NULL);
4881                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, ok_result_bb);
4882 #endif
4883         } else {
4884 #ifndef DISABLE_REMOTING
4885                 NEW_BBLOCK (cfg, no_proxy_bb);
4886
4887                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4888                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4889                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4890
4891                 tmp_reg = alloc_preg (cfg);
4892                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4893                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4894
4895                 tmp_reg = alloc_preg (cfg);
4896                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4897                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4898                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4899
4900                 NEW_BBLOCK (cfg, fail_1_bb);
4901                 
4902                 mini_emit_isninst_cast (cfg, klass_reg, klass, fail_1_bb, ok_result_bb);
4903
4904                 MONO_START_BB (cfg, fail_1_bb);
4905
4906                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4907                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4908
4909                 MONO_START_BB (cfg, no_proxy_bb);
4910
4911                 mini_emit_castclass (cfg, obj_reg, klass_reg, klass, ok_result_bb);
4912 #else
4913                 g_error ("Transparent proxy support is disabled while trying to JIT code that uses it");
4914 #endif
4915         }
4916
4917         MONO_START_BB (cfg, ok_result_bb);
4918
4919         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4920
4921 #ifndef DISABLE_REMOTING
4922         MONO_START_BB (cfg, end_bb);
4923 #endif
4924
4925         /* FIXME: */
4926         MONO_INST_NEW (cfg, ins, OP_ICONST);
4927         ins->dreg = dreg;
4928         ins->type = STACK_I4;
4929
4930         return ins;
4931 }
4932
4933 static G_GNUC_UNUSED MonoInst*
4934 handle_enum_has_flag (MonoCompile *cfg, MonoClass *klass, MonoInst *enum_this, MonoInst *enum_flag)
4935 {
4936         MonoType *enum_type = mono_type_get_underlying_type (&klass->byval_arg);
4937         guint32 load_opc = mono_type_to_load_membase (cfg, enum_type);
4938         gboolean is_i4;
4939
4940         switch (enum_type->type) {
4941         case MONO_TYPE_I8:
4942         case MONO_TYPE_U8:
4943 #if SIZEOF_REGISTER == 8
4944         case MONO_TYPE_I:
4945         case MONO_TYPE_U:
4946 #endif
4947                 is_i4 = FALSE;
4948                 break;
4949         default:
4950                 is_i4 = TRUE;
4951                 break;
4952         }
4953
4954         {
4955                 MonoInst *load, *and, *cmp, *ceq;
4956                 int enum_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
4957                 int and_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
4958                 int dest_reg = alloc_ireg (cfg);
4959
4960                 EMIT_NEW_LOAD_MEMBASE (cfg, load, load_opc, enum_reg, enum_this->dreg, 0);
4961                 EMIT_NEW_BIALU (cfg, and, is_i4 ? OP_IAND : OP_LAND, and_reg, enum_reg, enum_flag->dreg);
4962                 EMIT_NEW_BIALU (cfg, cmp, is_i4 ? OP_ICOMPARE : OP_LCOMPARE, -1, and_reg, enum_flag->dreg);
4963                 EMIT_NEW_UNALU (cfg, ceq, is_i4 ? OP_ICEQ : OP_LCEQ, dest_reg, -1);
4964
4965                 ceq->type = STACK_I4;
4966
4967                 if (!is_i4) {
4968                         load = mono_decompose_opcode (cfg, load);
4969                         and = mono_decompose_opcode (cfg, and);
4970                         cmp = mono_decompose_opcode (cfg, cmp);
4971                         ceq = mono_decompose_opcode (cfg, ceq);
4972                 }
4973
4974                 return ceq;
4975         }
4976 }
4977
4978 /*
4979  * Returns NULL and set the cfg exception on error.
4980  */
4981 static G_GNUC_UNUSED MonoInst*
4982 handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, MonoMethod *method, int context_used, gboolean virtual)
4983 {
4984         MonoInst *ptr;
4985         int dreg;
4986         gpointer trampoline;
4987         MonoInst *obj, *method_ins, *tramp_ins;
4988         MonoDomain *domain;
4989         guint8 **code_slot;
4990
4991         if (virtual && !cfg->llvm_only) {
4992                 MonoMethod *invoke = mono_get_delegate_invoke (klass);
4993                 g_assert (invoke);
4994
4995                 if (!mono_get_delegate_virtual_invoke_impl (mono_method_signature (invoke), context_used ? NULL : method))
4996                         return NULL;
4997         }
4998
4999         obj = handle_alloc (cfg, klass, FALSE, mono_class_check_context_used (klass));
5000         if (!obj)
5001                 return NULL;
5002
5003         if (cfg->llvm_only) {
5004                 MonoInst *args [16];
5005
5006                 /*
5007                  * If the method to be called needs an rgctx, we can't fall back to mono_delegate_ctor (), since it might receive
5008                  * the address of a gshared method. So use a JIT icall.
5009                  * FIXME: Optimize this.
5010                  */
5011                 args [0] = obj;
5012                 args [1] = target;
5013                 args [2] = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
5014                 mono_emit_jit_icall (cfg, virtual ? mono_init_delegate_virtual : mono_init_delegate, args);
5015
5016                 return obj;
5017         }
5018
5019         /* Inline the contents of mono_delegate_ctor */
5020
5021         /* Set target field */
5022         /* Optimize away setting of NULL target */
5023         if (!(target->opcode == OP_PCONST && target->inst_p0 == 0)) {
5024                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target), target->dreg);
5025                 if (cfg->gen_write_barriers) {
5026                         dreg = alloc_preg (cfg);
5027                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target));
5028                         emit_write_barrier (cfg, ptr, target);
5029                 }
5030         }
5031
5032         /* Set method field */
5033         method_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
5034         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method), method_ins->dreg);
5035
5036         /* 
5037          * To avoid looking up the compiled code belonging to the target method
5038          * in mono_delegate_trampoline (), we allocate a per-domain memory slot to
5039          * store it, and we fill it after the method has been compiled.
5040          */
5041         if (!method->dynamic && !(cfg->opt & MONO_OPT_SHARED)) {
5042                 MonoInst *code_slot_ins;
5043
5044                 if (context_used) {
5045                         code_slot_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD_DELEGATE_CODE);
5046                 } else {
5047                         domain = mono_domain_get ();
5048                         mono_domain_lock (domain);
5049                         if (!domain_jit_info (domain)->method_code_hash)
5050                                 domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
5051                         code_slot = g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, method);
5052                         if (!code_slot) {
5053                                 code_slot = mono_domain_alloc0 (domain, sizeof (gpointer));
5054                                 g_hash_table_insert (domain_jit_info (domain)->method_code_hash, method, code_slot);
5055                         }
5056                         mono_domain_unlock (domain);
5057
5058                         if (cfg->compile_aot)
5059                                 EMIT_NEW_AOTCONST (cfg, code_slot_ins, MONO_PATCH_INFO_METHOD_CODE_SLOT, method);
5060                         else
5061                                 EMIT_NEW_PCONST (cfg, code_slot_ins, code_slot);
5062                 }
5063                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_code), code_slot_ins->dreg);                
5064         }
5065
5066         if (cfg->compile_aot) {
5067                 MonoDelegateClassMethodPair *del_tramp;
5068
5069                 del_tramp = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoDelegateClassMethodPair));
5070                 del_tramp->klass = klass;
5071                 del_tramp->method = context_used ? NULL : method;
5072                 del_tramp->virtual = virtual;
5073                 EMIT_NEW_AOTCONST (cfg, tramp_ins, MONO_PATCH_INFO_DELEGATE_TRAMPOLINE, del_tramp);
5074         } else {
5075                 if (virtual)
5076                         trampoline = mono_create_delegate_virtual_trampoline (cfg->domain, klass, context_used ? NULL : method);
5077                 else
5078                         trampoline = mono_create_delegate_trampoline_info (cfg->domain, klass, context_used ? NULL : method);
5079                 EMIT_NEW_PCONST (cfg, tramp_ins, trampoline);
5080         }
5081
5082         /* Set invoke_impl field */
5083         if (virtual) {
5084                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), tramp_ins->dreg);
5085         } else {
5086                 dreg = alloc_preg (cfg);
5087                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, invoke_impl));
5088                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), dreg);
5089
5090                 dreg = alloc_preg (cfg);
5091                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, method_ptr));
5092                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr), dreg);
5093         }
5094
5095         dreg = alloc_preg (cfg);
5096         MONO_EMIT_NEW_ICONST (cfg, dreg, virtual ? 1 : 0);
5097         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_is_virtual), dreg);
5098
5099         /* All the checks which are in mono_delegate_ctor () are done by the delegate trampoline */
5100
5101         return obj;
5102 }
5103
5104 static MonoInst*
5105 handle_array_new (MonoCompile *cfg, int rank, MonoInst **sp, unsigned char *ip)
5106 {
5107         MonoJitICallInfo *info;
5108
5109         /* Need to register the icall so it gets an icall wrapper */
5110         info = mono_get_array_new_va_icall (rank);
5111
5112         cfg->flags |= MONO_CFG_HAS_VARARGS;
5113
5114         /* mono_array_new_va () needs a vararg calling convention */
5115         cfg->disable_llvm = TRUE;
5116
5117         /* FIXME: This uses info->sig, but it should use the signature of the wrapper */
5118         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, sp);
5119 }
5120
5121 /*
5122  * handle_constrained_gsharedvt_call:
5123  *
5124  *   Handle constrained calls where the receiver is a gsharedvt type.
5125  * Return the instruction representing the call. Set the cfg exception on failure.
5126  */
5127 static MonoInst*
5128 handle_constrained_gsharedvt_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp, MonoClass *constrained_class,
5129                                                                    gboolean *ref_emit_widen)
5130 {
5131         MonoInst *ins = NULL;
5132         gboolean emit_widen = *ref_emit_widen;
5133
5134         /*
5135          * Constrained calls need to behave differently at runtime dependending on whenever the receiver is instantiated as ref type or as a vtype.
5136          * 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
5137          * pack the arguments into an array, and do the rest of the work in in an icall.
5138          */
5139         if (((cmethod->klass == mono_defaults.object_class) || (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) || (!cmethod->klass->valuetype && cmethod->klass->image != mono_defaults.corlib)) &&
5140                 (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)) &&
5141                 (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]))))) {
5142                 MonoInst *args [16];
5143
5144                 /*
5145                  * This case handles calls to
5146                  * - object:ToString()/Equals()/GetHashCode(),
5147                  * - System.IComparable<T>:CompareTo()
5148                  * - System.IEquatable<T>:Equals ()
5149                  * plus some simple interface calls enough to support AsyncTaskMethodBuilder.
5150                  */
5151
5152                 args [0] = sp [0];
5153                 if (mono_method_check_context_used (cmethod))
5154                         args [1] = emit_get_rgctx_method (cfg, mono_method_check_context_used (cmethod), cmethod, MONO_RGCTX_INFO_METHOD);
5155                 else
5156                         EMIT_NEW_METHODCONST (cfg, args [1], cmethod);
5157                 args [2] = emit_get_rgctx_klass (cfg, mono_class_check_context_used (constrained_class), constrained_class, MONO_RGCTX_INFO_KLASS);
5158
5159                 /* !fsig->hasthis is for the wrapper for the Object.GetType () icall */
5160                 if (fsig->hasthis && fsig->param_count) {
5161                         /* Pass the arguments using a localloc-ed array using the format expected by runtime_invoke () */
5162                         MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
5163                         ins->dreg = alloc_preg (cfg);
5164                         ins->inst_imm = fsig->param_count * sizeof (mgreg_t);
5165                         MONO_ADD_INS (cfg->cbb, ins);
5166                         args [4] = ins;
5167
5168                         if (mini_is_gsharedvt_type (fsig->params [0])) {
5169                                 int addr_reg;
5170
5171                                 args [3] = emit_get_gsharedvt_info_klass (cfg, mono_class_from_mono_type (fsig->params [0]), MONO_RGCTX_INFO_CLASS_BOX_TYPE);
5172
5173                                 EMIT_NEW_VARLOADA_VREG (cfg, ins, sp [1]->dreg, fsig->params [0]);
5174                                 addr_reg = ins->dreg;
5175                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, addr_reg);
5176                         } else {
5177                                 EMIT_NEW_ICONST (cfg, args [3], 0);
5178                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, sp [1]->dreg);
5179                         }
5180                 } else {
5181                         EMIT_NEW_ICONST (cfg, args [3], 0);
5182                         EMIT_NEW_ICONST (cfg, args [4], 0);
5183                 }
5184                 ins = mono_emit_jit_icall (cfg, mono_gsharedvt_constrained_call, args);
5185                 emit_widen = FALSE;
5186
5187                 if (mini_is_gsharedvt_type (fsig->ret)) {
5188                         ins = handle_unbox_gsharedvt (cfg, mono_class_from_mono_type (fsig->ret), ins);
5189                 } else if (MONO_TYPE_IS_PRIMITIVE (fsig->ret) || MONO_TYPE_ISSTRUCT (fsig->ret)) {
5190                         MonoInst *add;
5191
5192                         /* Unbox */
5193                         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), ins->dreg, sizeof (MonoObject));
5194                         MONO_ADD_INS (cfg->cbb, add);
5195                         /* Load value */
5196                         NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, add->dreg, 0);
5197                         MONO_ADD_INS (cfg->cbb, ins);
5198                         /* ins represents the call result */
5199                 }
5200         } else {
5201                 GSHAREDVT_FAILURE (CEE_CALLVIRT);
5202         }
5203
5204         *ref_emit_widen = emit_widen;
5205
5206         return ins;
5207
5208  exception_exit:
5209         return NULL;
5210 }
5211
5212 static void
5213 mono_emit_load_got_addr (MonoCompile *cfg)
5214 {
5215         MonoInst *getaddr, *dummy_use;
5216
5217         if (!cfg->got_var || cfg->got_var_allocated)
5218                 return;
5219
5220         MONO_INST_NEW (cfg, getaddr, OP_LOAD_GOTADDR);
5221         getaddr->cil_code = cfg->header->code;
5222         getaddr->dreg = cfg->got_var->dreg;
5223
5224         /* Add it to the start of the first bblock */
5225         if (cfg->bb_entry->code) {
5226                 getaddr->next = cfg->bb_entry->code;
5227                 cfg->bb_entry->code = getaddr;
5228         }
5229         else
5230                 MONO_ADD_INS (cfg->bb_entry, getaddr);
5231
5232         cfg->got_var_allocated = TRUE;
5233
5234         /* 
5235          * Add a dummy use to keep the got_var alive, since real uses might
5236          * only be generated by the back ends.
5237          * Add it to end_bblock, so the variable's lifetime covers the whole
5238          * method.
5239          * It would be better to make the usage of the got var explicit in all
5240          * cases when the backend needs it (i.e. calls, throw etc.), so this
5241          * wouldn't be needed.
5242          */
5243         NEW_DUMMY_USE (cfg, dummy_use, cfg->got_var);
5244         MONO_ADD_INS (cfg->bb_exit, dummy_use);
5245 }
5246
5247 static int inline_limit;
5248 static gboolean inline_limit_inited;
5249
5250 static gboolean
5251 mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
5252 {
5253         MonoMethodHeaderSummary header;
5254         MonoVTable *vtable;
5255 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
5256         MonoMethodSignature *sig = mono_method_signature (method);
5257         int i;
5258 #endif
5259
5260         if (cfg->disable_inline)
5261                 return FALSE;
5262         if (cfg->gshared)
5263                 return FALSE;
5264
5265         if (cfg->inline_depth > 10)
5266                 return FALSE;
5267
5268         if (!mono_method_get_header_summary (method, &header))
5269                 return FALSE;
5270
5271         /*runtime, icall and pinvoke are checked by summary call*/
5272         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
5273             (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
5274             (mono_class_is_marshalbyref (method->klass)) ||
5275             header.has_clauses)
5276                 return FALSE;
5277
5278         /* also consider num_locals? */
5279         /* Do the size check early to avoid creating vtables */
5280         if (!inline_limit_inited) {
5281                 if (g_getenv ("MONO_INLINELIMIT"))
5282                         inline_limit = atoi (g_getenv ("MONO_INLINELIMIT"));
5283                 else
5284                         inline_limit = INLINE_LENGTH_LIMIT;
5285                 inline_limit_inited = TRUE;
5286         }
5287         if (header.code_size >= inline_limit && !(method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))
5288                 return FALSE;
5289
5290         /*
5291          * if we can initialize the class of the method right away, we do,
5292          * otherwise we don't allow inlining if the class needs initialization,
5293          * since it would mean inserting a call to mono_runtime_class_init()
5294          * inside the inlined code
5295          */
5296         if (!(cfg->opt & MONO_OPT_SHARED)) {
5297                 /* The AggressiveInlining hint is a good excuse to force that cctor to run. */
5298                 if (method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING) {
5299                         vtable = mono_class_vtable (cfg->domain, method->klass);
5300                         if (!vtable)
5301                                 return FALSE;
5302                         if (!cfg->compile_aot)
5303                                 mono_runtime_class_init (vtable);
5304                 } else if (method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
5305                         if (cfg->run_cctors && method->klass->has_cctor) {
5306                                 /*FIXME it would easier and lazier to just use mono_class_try_get_vtable */
5307                                 if (!method->klass->runtime_info)
5308                                         /* No vtable created yet */
5309                                         return FALSE;
5310                                 vtable = mono_class_vtable (cfg->domain, method->klass);
5311                                 if (!vtable)
5312                                         return FALSE;
5313                                 /* This makes so that inline cannot trigger */
5314                                 /* .cctors: too many apps depend on them */
5315                                 /* running with a specific order... */
5316                                 if (! vtable->initialized)
5317                                         return FALSE;
5318                                 mono_runtime_class_init (vtable);
5319                         }
5320                 } else if (mono_class_needs_cctor_run (method->klass, NULL)) {
5321                         if (!method->klass->runtime_info)
5322                                 /* No vtable created yet */
5323                                 return FALSE;
5324                         vtable = mono_class_vtable (cfg->domain, method->klass);
5325                         if (!vtable)
5326                                 return FALSE;
5327                         if (!vtable->initialized)
5328                                 return FALSE;
5329                 }
5330         } else {
5331                 /* 
5332                  * If we're compiling for shared code
5333                  * the cctor will need to be run at aot method load time, for example,
5334                  * or at the end of the compilation of the inlining method.
5335                  */
5336                 if (mono_class_needs_cctor_run (method->klass, NULL) && !((method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)))
5337                         return FALSE;
5338         }
5339
5340 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
5341         if (mono_arch_is_soft_float ()) {
5342                 /* FIXME: */
5343                 if (sig->ret && sig->ret->type == MONO_TYPE_R4)
5344                         return FALSE;
5345                 for (i = 0; i < sig->param_count; ++i)
5346                         if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_R4)
5347                                 return FALSE;
5348         }
5349 #endif
5350
5351         if (g_list_find (cfg->dont_inline, method))
5352                 return FALSE;
5353
5354         return TRUE;
5355 }
5356
5357 static gboolean
5358 mini_field_access_needs_cctor_run (MonoCompile *cfg, MonoMethod *method, MonoClass *klass, MonoVTable *vtable)
5359 {
5360         if (!cfg->compile_aot) {
5361                 g_assert (vtable);
5362                 if (vtable->initialized)
5363                         return FALSE;
5364         }
5365
5366         if (klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
5367                 if (cfg->method == method)
5368                         return FALSE;
5369         }
5370
5371         if (!mono_class_needs_cctor_run (klass, method))
5372                 return FALSE;
5373
5374         if (! (method->flags & METHOD_ATTRIBUTE_STATIC) && (klass == method->klass))
5375                 /* The initialization is already done before the method is called */
5376                 return FALSE;
5377
5378         return TRUE;
5379 }
5380
5381 static MonoInst*
5382 mini_emit_ldelema_1_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index, gboolean bcheck)
5383 {
5384         MonoInst *ins;
5385         guint32 size;
5386         int mult_reg, add_reg, array_reg, index_reg, index2_reg;
5387         int context_used;
5388
5389         if (mini_is_gsharedvt_variable_klass (klass)) {
5390                 size = -1;
5391         } else {
5392                 mono_class_init (klass);
5393                 size = mono_class_array_element_size (klass);
5394         }
5395
5396         mult_reg = alloc_preg (cfg);
5397         array_reg = arr->dreg;
5398         index_reg = index->dreg;
5399
5400 #if SIZEOF_REGISTER == 8
5401         /* The array reg is 64 bits but the index reg is only 32 */
5402         if (COMPILE_LLVM (cfg)) {
5403                 /* Not needed */
5404                 index2_reg = index_reg;
5405         } else {
5406                 index2_reg = alloc_preg (cfg);
5407                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index2_reg, index_reg);
5408         }
5409 #else
5410         if (index->type == STACK_I8) {
5411                 index2_reg = alloc_preg (cfg);
5412                 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I4, index2_reg, index_reg);
5413         } else {
5414                 index2_reg = index_reg;
5415         }
5416 #endif
5417
5418         if (bcheck)
5419                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index2_reg);
5420
5421 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5422         if (size == 1 || size == 2 || size == 4 || size == 8) {
5423                 static const int fast_log2 [] = { 1, 0, 1, -1, 2, -1, -1, -1, 3 };
5424
5425                 EMIT_NEW_X86_LEA (cfg, ins, array_reg, index2_reg, fast_log2 [size], MONO_STRUCT_OFFSET (MonoArray, vector));
5426                 ins->klass = mono_class_get_element_class (klass);
5427                 ins->type = STACK_MP;
5428
5429                 return ins;
5430         }
5431 #endif          
5432
5433         add_reg = alloc_ireg_mp (cfg);
5434
5435         if (size == -1) {
5436                 MonoInst *rgctx_ins;
5437
5438                 /* gsharedvt */
5439                 g_assert (cfg->gshared);
5440                 context_used = mini_class_check_context_used (cfg, klass);
5441                 g_assert (context_used);
5442                 rgctx_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE);
5443                 MONO_EMIT_NEW_BIALU (cfg, OP_IMUL, mult_reg, index2_reg, rgctx_ins->dreg);
5444         } else {
5445                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MUL_IMM, mult_reg, index2_reg, size);
5446         }
5447         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, array_reg, mult_reg);
5448         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
5449         ins->klass = mono_class_get_element_class (klass);
5450         ins->type = STACK_MP;
5451         MONO_ADD_INS (cfg->cbb, ins);
5452
5453         return ins;
5454 }
5455
5456 #ifndef MONO_ARCH_EMULATE_MUL_DIV
5457 static MonoInst*
5458 mini_emit_ldelema_2_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index_ins1, MonoInst *index_ins2)
5459 {
5460         int bounds_reg = alloc_preg (cfg);
5461         int add_reg = alloc_ireg_mp (cfg);
5462         int mult_reg = alloc_preg (cfg);
5463         int mult2_reg = alloc_preg (cfg);
5464         int low1_reg = alloc_preg (cfg);
5465         int low2_reg = alloc_preg (cfg);
5466         int high1_reg = alloc_preg (cfg);
5467         int high2_reg = alloc_preg (cfg);
5468         int realidx1_reg = alloc_preg (cfg);
5469         int realidx2_reg = alloc_preg (cfg);
5470         int sum_reg = alloc_preg (cfg);
5471         int index1, index2, tmpreg;
5472         MonoInst *ins;
5473         guint32 size;
5474
5475         mono_class_init (klass);
5476         size = mono_class_array_element_size (klass);
5477
5478         index1 = index_ins1->dreg;
5479         index2 = index_ins2->dreg;
5480
5481 #if SIZEOF_REGISTER == 8
5482         /* The array reg is 64 bits but the index reg is only 32 */
5483         if (COMPILE_LLVM (cfg)) {
5484                 /* Not needed */
5485         } else {
5486                 tmpreg = alloc_preg (cfg);
5487                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index1);
5488                 index1 = tmpreg;
5489                 tmpreg = alloc_preg (cfg);
5490                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index2);
5491                 index2 = tmpreg;
5492         }
5493 #else
5494         // FIXME: Do we need to do something here for i8 indexes, like in ldelema_1_ins ?
5495         tmpreg = -1;
5496 #endif
5497
5498         /* range checking */
5499         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, 
5500                                        arr->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
5501
5502         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low1_reg, 
5503                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5504         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx1_reg, index1, low1_reg);
5505         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high1_reg, 
5506                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5507         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high1_reg, realidx1_reg);
5508         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
5509
5510         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low2_reg, 
5511                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5512         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx2_reg, index2, low2_reg);
5513         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high2_reg, 
5514                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5515         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high2_reg, realidx2_reg);
5516         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
5517
5518         MONO_EMIT_NEW_BIALU (cfg, OP_PMUL, mult_reg, high2_reg, realidx1_reg);
5519         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, mult_reg, realidx2_reg);
5520         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PMUL_IMM, mult2_reg, sum_reg, size);
5521         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult2_reg, arr->dreg);
5522         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
5523
5524         ins->type = STACK_MP;
5525         ins->klass = klass;
5526         MONO_ADD_INS (cfg->cbb, ins);
5527
5528         return ins;
5529 }
5530 #endif
5531
5532 static MonoInst*
5533 mini_emit_ldelema_ins (MonoCompile *cfg, MonoMethod *cmethod, MonoInst **sp, unsigned char *ip, gboolean is_set)
5534 {
5535         int rank;
5536         MonoInst *addr;
5537         MonoMethod *addr_method;
5538         int element_size;
5539         MonoClass *eclass = cmethod->klass->element_class;
5540
5541         rank = mono_method_signature (cmethod)->param_count - (is_set? 1: 0);
5542
5543         if (rank == 1)
5544                 return mini_emit_ldelema_1_ins (cfg, eclass, sp [0], sp [1], TRUE);
5545
5546 #ifndef MONO_ARCH_EMULATE_MUL_DIV
5547         /* emit_ldelema_2 depends on OP_LMUL */
5548         if (rank == 2 && (cfg->opt & MONO_OPT_INTRINS) && !mini_is_gsharedvt_variable_klass (eclass)) {
5549                 return mini_emit_ldelema_2_ins (cfg, eclass, sp [0], sp [1], sp [2]);
5550         }
5551 #endif
5552
5553         if (mini_is_gsharedvt_variable_klass (eclass))
5554                 element_size = 0;
5555         else
5556                 element_size = mono_class_array_element_size (eclass);
5557         addr_method = mono_marshal_get_array_address (rank, element_size);
5558         addr = mono_emit_method_call (cfg, addr_method, sp, NULL);
5559
5560         return addr;
5561 }
5562
5563 static MonoBreakPolicy
5564 always_insert_breakpoint (MonoMethod *method)
5565 {
5566         return MONO_BREAK_POLICY_ALWAYS;
5567 }
5568
5569 static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
5570
5571 /**
5572  * mono_set_break_policy:
5573  * policy_callback: the new callback function
5574  *
5575  * Allow embedders to decide wherther to actually obey breakpoint instructions
5576  * (both break IL instructions and Debugger.Break () method calls), for example
5577  * to not allow an app to be aborted by a perfectly valid IL opcode when executing
5578  * untrusted or semi-trusted code.
5579  *
5580  * @policy_callback will be called every time a break point instruction needs to
5581  * be inserted with the method argument being the method that calls Debugger.Break()
5582  * or has the IL break instruction. The callback should return #MONO_BREAK_POLICY_NEVER
5583  * if it wants the breakpoint to not be effective in the given method.
5584  * #MONO_BREAK_POLICY_ALWAYS is the default.
5585  */
5586 void
5587 mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
5588 {
5589         if (policy_callback)
5590                 break_policy_func = policy_callback;
5591         else
5592                 break_policy_func = always_insert_breakpoint;
5593 }
5594
5595 static gboolean
5596 should_insert_brekpoint (MonoMethod *method) {
5597         switch (break_policy_func (method)) {
5598         case MONO_BREAK_POLICY_ALWAYS:
5599                 return TRUE;
5600         case MONO_BREAK_POLICY_NEVER:
5601                 return FALSE;
5602         case MONO_BREAK_POLICY_ON_DBG:
5603                 g_warning ("mdb no longer supported");
5604                 return FALSE;
5605         default:
5606                 g_warning ("Incorrect value returned from break policy callback");
5607                 return FALSE;
5608         }
5609 }
5610
5611 /* optimize the simple GetGenericValueImpl/SetGenericValueImpl generic icalls */
5612 static MonoInst*
5613 emit_array_generic_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
5614 {
5615         MonoInst *addr, *store, *load;
5616         MonoClass *eklass = mono_class_from_mono_type (fsig->params [2]);
5617
5618         /* the bounds check is already done by the callers */
5619         addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
5620         if (is_set) {
5621                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, args [2]->dreg, 0);
5622                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, addr->dreg, 0, load->dreg);
5623                 if (mini_type_is_reference (fsig->params [2]))
5624                         emit_write_barrier (cfg, addr, load);
5625         } else {
5626                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, addr->dreg, 0);
5627                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, args [2]->dreg, 0, load->dreg);
5628         }
5629         return store;
5630 }
5631
5632
5633 static gboolean
5634 generic_class_is_reference_type (MonoCompile *cfg, MonoClass *klass)
5635 {
5636         return mini_type_is_reference (&klass->byval_arg);
5637 }
5638
5639 static MonoInst*
5640 emit_array_store (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, gboolean safety_checks)
5641 {
5642         if (safety_checks && generic_class_is_reference_type (cfg, klass) &&
5643                 !(sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL)) {
5644                 MonoClass *obj_array = mono_array_class_get_cached (mono_defaults.object_class, 1);
5645                 MonoMethod *helper = mono_marshal_get_virtual_stelemref (obj_array);
5646                 MonoInst *iargs [3];
5647
5648                 if (!helper->slot)
5649                         mono_class_setup_vtable (obj_array);
5650                 g_assert (helper->slot);
5651
5652                 if (sp [0]->type != STACK_OBJ)
5653                         return NULL;
5654                 if (sp [2]->type != STACK_OBJ)
5655                         return NULL;
5656
5657                 iargs [2] = sp [2];
5658                 iargs [1] = sp [1];
5659                 iargs [0] = sp [0];
5660
5661                 return mono_emit_method_call (cfg, helper, iargs, sp [0]);
5662         } else {
5663                 MonoInst *ins;
5664
5665                 if (mini_is_gsharedvt_variable_klass (klass)) {
5666                         MonoInst *addr;
5667
5668                         // FIXME-VT: OP_ICONST optimization
5669                         addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
5670                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5671                         ins->opcode = OP_STOREV_MEMBASE;
5672                 } else if (sp [1]->opcode == OP_ICONST) {
5673                         int array_reg = sp [0]->dreg;
5674                         int index_reg = sp [1]->dreg;
5675                         int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
5676
5677                         if (safety_checks)
5678                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
5679                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset, sp [2]->dreg);
5680                 } else {
5681                         MonoInst *addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], safety_checks);
5682                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5683                         if (generic_class_is_reference_type (cfg, klass))
5684                                 emit_write_barrier (cfg, addr, sp [2]);
5685                 }
5686                 return ins;
5687         }
5688 }
5689
5690 static MonoInst*
5691 emit_array_unsafe_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
5692 {
5693         MonoClass *eklass;
5694         
5695         if (is_set)
5696                 eklass = mono_class_from_mono_type (fsig->params [2]);
5697         else
5698                 eklass = mono_class_from_mono_type (fsig->ret);
5699
5700         if (is_set) {
5701                 return emit_array_store (cfg, eklass, args, FALSE);
5702         } else {
5703                 MonoInst *ins, *addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
5704                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &eklass->byval_arg, addr->dreg, 0);
5705                 return ins;
5706         }
5707 }
5708
5709 static gboolean
5710 is_unsafe_mov_compatible (MonoCompile *cfg, MonoClass *param_klass, MonoClass *return_klass)
5711 {
5712         uint32_t align;
5713
5714         param_klass = mono_class_from_mono_type (mini_get_underlying_type (&param_klass->byval_arg));
5715
5716         //Only allow for valuetypes
5717         if (!param_klass->valuetype || !return_klass->valuetype)
5718                 return FALSE;
5719
5720         //That are blitable
5721         if (param_klass->has_references || return_klass->has_references)
5722                 return FALSE;
5723
5724         /* Avoid mixing structs and primitive types/enums, they need to be handled differently in the JIT */
5725         if ((MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && !MONO_TYPE_ISSTRUCT (&return_klass->byval_arg)) ||
5726                 (!MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && MONO_TYPE_ISSTRUCT (&return_klass->byval_arg)))
5727                 return FALSE;
5728
5729         if (param_klass->byval_arg.type == MONO_TYPE_R4 || param_klass->byval_arg.type == MONO_TYPE_R8 ||
5730                 return_klass->byval_arg.type == MONO_TYPE_R4 || return_klass->byval_arg.type == MONO_TYPE_R8)
5731                 return FALSE;
5732
5733         //And have the same size
5734         if (mono_class_value_size (param_klass, &align) != mono_class_value_size (return_klass, &align))
5735                 return FALSE;
5736         return TRUE;
5737 }
5738
5739 static MonoInst*
5740 emit_array_unsafe_mov (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args)
5741 {
5742         MonoClass *param_klass = mono_class_from_mono_type (fsig->params [0]);
5743         MonoClass *return_klass = mono_class_from_mono_type (fsig->ret);
5744
5745         //Valuetypes that are semantically equivalent
5746         if (is_unsafe_mov_compatible (cfg, param_klass, return_klass))
5747                 return args [0];
5748
5749         //Arrays of valuetypes that are semantically equivalent
5750         if (param_klass->rank == 1 && return_klass->rank == 1 && is_unsafe_mov_compatible (cfg, param_klass->element_class, return_klass->element_class))
5751                 return args [0];
5752
5753         return NULL;
5754 }
5755
5756 static MonoInst*
5757 mini_emit_inst_for_ctor (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5758 {
5759 #ifdef MONO_ARCH_SIMD_INTRINSICS
5760         MonoInst *ins = NULL;
5761
5762         if (cfg->opt & MONO_OPT_SIMD) {
5763                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
5764                 if (ins)
5765                         return ins;
5766         }
5767 #endif
5768
5769         return mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
5770 }
5771
5772 static MonoInst*
5773 emit_memory_barrier (MonoCompile *cfg, int kind)
5774 {
5775         MonoInst *ins = NULL;
5776         MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
5777         MONO_ADD_INS (cfg->cbb, ins);
5778         ins->backend.memory_barrier_kind = kind;
5779
5780         return ins;
5781 }
5782
5783 static MonoInst*
5784 llvm_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5785 {
5786         MonoInst *ins = NULL;
5787         int opcode = 0;
5788
5789         /* The LLVM backend supports these intrinsics */
5790         if (cmethod->klass == mono_defaults.math_class) {
5791                 if (strcmp (cmethod->name, "Sin") == 0) {
5792                         opcode = OP_SIN;
5793                 } else if (strcmp (cmethod->name, "Cos") == 0) {
5794                         opcode = OP_COS;
5795                 } else if (strcmp (cmethod->name, "Sqrt") == 0) {
5796                         opcode = OP_SQRT;
5797                 } else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8) {
5798                         opcode = OP_ABS;
5799                 }
5800
5801                 if (opcode && fsig->param_count == 1) {
5802                         MONO_INST_NEW (cfg, ins, opcode);
5803                         ins->type = STACK_R8;
5804                         ins->dreg = mono_alloc_freg (cfg);
5805                         ins->sreg1 = args [0]->dreg;
5806                         MONO_ADD_INS (cfg->cbb, ins);
5807                 }
5808
5809                 opcode = 0;
5810                 if (cfg->opt & MONO_OPT_CMOV) {
5811                         if (strcmp (cmethod->name, "Min") == 0) {
5812                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5813                                         opcode = OP_IMIN;
5814                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5815                                         opcode = OP_IMIN_UN;
5816                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5817                                         opcode = OP_LMIN;
5818                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5819                                         opcode = OP_LMIN_UN;
5820                         } else if (strcmp (cmethod->name, "Max") == 0) {
5821                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5822                                         opcode = OP_IMAX;
5823                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5824                                         opcode = OP_IMAX_UN;
5825                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5826                                         opcode = OP_LMAX;
5827                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5828                                         opcode = OP_LMAX_UN;
5829                         }
5830                 }
5831
5832                 if (opcode && fsig->param_count == 2) {
5833                         MONO_INST_NEW (cfg, ins, opcode);
5834                         ins->type = fsig->params [0]->type == MONO_TYPE_I4 ? STACK_I4 : STACK_I8;
5835                         ins->dreg = mono_alloc_ireg (cfg);
5836                         ins->sreg1 = args [0]->dreg;
5837                         ins->sreg2 = args [1]->dreg;
5838                         MONO_ADD_INS (cfg->cbb, ins);
5839                 }
5840         }
5841
5842         return ins;
5843 }
5844
5845 static MonoInst*
5846 mini_emit_inst_for_sharable_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5847 {
5848         if (cmethod->klass == mono_defaults.array_class) {
5849                 if (strcmp (cmethod->name, "UnsafeStore") == 0)
5850                         return emit_array_unsafe_access (cfg, fsig, args, TRUE);
5851                 else if (strcmp (cmethod->name, "UnsafeLoad") == 0)
5852                         return emit_array_unsafe_access (cfg, fsig, args, FALSE);
5853                 else if (strcmp (cmethod->name, "UnsafeMov") == 0)
5854                         return emit_array_unsafe_mov (cfg, fsig, args);
5855         }
5856
5857         return NULL;
5858 }
5859
5860 static MonoInst*
5861 mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5862 {
5863         MonoInst *ins = NULL;
5864
5865         static MonoClass *runtime_helpers_class = NULL;
5866         if (! runtime_helpers_class)
5867                 runtime_helpers_class = mono_class_from_name (mono_defaults.corlib,
5868                         "System.Runtime.CompilerServices", "RuntimeHelpers");
5869
5870         if (cmethod->klass == mono_defaults.string_class) {
5871                 if (strcmp (cmethod->name, "get_Chars") == 0 && fsig->param_count + fsig->hasthis == 2) {
5872                         int dreg = alloc_ireg (cfg);
5873                         int index_reg = alloc_preg (cfg);
5874                         int add_reg = alloc_preg (cfg);
5875
5876 #if SIZEOF_REGISTER == 8
5877                         /* The array reg is 64 bits but the index reg is only 32 */
5878                         MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index_reg, args [1]->dreg);
5879 #else
5880                         index_reg = args [1]->dreg;
5881 #endif  
5882                         MONO_EMIT_BOUNDS_CHECK (cfg, args [0]->dreg, MonoString, length, index_reg);
5883
5884 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5885                         EMIT_NEW_X86_LEA (cfg, ins, args [0]->dreg, index_reg, 1, MONO_STRUCT_OFFSET (MonoString, chars));
5886                         add_reg = ins->dreg;
5887                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5888                                                                    add_reg, 0);
5889 #else
5890                         int mult_reg = alloc_preg (cfg);
5891                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, index_reg, 1);
5892                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
5893                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5894                                                                    add_reg, MONO_STRUCT_OFFSET (MonoString, chars));
5895 #endif
5896                         type_from_op (cfg, ins, NULL, NULL);
5897                         return ins;
5898                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count + fsig->hasthis == 1) {
5899                         int dreg = alloc_ireg (cfg);
5900                         /* Decompose later to allow more optimizations */
5901                         EMIT_NEW_UNALU (cfg, ins, OP_STRLEN, dreg, args [0]->dreg);
5902                         ins->type = STACK_I4;
5903                         ins->flags |= MONO_INST_FAULT;
5904                         cfg->cbb->has_array_access = TRUE;
5905                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
5906
5907                         return ins;
5908                 } else 
5909                         return NULL;
5910         } else if (cmethod->klass == mono_defaults.object_class) {
5911
5912                 if (strcmp (cmethod->name, "GetType") == 0 && fsig->param_count + fsig->hasthis == 1) {
5913                         int dreg = alloc_ireg_ref (cfg);
5914                         int vt_reg = alloc_preg (cfg);
5915                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vt_reg, args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
5916                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, vt_reg, MONO_STRUCT_OFFSET (MonoVTable, type));
5917                         type_from_op (cfg, ins, NULL, NULL);
5918
5919                         return ins;
5920 #if !defined(MONO_ARCH_EMULATE_MUL_DIV)
5921                 } else if (strcmp (cmethod->name, "InternalGetHashCode") == 0 && fsig->param_count == 1 && !mono_gc_is_moving ()) {
5922                         int dreg = alloc_ireg (cfg);
5923                         int t1 = alloc_ireg (cfg);
5924         
5925                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, t1, args [0]->dreg, 3);
5926                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_MUL_IMM, dreg, t1, 2654435761u);
5927                         ins->type = STACK_I4;
5928
5929                         return ins;
5930 #endif
5931                 } else if (strcmp (cmethod->name, ".ctor") == 0 && fsig->param_count == 0) {
5932                         MONO_INST_NEW (cfg, ins, OP_NOP);
5933                         MONO_ADD_INS (cfg->cbb, ins);
5934                         return ins;
5935                 } else
5936                         return NULL;
5937         } else if (cmethod->klass == mono_defaults.array_class) {
5938                 if (strcmp (cmethod->name, "GetGenericValueImpl") == 0 && fsig->param_count + fsig->hasthis == 3 && !cfg->gsharedvt)
5939                         return emit_array_generic_access (cfg, fsig, args, FALSE);
5940                 else if (strcmp (cmethod->name, "SetGenericValueImpl") == 0 && fsig->param_count + fsig->hasthis == 3 && !cfg->gsharedvt)
5941                         return emit_array_generic_access (cfg, fsig, args, TRUE);
5942
5943 #ifndef MONO_BIG_ARRAYS
5944                 /*
5945                  * This is an inline version of GetLength/GetLowerBound(0) used frequently in
5946                  * Array methods.
5947                  */
5948                 else if (((strcmp (cmethod->name, "GetLength") == 0 && fsig->param_count + fsig->hasthis == 2) ||
5949                          (strcmp (cmethod->name, "GetLowerBound") == 0 && fsig->param_count + fsig->hasthis == 2)) &&
5950                          args [1]->opcode == OP_ICONST && args [1]->inst_c0 == 0) {
5951                         int dreg = alloc_ireg (cfg);
5952                         int bounds_reg = alloc_ireg_mp (cfg);
5953                         MonoBasicBlock *end_bb, *szarray_bb;
5954                         gboolean get_length = strcmp (cmethod->name, "GetLength") == 0;
5955
5956                         NEW_BBLOCK (cfg, end_bb);
5957                         NEW_BBLOCK (cfg, szarray_bb);
5958
5959                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOAD_MEMBASE, bounds_reg,
5960                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
5961                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
5962                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, szarray_bb);
5963                         /* Non-szarray case */
5964                         if (get_length)
5965                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5966                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5967                         else
5968                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5969                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5970                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
5971                         MONO_START_BB (cfg, szarray_bb);
5972                         /* Szarray case */
5973                         if (get_length)
5974                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5975                                                                            args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
5976                         else
5977                                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
5978                         MONO_START_BB (cfg, end_bb);
5979
5980                         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, dreg, dreg);
5981                         ins->type = STACK_I4;
5982                         
5983                         return ins;
5984                 }
5985 #endif
5986
5987                 if (cmethod->name [0] != 'g')
5988                         return NULL;
5989
5990                 if (strcmp (cmethod->name, "get_Rank") == 0 && fsig->param_count + fsig->hasthis == 1) {
5991                         int dreg = alloc_ireg (cfg);
5992                         int vtable_reg = alloc_preg (cfg);
5993                         MONO_EMIT_NEW_LOAD_MEMBASE_OP_FAULT (cfg, OP_LOAD_MEMBASE, vtable_reg, 
5994                                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
5995                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU1_MEMBASE, dreg,
5996                                                                    vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
5997                         type_from_op (cfg, ins, NULL, NULL);
5998
5999                         return ins;
6000                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count + fsig->hasthis == 1) {
6001                         int dreg = alloc_ireg (cfg);
6002
6003                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOADI4_MEMBASE, dreg, 
6004                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
6005                         type_from_op (cfg, ins, NULL, NULL);
6006
6007                         return ins;
6008                 } else
6009                         return NULL;
6010         } else if (cmethod->klass == runtime_helpers_class) {
6011
6012                 if (strcmp (cmethod->name, "get_OffsetToStringData") == 0 && fsig->param_count == 0) {
6013                         EMIT_NEW_ICONST (cfg, ins, MONO_STRUCT_OFFSET (MonoString, chars));
6014                         return ins;
6015                 } else
6016                         return NULL;
6017         } else if (cmethod->klass == mono_defaults.thread_class) {
6018                 if (strcmp (cmethod->name, "SpinWait_nop") == 0 && fsig->param_count == 0) {
6019                         MONO_INST_NEW (cfg, ins, OP_RELAXED_NOP);
6020                         MONO_ADD_INS (cfg->cbb, ins);
6021                         return ins;
6022                 } else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0) {
6023                         return emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6024                 } else if (!strcmp (cmethod->name, "VolatileRead") && fsig->param_count == 1) {
6025                         guint32 opcode = 0;
6026                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6027
6028                         if (fsig->params [0]->type == MONO_TYPE_I1)
6029                                 opcode = OP_LOADI1_MEMBASE;
6030                         else if (fsig->params [0]->type == MONO_TYPE_U1)
6031                                 opcode = OP_LOADU1_MEMBASE;
6032                         else if (fsig->params [0]->type == MONO_TYPE_I2)
6033                                 opcode = OP_LOADI2_MEMBASE;
6034                         else if (fsig->params [0]->type == MONO_TYPE_U2)
6035                                 opcode = OP_LOADU2_MEMBASE;
6036                         else if (fsig->params [0]->type == MONO_TYPE_I4)
6037                                 opcode = OP_LOADI4_MEMBASE;
6038                         else if (fsig->params [0]->type == MONO_TYPE_U4)
6039                                 opcode = OP_LOADU4_MEMBASE;
6040                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
6041                                 opcode = OP_LOADI8_MEMBASE;
6042                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6043                                 opcode = OP_LOADR4_MEMBASE;
6044                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6045                                 opcode = OP_LOADR8_MEMBASE;
6046                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
6047                                 opcode = OP_LOAD_MEMBASE;
6048
6049                         if (opcode) {
6050                                 MONO_INST_NEW (cfg, ins, opcode);
6051                                 ins->inst_basereg = args [0]->dreg;
6052                                 ins->inst_offset = 0;
6053                                 MONO_ADD_INS (cfg->cbb, ins);
6054
6055                                 switch (fsig->params [0]->type) {
6056                                 case MONO_TYPE_I1:
6057                                 case MONO_TYPE_U1:
6058                                 case MONO_TYPE_I2:
6059                                 case MONO_TYPE_U2:
6060                                 case MONO_TYPE_I4:
6061                                 case MONO_TYPE_U4:
6062                                         ins->dreg = mono_alloc_ireg (cfg);
6063                                         ins->type = STACK_I4;
6064                                         break;
6065                                 case MONO_TYPE_I8:
6066                                 case MONO_TYPE_U8:
6067                                         ins->dreg = mono_alloc_lreg (cfg);
6068                                         ins->type = STACK_I8;
6069                                         break;
6070                                 case MONO_TYPE_I:
6071                                 case MONO_TYPE_U:
6072                                         ins->dreg = mono_alloc_ireg (cfg);
6073 #if SIZEOF_REGISTER == 8
6074                                         ins->type = STACK_I8;
6075 #else
6076                                         ins->type = STACK_I4;
6077 #endif
6078                                         break;
6079                                 case MONO_TYPE_R4:
6080                                 case MONO_TYPE_R8:
6081                                         ins->dreg = mono_alloc_freg (cfg);
6082                                         ins->type = STACK_R8;
6083                                         break;
6084                                 default:
6085                                         g_assert (mini_type_is_reference (fsig->params [0]));
6086                                         ins->dreg = mono_alloc_ireg_ref (cfg);
6087                                         ins->type = STACK_OBJ;
6088                                         break;
6089                                 }
6090
6091                                 if (opcode == OP_LOADI8_MEMBASE)
6092                                         ins = mono_decompose_opcode (cfg, ins);
6093
6094                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
6095
6096                                 return ins;
6097                         }
6098                 } else if (!strcmp (cmethod->name, "VolatileWrite") && fsig->param_count == 2) {
6099                         guint32 opcode = 0;
6100                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6101
6102                         if (fsig->params [0]->type == MONO_TYPE_I1 || fsig->params [0]->type == MONO_TYPE_U1)
6103                                 opcode = OP_STOREI1_MEMBASE_REG;
6104                         else if (fsig->params [0]->type == MONO_TYPE_I2 || fsig->params [0]->type == MONO_TYPE_U2)
6105                                 opcode = OP_STOREI2_MEMBASE_REG;
6106                         else if (fsig->params [0]->type == MONO_TYPE_I4 || fsig->params [0]->type == MONO_TYPE_U4)
6107                                 opcode = OP_STOREI4_MEMBASE_REG;
6108                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
6109                                 opcode = OP_STOREI8_MEMBASE_REG;
6110                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6111                                 opcode = OP_STORER4_MEMBASE_REG;
6112                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6113                                 opcode = OP_STORER8_MEMBASE_REG;
6114                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
6115                                 opcode = OP_STORE_MEMBASE_REG;
6116
6117                         if (opcode) {
6118                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
6119
6120                                 MONO_INST_NEW (cfg, ins, opcode);
6121                                 ins->sreg1 = args [1]->dreg;
6122                                 ins->inst_destbasereg = args [0]->dreg;
6123                                 ins->inst_offset = 0;
6124                                 MONO_ADD_INS (cfg->cbb, ins);
6125
6126                                 if (opcode == OP_STOREI8_MEMBASE_REG)
6127                                         ins = mono_decompose_opcode (cfg, ins);
6128
6129                                 return ins;
6130                         }
6131                 }
6132         } else if (cmethod->klass->image == mono_defaults.corlib &&
6133                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
6134                            (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
6135                 ins = NULL;
6136
6137 #if SIZEOF_REGISTER == 8
6138                 if (strcmp (cmethod->name, "Read") == 0 && fsig->param_count == 1 && (fsig->params [0]->type == MONO_TYPE_I8)) {
6139                         if (mono_arch_opcode_supported (OP_ATOMIC_LOAD_I8)) {
6140                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_LOAD_I8);
6141                                 ins->dreg = mono_alloc_preg (cfg);
6142                                 ins->sreg1 = args [0]->dreg;
6143                                 ins->type = STACK_I8;
6144                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_SEQ;
6145                                 MONO_ADD_INS (cfg->cbb, ins);
6146                         } else {
6147                                 MonoInst *load_ins;
6148
6149                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6150
6151                                 /* 64 bit reads are already atomic */
6152                                 MONO_INST_NEW (cfg, load_ins, OP_LOADI8_MEMBASE);
6153                                 load_ins->dreg = mono_alloc_preg (cfg);
6154                                 load_ins->inst_basereg = args [0]->dreg;
6155                                 load_ins->inst_offset = 0;
6156                                 load_ins->type = STACK_I8;
6157                                 MONO_ADD_INS (cfg->cbb, load_ins);
6158
6159                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6160
6161                                 ins = load_ins;
6162                         }
6163                 }
6164 #endif
6165
6166                 if (strcmp (cmethod->name, "Increment") == 0 && fsig->param_count == 1) {
6167                         MonoInst *ins_iconst;
6168                         guint32 opcode = 0;
6169
6170                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6171                                 opcode = OP_ATOMIC_ADD_I4;
6172                                 cfg->has_atomic_add_i4 = TRUE;
6173                         }
6174 #if SIZEOF_REGISTER == 8
6175                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6176                                 opcode = OP_ATOMIC_ADD_I8;
6177 #endif
6178                         if (opcode) {
6179                                 if (!mono_arch_opcode_supported (opcode))
6180                                         return NULL;
6181                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
6182                                 ins_iconst->inst_c0 = 1;
6183                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
6184                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
6185
6186                                 MONO_INST_NEW (cfg, ins, opcode);
6187                                 ins->dreg = mono_alloc_ireg (cfg);
6188                                 ins->inst_basereg = args [0]->dreg;
6189                                 ins->inst_offset = 0;
6190                                 ins->sreg2 = ins_iconst->dreg;
6191                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6192                                 MONO_ADD_INS (cfg->cbb, ins);
6193                         }
6194                 } else if (strcmp (cmethod->name, "Decrement") == 0 && fsig->param_count == 1) {
6195                         MonoInst *ins_iconst;
6196                         guint32 opcode = 0;
6197
6198                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6199                                 opcode = OP_ATOMIC_ADD_I4;
6200                                 cfg->has_atomic_add_i4 = TRUE;
6201                         }
6202 #if SIZEOF_REGISTER == 8
6203                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6204                                 opcode = OP_ATOMIC_ADD_I8;
6205 #endif
6206                         if (opcode) {
6207                                 if (!mono_arch_opcode_supported (opcode))
6208                                         return NULL;
6209                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
6210                                 ins_iconst->inst_c0 = -1;
6211                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
6212                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
6213
6214                                 MONO_INST_NEW (cfg, ins, opcode);
6215                                 ins->dreg = mono_alloc_ireg (cfg);
6216                                 ins->inst_basereg = args [0]->dreg;
6217                                 ins->inst_offset = 0;
6218                                 ins->sreg2 = ins_iconst->dreg;
6219                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6220                                 MONO_ADD_INS (cfg->cbb, ins);
6221                         }
6222                 } else if (strcmp (cmethod->name, "Add") == 0 && fsig->param_count == 2) {
6223                         guint32 opcode = 0;
6224
6225                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6226                                 opcode = OP_ATOMIC_ADD_I4;
6227                                 cfg->has_atomic_add_i4 = TRUE;
6228                         }
6229 #if SIZEOF_REGISTER == 8
6230                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6231                                 opcode = OP_ATOMIC_ADD_I8;
6232 #endif
6233                         if (opcode) {
6234                                 if (!mono_arch_opcode_supported (opcode))
6235                                         return NULL;
6236                                 MONO_INST_NEW (cfg, ins, opcode);
6237                                 ins->dreg = mono_alloc_ireg (cfg);
6238                                 ins->inst_basereg = args [0]->dreg;
6239                                 ins->inst_offset = 0;
6240                                 ins->sreg2 = args [1]->dreg;
6241                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6242                                 MONO_ADD_INS (cfg->cbb, ins);
6243                         }
6244                 }
6245                 else if (strcmp (cmethod->name, "Exchange") == 0 && fsig->param_count == 2) {
6246                         MonoInst *f2i = NULL, *i2f;
6247                         guint32 opcode, f2i_opcode, i2f_opcode;
6248                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6249                         gboolean is_float = fsig->params [0]->type == MONO_TYPE_R4 || fsig->params [0]->type == MONO_TYPE_R8;
6250
6251                         if (fsig->params [0]->type == MONO_TYPE_I4 ||
6252                             fsig->params [0]->type == MONO_TYPE_R4) {
6253                                 opcode = OP_ATOMIC_EXCHANGE_I4;
6254                                 f2i_opcode = OP_MOVE_F_TO_I4;
6255                                 i2f_opcode = OP_MOVE_I4_TO_F;
6256                                 cfg->has_atomic_exchange_i4 = TRUE;
6257                         }
6258 #if SIZEOF_REGISTER == 8
6259                         else if (is_ref ||
6260                                  fsig->params [0]->type == MONO_TYPE_I8 ||
6261                                  fsig->params [0]->type == MONO_TYPE_R8 ||
6262                                  fsig->params [0]->type == MONO_TYPE_I) {
6263                                 opcode = OP_ATOMIC_EXCHANGE_I8;
6264                                 f2i_opcode = OP_MOVE_F_TO_I8;
6265                                 i2f_opcode = OP_MOVE_I8_TO_F;
6266                         }
6267 #else
6268                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I) {
6269                                 opcode = OP_ATOMIC_EXCHANGE_I4;
6270                                 cfg->has_atomic_exchange_i4 = TRUE;
6271                         }
6272 #endif
6273                         else
6274                                 return NULL;
6275
6276                         if (!mono_arch_opcode_supported (opcode))
6277                                 return NULL;
6278
6279                         if (is_float) {
6280                                 /* TODO: Decompose these opcodes instead of bailing here. */
6281                                 if (COMPILE_SOFT_FLOAT (cfg))
6282                                         return NULL;
6283
6284                                 MONO_INST_NEW (cfg, f2i, f2i_opcode);
6285                                 f2i->dreg = mono_alloc_ireg (cfg);
6286                                 f2i->sreg1 = args [1]->dreg;
6287                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6288                                         f2i->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6289                                 MONO_ADD_INS (cfg->cbb, f2i);
6290                         }
6291
6292                         MONO_INST_NEW (cfg, ins, opcode);
6293                         ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : mono_alloc_ireg (cfg);
6294                         ins->inst_basereg = args [0]->dreg;
6295                         ins->inst_offset = 0;
6296                         ins->sreg2 = is_float ? f2i->dreg : args [1]->dreg;
6297                         MONO_ADD_INS (cfg->cbb, ins);
6298
6299                         switch (fsig->params [0]->type) {
6300                         case MONO_TYPE_I4:
6301                                 ins->type = STACK_I4;
6302                                 break;
6303                         case MONO_TYPE_I8:
6304                                 ins->type = STACK_I8;
6305                                 break;
6306                         case MONO_TYPE_I:
6307 #if SIZEOF_REGISTER == 8
6308                                 ins->type = STACK_I8;
6309 #else
6310                                 ins->type = STACK_I4;
6311 #endif
6312                                 break;
6313                         case MONO_TYPE_R4:
6314                         case MONO_TYPE_R8:
6315                                 ins->type = STACK_R8;
6316                                 break;
6317                         default:
6318                                 g_assert (mini_type_is_reference (fsig->params [0]));
6319                                 ins->type = STACK_OBJ;
6320                                 break;
6321                         }
6322
6323                         if (is_float) {
6324                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
6325                                 i2f->dreg = mono_alloc_freg (cfg);
6326                                 i2f->sreg1 = ins->dreg;
6327                                 i2f->type = STACK_R8;
6328                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
6329                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6330                                 MONO_ADD_INS (cfg->cbb, i2f);
6331
6332                                 ins = i2f;
6333                         }
6334
6335                         if (cfg->gen_write_barriers && is_ref)
6336                                 emit_write_barrier (cfg, args [0], args [1]);
6337                 }
6338                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 3) {
6339                         MonoInst *f2i_new = NULL, *f2i_cmp = NULL, *i2f;
6340                         guint32 opcode, f2i_opcode, i2f_opcode;
6341                         gboolean is_ref = mini_type_is_reference (fsig->params [1]);
6342                         gboolean is_float = fsig->params [1]->type == MONO_TYPE_R4 || fsig->params [1]->type == MONO_TYPE_R8;
6343
6344                         if (fsig->params [1]->type == MONO_TYPE_I4 ||
6345                             fsig->params [1]->type == MONO_TYPE_R4) {
6346                                 opcode = OP_ATOMIC_CAS_I4;
6347                                 f2i_opcode = OP_MOVE_F_TO_I4;
6348                                 i2f_opcode = OP_MOVE_I4_TO_F;
6349                                 cfg->has_atomic_cas_i4 = TRUE;
6350                         }
6351 #if SIZEOF_REGISTER == 8
6352                         else if (is_ref ||
6353                                  fsig->params [1]->type == MONO_TYPE_I8 ||
6354                                  fsig->params [1]->type == MONO_TYPE_R8 ||
6355                                  fsig->params [1]->type == MONO_TYPE_I) {
6356                                 opcode = OP_ATOMIC_CAS_I8;
6357                                 f2i_opcode = OP_MOVE_F_TO_I8;
6358                                 i2f_opcode = OP_MOVE_I8_TO_F;
6359                         }
6360 #else
6361                         else if (is_ref || fsig->params [1]->type == MONO_TYPE_I) {
6362                                 opcode = OP_ATOMIC_CAS_I4;
6363                                 cfg->has_atomic_cas_i4 = TRUE;
6364                         }
6365 #endif
6366                         else
6367                                 return NULL;
6368
6369                         if (!mono_arch_opcode_supported (opcode))
6370                                 return NULL;
6371
6372                         if (is_float) {
6373                                 /* TODO: Decompose these opcodes instead of bailing here. */
6374                                 if (COMPILE_SOFT_FLOAT (cfg))
6375                                         return NULL;
6376
6377                                 MONO_INST_NEW (cfg, f2i_new, f2i_opcode);
6378                                 f2i_new->dreg = mono_alloc_ireg (cfg);
6379                                 f2i_new->sreg1 = args [1]->dreg;
6380                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6381                                         f2i_new->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6382                                 MONO_ADD_INS (cfg->cbb, f2i_new);
6383
6384                                 MONO_INST_NEW (cfg, f2i_cmp, f2i_opcode);
6385                                 f2i_cmp->dreg = mono_alloc_ireg (cfg);
6386                                 f2i_cmp->sreg1 = args [2]->dreg;
6387                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6388                                         f2i_cmp->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6389                                 MONO_ADD_INS (cfg->cbb, f2i_cmp);
6390                         }
6391
6392                         MONO_INST_NEW (cfg, ins, opcode);
6393                         ins->dreg = is_ref ? alloc_ireg_ref (cfg) : alloc_ireg (cfg);
6394                         ins->sreg1 = args [0]->dreg;
6395                         ins->sreg2 = is_float ? f2i_new->dreg : args [1]->dreg;
6396                         ins->sreg3 = is_float ? f2i_cmp->dreg : args [2]->dreg;
6397                         MONO_ADD_INS (cfg->cbb, ins);
6398
6399                         switch (fsig->params [1]->type) {
6400                         case MONO_TYPE_I4:
6401                                 ins->type = STACK_I4;
6402                                 break;
6403                         case MONO_TYPE_I8:
6404                                 ins->type = STACK_I8;
6405                                 break;
6406                         case MONO_TYPE_I:
6407 #if SIZEOF_REGISTER == 8
6408                                 ins->type = STACK_I8;
6409 #else
6410                                 ins->type = STACK_I4;
6411 #endif
6412                                 break;
6413                         case MONO_TYPE_R4:
6414                                 ins->type = cfg->r4_stack_type;
6415                                 break;
6416                         case MONO_TYPE_R8:
6417                                 ins->type = STACK_R8;
6418                                 break;
6419                         default:
6420                                 g_assert (mini_type_is_reference (fsig->params [1]));
6421                                 ins->type = STACK_OBJ;
6422                                 break;
6423                         }
6424
6425                         if (is_float) {
6426                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
6427                                 i2f->dreg = mono_alloc_freg (cfg);
6428                                 i2f->sreg1 = ins->dreg;
6429                                 i2f->type = STACK_R8;
6430                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
6431                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6432                                 MONO_ADD_INS (cfg->cbb, i2f);
6433
6434                                 ins = i2f;
6435                         }
6436
6437                         if (cfg->gen_write_barriers && is_ref)
6438                                 emit_write_barrier (cfg, args [0], args [1]);
6439                 }
6440                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 4 &&
6441                          fsig->params [1]->type == MONO_TYPE_I4) {
6442                         MonoInst *cmp, *ceq;
6443
6444                         if (!mono_arch_opcode_supported (OP_ATOMIC_CAS_I4))
6445                                 return NULL;
6446
6447                         /* int32 r = CAS (location, value, comparand); */
6448                         MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I4);
6449                         ins->dreg = alloc_ireg (cfg);
6450                         ins->sreg1 = args [0]->dreg;
6451                         ins->sreg2 = args [1]->dreg;
6452                         ins->sreg3 = args [2]->dreg;
6453                         ins->type = STACK_I4;
6454                         MONO_ADD_INS (cfg->cbb, ins);
6455
6456                         /* bool result = r == comparand; */
6457                         MONO_INST_NEW (cfg, cmp, OP_ICOMPARE);
6458                         cmp->sreg1 = ins->dreg;
6459                         cmp->sreg2 = args [2]->dreg;
6460                         cmp->type = STACK_I4;
6461                         MONO_ADD_INS (cfg->cbb, cmp);
6462
6463                         MONO_INST_NEW (cfg, ceq, OP_ICEQ);
6464                         ceq->dreg = alloc_ireg (cfg);
6465                         ceq->type = STACK_I4;
6466                         MONO_ADD_INS (cfg->cbb, ceq);
6467
6468                         /* *success = result; */
6469                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, args [3]->dreg, 0, ceq->dreg);
6470
6471                         cfg->has_atomic_cas_i4 = TRUE;
6472                 }
6473                 else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0)
6474                         ins = emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6475
6476                 if (ins)
6477                         return ins;
6478         } else if (cmethod->klass->image == mono_defaults.corlib &&
6479                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
6480                            (strcmp (cmethod->klass->name, "Volatile") == 0)) {
6481                 ins = NULL;
6482
6483                 if (!strcmp (cmethod->name, "Read") && fsig->param_count == 1) {
6484                         guint32 opcode = 0;
6485                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6486                         gboolean is_float = fsig->params [0]->type == MONO_TYPE_R4 || fsig->params [0]->type == MONO_TYPE_R8;
6487
6488                         if (fsig->params [0]->type == MONO_TYPE_I1)
6489                                 opcode = OP_ATOMIC_LOAD_I1;
6490                         else if (fsig->params [0]->type == MONO_TYPE_U1 || fsig->params [0]->type == MONO_TYPE_BOOLEAN)
6491                                 opcode = OP_ATOMIC_LOAD_U1;
6492                         else if (fsig->params [0]->type == MONO_TYPE_I2)
6493                                 opcode = OP_ATOMIC_LOAD_I2;
6494                         else if (fsig->params [0]->type == MONO_TYPE_U2)
6495                                 opcode = OP_ATOMIC_LOAD_U2;
6496                         else if (fsig->params [0]->type == MONO_TYPE_I4)
6497                                 opcode = OP_ATOMIC_LOAD_I4;
6498                         else if (fsig->params [0]->type == MONO_TYPE_U4)
6499                                 opcode = OP_ATOMIC_LOAD_U4;
6500                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6501                                 opcode = OP_ATOMIC_LOAD_R4;
6502                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6503                                 opcode = OP_ATOMIC_LOAD_R8;
6504 #if SIZEOF_REGISTER == 8
6505                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_I)
6506                                 opcode = OP_ATOMIC_LOAD_I8;
6507                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_U8 || fsig->params [0]->type == MONO_TYPE_U)
6508                                 opcode = OP_ATOMIC_LOAD_U8;
6509 #else
6510                         else if (fsig->params [0]->type == MONO_TYPE_I)
6511                                 opcode = OP_ATOMIC_LOAD_I4;
6512                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_U)
6513                                 opcode = OP_ATOMIC_LOAD_U4;
6514 #endif
6515
6516                         if (opcode) {
6517                                 if (!mono_arch_opcode_supported (opcode))
6518                                         return NULL;
6519
6520                                 MONO_INST_NEW (cfg, ins, opcode);
6521                                 ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : (is_float ? mono_alloc_freg (cfg) : mono_alloc_ireg (cfg));
6522                                 ins->sreg1 = args [0]->dreg;
6523                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_ACQ;
6524                                 MONO_ADD_INS (cfg->cbb, ins);
6525
6526                                 switch (fsig->params [0]->type) {
6527                                 case MONO_TYPE_BOOLEAN:
6528                                 case MONO_TYPE_I1:
6529                                 case MONO_TYPE_U1:
6530                                 case MONO_TYPE_I2:
6531                                 case MONO_TYPE_U2:
6532                                 case MONO_TYPE_I4:
6533                                 case MONO_TYPE_U4:
6534                                         ins->type = STACK_I4;
6535                                         break;
6536                                 case MONO_TYPE_I8:
6537                                 case MONO_TYPE_U8:
6538                                         ins->type = STACK_I8;
6539                                         break;
6540                                 case MONO_TYPE_I:
6541                                 case MONO_TYPE_U:
6542 #if SIZEOF_REGISTER == 8
6543                                         ins->type = STACK_I8;
6544 #else
6545                                         ins->type = STACK_I4;
6546 #endif
6547                                         break;
6548                                 case MONO_TYPE_R4:
6549                                         ins->type = cfg->r4_stack_type;
6550                                         break;
6551                                 case MONO_TYPE_R8:
6552                                         ins->type = STACK_R8;
6553                                         break;
6554                                 default:
6555                                         g_assert (mini_type_is_reference (fsig->params [0]));
6556                                         ins->type = STACK_OBJ;
6557                                         break;
6558                                 }
6559                         }
6560                 }
6561
6562                 if (!strcmp (cmethod->name, "Write") && fsig->param_count == 2) {
6563                         guint32 opcode = 0;
6564                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6565
6566                         if (fsig->params [0]->type == MONO_TYPE_I1)
6567                                 opcode = OP_ATOMIC_STORE_I1;
6568                         else if (fsig->params [0]->type == MONO_TYPE_U1 || fsig->params [0]->type == MONO_TYPE_BOOLEAN)
6569                                 opcode = OP_ATOMIC_STORE_U1;
6570                         else if (fsig->params [0]->type == MONO_TYPE_I2)
6571                                 opcode = OP_ATOMIC_STORE_I2;
6572                         else if (fsig->params [0]->type == MONO_TYPE_U2)
6573                                 opcode = OP_ATOMIC_STORE_U2;
6574                         else if (fsig->params [0]->type == MONO_TYPE_I4)
6575                                 opcode = OP_ATOMIC_STORE_I4;
6576                         else if (fsig->params [0]->type == MONO_TYPE_U4)
6577                                 opcode = OP_ATOMIC_STORE_U4;
6578                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6579                                 opcode = OP_ATOMIC_STORE_R4;
6580                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6581                                 opcode = OP_ATOMIC_STORE_R8;
6582 #if SIZEOF_REGISTER == 8
6583                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_I)
6584                                 opcode = OP_ATOMIC_STORE_I8;
6585                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_U8 || fsig->params [0]->type == MONO_TYPE_U)
6586                                 opcode = OP_ATOMIC_STORE_U8;
6587 #else
6588                         else if (fsig->params [0]->type == MONO_TYPE_I)
6589                                 opcode = OP_ATOMIC_STORE_I4;
6590                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_U)
6591                                 opcode = OP_ATOMIC_STORE_U4;
6592 #endif
6593
6594                         if (opcode) {
6595                                 if (!mono_arch_opcode_supported (opcode))
6596                                         return NULL;
6597
6598                                 MONO_INST_NEW (cfg, ins, opcode);
6599                                 ins->dreg = args [0]->dreg;
6600                                 ins->sreg1 = args [1]->dreg;
6601                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_REL;
6602                                 MONO_ADD_INS (cfg->cbb, ins);
6603
6604                                 if (cfg->gen_write_barriers && is_ref)
6605                                         emit_write_barrier (cfg, args [0], args [1]);
6606                         }
6607                 }
6608
6609                 if (ins)
6610                         return ins;
6611         } else if (cmethod->klass->image == mono_defaults.corlib &&
6612                            (strcmp (cmethod->klass->name_space, "System.Diagnostics") == 0) &&
6613                            (strcmp (cmethod->klass->name, "Debugger") == 0)) {
6614                 if (!strcmp (cmethod->name, "Break") && fsig->param_count == 0) {
6615                         if (should_insert_brekpoint (cfg->method)) {
6616                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
6617                         } else {
6618                                 MONO_INST_NEW (cfg, ins, OP_NOP);
6619                                 MONO_ADD_INS (cfg->cbb, ins);
6620                         }
6621                         return ins;
6622                 }
6623         } else if (cmethod->klass->image == mono_defaults.corlib &&
6624                    (strcmp (cmethod->klass->name_space, "System") == 0) &&
6625                    (strcmp (cmethod->klass->name, "Environment") == 0)) {
6626                 if (!strcmp (cmethod->name, "get_IsRunningOnWindows") && fsig->param_count == 0) {
6627 #ifdef TARGET_WIN32
6628                         EMIT_NEW_ICONST (cfg, ins, 1);
6629 #else
6630                         EMIT_NEW_ICONST (cfg, ins, 0);
6631 #endif
6632                 }
6633         } else if (cmethod->klass == mono_defaults.math_class) {
6634                 /* 
6635                  * There is general branchless code for Min/Max, but it does not work for 
6636                  * all inputs:
6637                  * http://everything2.com/?node_id=1051618
6638                  */
6639         } else if (((!strcmp (cmethod->klass->image->assembly->aname.name, "MonoMac") ||
6640                     !strcmp (cmethod->klass->image->assembly->aname.name, "monotouch")) &&
6641                                 !strcmp (cmethod->klass->name_space, "XamCore.ObjCRuntime") &&
6642                                 !strcmp (cmethod->klass->name, "Selector")) ||
6643                            (!strcmp (cmethod->klass->image->assembly->aname.name, "Xamarin.iOS") &&
6644                                 !strcmp (cmethod->klass->name_space, "ObjCRuntime") &&
6645                                 !strcmp (cmethod->klass->name, "Selector"))
6646                            ) {
6647 #ifdef MONO_ARCH_HAVE_OBJC_GET_SELECTOR
6648                 if (!strcmp (cmethod->name, "GetHandle") && fsig->param_count == 1 &&
6649                     (args [0]->opcode == OP_GOT_ENTRY || args [0]->opcode == OP_AOTCONST) &&
6650                     cfg->compile_aot) {
6651                         MonoInst *pi;
6652                         MonoJumpInfoToken *ji;
6653                         MonoString *s;
6654
6655                         cfg->disable_llvm = TRUE;
6656
6657                         if (args [0]->opcode == OP_GOT_ENTRY) {
6658                                 pi = args [0]->inst_p1;
6659                                 g_assert (pi->opcode == OP_PATCH_INFO);
6660                                 g_assert (GPOINTER_TO_INT (pi->inst_p1) == MONO_PATCH_INFO_LDSTR);
6661                                 ji = pi->inst_p0;
6662                         } else {
6663                                 g_assert (GPOINTER_TO_INT (args [0]->inst_p1) == MONO_PATCH_INFO_LDSTR);
6664                                 ji = args [0]->inst_p0;
6665                         }
6666
6667                         NULLIFY_INS (args [0]);
6668
6669                         // FIXME: Ugly
6670                         s = mono_ldstr (cfg->domain, ji->image, mono_metadata_token_index (ji->token));
6671                         MONO_INST_NEW (cfg, ins, OP_OBJC_GET_SELECTOR);
6672                         ins->dreg = mono_alloc_ireg (cfg);
6673                         // FIXME: Leaks
6674                         ins->inst_p0 = mono_string_to_utf8 (s);
6675                         MONO_ADD_INS (cfg->cbb, ins);
6676                         return ins;
6677                 }
6678 #endif
6679         }
6680
6681 #ifdef MONO_ARCH_SIMD_INTRINSICS
6682         if (cfg->opt & MONO_OPT_SIMD) {
6683                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
6684                 if (ins)
6685                         return ins;
6686         }
6687 #endif
6688
6689         ins = mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
6690         if (ins)
6691                 return ins;
6692
6693         if (COMPILE_LLVM (cfg)) {
6694                 ins = llvm_emit_inst_for_method (cfg, cmethod, fsig, args);
6695                 if (ins)
6696                         return ins;
6697         }
6698
6699         return mono_arch_emit_inst_for_method (cfg, cmethod, fsig, args);
6700 }
6701
6702 /*
6703  * This entry point could be used later for arbitrary method
6704  * redirection.
6705  */
6706 inline static MonoInst*
6707 mini_redirect_call (MonoCompile *cfg, MonoMethod *method,  
6708                                         MonoMethodSignature *signature, MonoInst **args, MonoInst *this_ins)
6709 {
6710         if (method->klass == mono_defaults.string_class) {
6711                 /* managed string allocation support */
6712                 if (strcmp (method->name, "InternalAllocateStr") == 0 && !(mono_profiler_events & MONO_PROFILE_ALLOCATIONS) && !(cfg->opt & MONO_OPT_SHARED)) {
6713                         MonoInst *iargs [2];
6714                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
6715                         MonoMethod *managed_alloc = NULL;
6716
6717                         g_assert (vtable); /*Should not fail since it System.String*/
6718 #ifndef MONO_CROSS_COMPILE
6719                         managed_alloc = mono_gc_get_managed_allocator (method->klass, FALSE, FALSE);
6720 #endif
6721                         if (!managed_alloc)
6722                                 return NULL;
6723                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
6724                         iargs [1] = args [0];
6725                         return mono_emit_method_call (cfg, managed_alloc, iargs, this_ins);
6726                 }
6727         }
6728         return NULL;
6729 }
6730
6731 static void
6732 mono_save_args (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **sp)
6733 {
6734         MonoInst *store, *temp;
6735         int i;
6736
6737         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
6738                 MonoType *argtype = (sig->hasthis && (i == 0)) ? type_from_stack_type (*sp) : sig->params [i - sig->hasthis];
6739
6740                 /*
6741                  * FIXME: We should use *args++ = sp [0], but that would mean the arg
6742                  * would be different than the MonoInst's used to represent arguments, and
6743                  * the ldelema implementation can't deal with that.
6744                  * Solution: When ldelema is used on an inline argument, create a var for 
6745                  * it, emit ldelema on that var, and emit the saving code below in
6746                  * inline_method () if needed.
6747                  */
6748                 temp = mono_compile_create_var (cfg, argtype, OP_LOCAL);
6749                 cfg->args [i] = temp;
6750                 /* This uses cfg->args [i] which is set by the preceeding line */
6751                 EMIT_NEW_ARGSTORE (cfg, store, i, *sp);
6752                 store->cil_code = sp [0]->cil_code;
6753                 sp++;
6754         }
6755 }
6756
6757 #define MONO_INLINE_CALLED_LIMITED_METHODS 1
6758 #define MONO_INLINE_CALLER_LIMITED_METHODS 1
6759
6760 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
6761 static gboolean
6762 check_inline_called_method_name_limit (MonoMethod *called_method)
6763 {
6764         int strncmp_result;
6765         static const char *limit = NULL;
6766         
6767         if (limit == NULL) {
6768                 const char *limit_string = g_getenv ("MONO_INLINE_CALLED_METHOD_NAME_LIMIT");
6769
6770                 if (limit_string != NULL)
6771                         limit = limit_string;
6772                 else
6773                         limit = "";
6774         }
6775
6776         if (limit [0] != '\0') {
6777                 char *called_method_name = mono_method_full_name (called_method, TRUE);
6778
6779                 strncmp_result = strncmp (called_method_name, limit, strlen (limit));
6780                 g_free (called_method_name);
6781         
6782                 //return (strncmp_result <= 0);
6783                 return (strncmp_result == 0);
6784         } else {
6785                 return TRUE;
6786         }
6787 }
6788 #endif
6789
6790 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
6791 static gboolean
6792 check_inline_caller_method_name_limit (MonoMethod *caller_method)
6793 {
6794         int strncmp_result;
6795         static const char *limit = NULL;
6796         
6797         if (limit == NULL) {
6798                 const char *limit_string = g_getenv ("MONO_INLINE_CALLER_METHOD_NAME_LIMIT");
6799                 if (limit_string != NULL) {
6800                         limit = limit_string;
6801                 } else {
6802                         limit = "";
6803                 }
6804         }
6805
6806         if (limit [0] != '\0') {
6807                 char *caller_method_name = mono_method_full_name (caller_method, TRUE);
6808
6809                 strncmp_result = strncmp (caller_method_name, limit, strlen (limit));
6810                 g_free (caller_method_name);
6811         
6812                 //return (strncmp_result <= 0);
6813                 return (strncmp_result == 0);
6814         } else {
6815                 return TRUE;
6816         }
6817 }
6818 #endif
6819
6820 static void
6821 emit_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
6822 {
6823         static double r8_0 = 0.0;
6824         static float r4_0 = 0.0;
6825         MonoInst *ins;
6826         int t;
6827
6828         rtype = mini_get_underlying_type (rtype);
6829         t = rtype->type;
6830
6831         if (rtype->byref) {
6832                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
6833         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
6834                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
6835         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
6836                 MONO_EMIT_NEW_I8CONST (cfg, dreg, 0);
6837         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
6838                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
6839                 ins->type = STACK_R4;
6840                 ins->inst_p0 = (void*)&r4_0;
6841                 ins->dreg = dreg;
6842                 MONO_ADD_INS (cfg->cbb, ins);
6843         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
6844                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
6845                 ins->type = STACK_R8;
6846                 ins->inst_p0 = (void*)&r8_0;
6847                 ins->dreg = dreg;
6848                 MONO_ADD_INS (cfg->cbb, ins);
6849         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
6850                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
6851                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
6852         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (rtype)) {
6853                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
6854         } else {
6855                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
6856         }
6857 }
6858
6859 static void
6860 emit_dummy_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
6861 {
6862         int t;
6863
6864         rtype = mini_get_underlying_type (rtype);
6865         t = rtype->type;
6866
6867         if (rtype->byref) {
6868                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_PCONST);
6869         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
6870                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_ICONST);
6871         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
6872                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_I8CONST);
6873         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
6874                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R4CONST);
6875         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
6876                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R8CONST);
6877         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
6878                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
6879                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
6880         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (rtype)) {
6881                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
6882         } else {
6883                 emit_init_rvar (cfg, dreg, rtype);
6884         }
6885 }
6886
6887 /* If INIT is FALSE, emit dummy initialization statements to keep the IR valid */
6888 static void
6889 emit_init_local (MonoCompile *cfg, int local, MonoType *type, gboolean init)
6890 {
6891         MonoInst *var = cfg->locals [local];
6892         if (COMPILE_SOFT_FLOAT (cfg)) {
6893                 MonoInst *store;
6894                 int reg = alloc_dreg (cfg, var->type);
6895                 emit_init_rvar (cfg, reg, type);
6896                 EMIT_NEW_LOCSTORE (cfg, store, local, cfg->cbb->last_ins);
6897         } else {
6898                 if (init)
6899                         emit_init_rvar (cfg, var->dreg, type);
6900                 else
6901                         emit_dummy_init_rvar (cfg, var->dreg, type);
6902         }
6903 }
6904
6905 /*
6906  * inline_method:
6907  *
6908  *   Return the cost of inlining CMETHOD.
6909  */
6910 static int
6911 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
6912                            guchar *ip, guint real_offset, gboolean inline_always)
6913 {
6914         MonoInst *ins, *rvar = NULL;
6915         MonoMethodHeader *cheader;
6916         MonoBasicBlock *ebblock, *sbblock;
6917         int i, costs;
6918         MonoMethod *prev_inlined_method;
6919         MonoInst **prev_locals, **prev_args;
6920         MonoType **prev_arg_types;
6921         guint prev_real_offset;
6922         GHashTable *prev_cbb_hash;
6923         MonoBasicBlock **prev_cil_offset_to_bb;
6924         MonoBasicBlock *prev_cbb;
6925         unsigned char* prev_cil_start;
6926         guint32 prev_cil_offset_to_bb_len;
6927         MonoMethod *prev_current_method;
6928         MonoGenericContext *prev_generic_context;
6929         gboolean ret_var_set, prev_ret_var_set, prev_disable_inline, virtual = FALSE;
6930
6931         g_assert (cfg->exception_type == MONO_EXCEPTION_NONE);
6932
6933 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
6934         if ((! inline_always) && ! check_inline_called_method_name_limit (cmethod))
6935                 return 0;
6936 #endif
6937 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
6938         if ((! inline_always) && ! check_inline_caller_method_name_limit (cfg->method))
6939                 return 0;
6940 #endif
6941
6942         if (!fsig)
6943                 fsig = mono_method_signature (cmethod);
6944
6945         if (cfg->verbose_level > 2)
6946                 printf ("INLINE START %p %s -> %s\n", cmethod,  mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
6947
6948         if (!cmethod->inline_info) {
6949                 cfg->stat_inlineable_methods++;
6950                 cmethod->inline_info = 1;
6951         }
6952
6953         /* allocate local variables */
6954         cheader = mono_method_get_header (cmethod);
6955
6956         if (cheader == NULL || mono_loader_get_last_error ()) {
6957                 MonoLoaderError *error = mono_loader_get_last_error ();
6958
6959                 if (cheader)
6960                         mono_metadata_free_mh (cheader);
6961                 if (inline_always && error)
6962                         mono_cfg_set_exception (cfg, error->exception_type);
6963
6964                 mono_loader_clear_error ();
6965                 return 0;
6966         }
6967
6968         /*Must verify before creating locals as it can cause the JIT to assert.*/
6969         if (mono_compile_is_broken (cfg, cmethod, FALSE)) {
6970                 mono_metadata_free_mh (cheader);
6971                 return 0;
6972         }
6973
6974         /* allocate space to store the return value */
6975         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
6976                 rvar = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
6977         }
6978
6979         prev_locals = cfg->locals;
6980         cfg->locals = mono_mempool_alloc0 (cfg->mempool, cheader->num_locals * sizeof (MonoInst*));     
6981         for (i = 0; i < cheader->num_locals; ++i)
6982                 cfg->locals [i] = mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
6983
6984         /* allocate start and end blocks */
6985         /* This is needed so if the inline is aborted, we can clean up */
6986         NEW_BBLOCK (cfg, sbblock);
6987         sbblock->real_offset = real_offset;
6988
6989         NEW_BBLOCK (cfg, ebblock);
6990         ebblock->block_num = cfg->num_bblocks++;
6991         ebblock->real_offset = real_offset;
6992
6993         prev_args = cfg->args;
6994         prev_arg_types = cfg->arg_types;
6995         prev_inlined_method = cfg->inlined_method;
6996         cfg->inlined_method = cmethod;
6997         cfg->ret_var_set = FALSE;
6998         cfg->inline_depth ++;
6999         prev_real_offset = cfg->real_offset;
7000         prev_cbb_hash = cfg->cbb_hash;
7001         prev_cil_offset_to_bb = cfg->cil_offset_to_bb;
7002         prev_cil_offset_to_bb_len = cfg->cil_offset_to_bb_len;
7003         prev_cil_start = cfg->cil_start;
7004         prev_cbb = cfg->cbb;
7005         prev_current_method = cfg->current_method;
7006         prev_generic_context = cfg->generic_context;
7007         prev_ret_var_set = cfg->ret_var_set;
7008         prev_disable_inline = cfg->disable_inline;
7009
7010         if (ip && *ip == CEE_CALLVIRT && !(cmethod->flags & METHOD_ATTRIBUTE_STATIC))
7011                 virtual = TRUE;
7012
7013         costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, rvar, sp, real_offset, virtual);
7014
7015         ret_var_set = cfg->ret_var_set;
7016
7017         cfg->inlined_method = prev_inlined_method;
7018         cfg->real_offset = prev_real_offset;
7019         cfg->cbb_hash = prev_cbb_hash;
7020         cfg->cil_offset_to_bb = prev_cil_offset_to_bb;
7021         cfg->cil_offset_to_bb_len = prev_cil_offset_to_bb_len;
7022         cfg->cil_start = prev_cil_start;
7023         cfg->locals = prev_locals;
7024         cfg->args = prev_args;
7025         cfg->arg_types = prev_arg_types;
7026         cfg->current_method = prev_current_method;
7027         cfg->generic_context = prev_generic_context;
7028         cfg->ret_var_set = prev_ret_var_set;
7029         cfg->disable_inline = prev_disable_inline;
7030         cfg->inline_depth --;
7031
7032         if ((costs >= 0 && costs < 60) || inline_always || (costs >= 0 && (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))) {
7033                 if (cfg->verbose_level > 2)
7034                         printf ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
7035                 
7036                 cfg->stat_inlined_methods++;
7037
7038                 /* always add some code to avoid block split failures */
7039                 MONO_INST_NEW (cfg, ins, OP_NOP);
7040                 MONO_ADD_INS (prev_cbb, ins);
7041
7042                 prev_cbb->next_bb = sbblock;
7043                 link_bblock (cfg, prev_cbb, sbblock);
7044
7045                 /* 
7046                  * Get rid of the begin and end bblocks if possible to aid local
7047                  * optimizations.
7048                  */
7049                 mono_merge_basic_blocks (cfg, prev_cbb, sbblock);
7050
7051                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] != ebblock))
7052                         mono_merge_basic_blocks (cfg, prev_cbb, prev_cbb->out_bb [0]);
7053
7054                 if ((ebblock->in_count == 1) && ebblock->in_bb [0]->out_count == 1) {
7055                         MonoBasicBlock *prev = ebblock->in_bb [0];
7056                         mono_merge_basic_blocks (cfg, prev, ebblock);
7057                         cfg->cbb = prev;
7058                         if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] == prev)) {
7059                                 mono_merge_basic_blocks (cfg, prev_cbb, prev);
7060                                 cfg->cbb = prev_cbb;
7061                         }
7062                 } else {
7063                         /* 
7064                          * Its possible that the rvar is set in some prev bblock, but not in others.
7065                          * (#1835).
7066                          */
7067                         if (rvar) {
7068                                 MonoBasicBlock *bb;
7069
7070                                 for (i = 0; i < ebblock->in_count; ++i) {
7071                                         bb = ebblock->in_bb [i];
7072
7073                                         if (bb->last_ins && bb->last_ins->opcode == OP_NOT_REACHED) {
7074                                                 cfg->cbb = bb;
7075
7076                                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
7077                                         }
7078                                 }
7079                         }
7080
7081                         cfg->cbb = ebblock;
7082                 }
7083
7084                 if (rvar) {
7085                         /*
7086                          * If the inlined method contains only a throw, then the ret var is not 
7087                          * set, so set it to a dummy value.
7088                          */
7089                         if (!ret_var_set)
7090                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
7091
7092                         EMIT_NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
7093                         *sp++ = ins;
7094                 }
7095                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
7096                 return costs + 1;
7097         } else {
7098                 if (cfg->verbose_level > 2)
7099                         printf ("INLINE ABORTED %s (cost %d)\n", mono_method_full_name (cmethod, TRUE), costs);
7100                 cfg->exception_type = MONO_EXCEPTION_NONE;
7101                 mono_loader_clear_error ();
7102
7103                 /* This gets rid of the newly added bblocks */
7104                 cfg->cbb = prev_cbb;
7105         }
7106         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
7107         return 0;
7108 }
7109
7110 /*
7111  * Some of these comments may well be out-of-date.
7112  * Design decisions: we do a single pass over the IL code (and we do bblock 
7113  * splitting/merging in the few cases when it's required: a back jump to an IL
7114  * address that was not already seen as bblock starting point).
7115  * Code is validated as we go (full verification is still better left to metadata/verify.c).
7116  * Complex operations are decomposed in simpler ones right away. We need to let the 
7117  * arch-specific code peek and poke inside this process somehow (except when the 
7118  * optimizations can take advantage of the full semantic info of coarse opcodes).
7119  * All the opcodes of the form opcode.s are 'normalized' to opcode.
7120  * MonoInst->opcode initially is the IL opcode or some simplification of that 
7121  * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific 
7122  * opcode with value bigger than OP_LAST.
7123  * At this point the IR can be handed over to an interpreter, a dumb code generator
7124  * or to the optimizing code generator that will translate it to SSA form.
7125  *
7126  * Profiling directed optimizations.
7127  * We may compile by default with few or no optimizations and instrument the code
7128  * or the user may indicate what methods to optimize the most either in a config file
7129  * or through repeated runs where the compiler applies offline the optimizations to 
7130  * each method and then decides if it was worth it.
7131  */
7132
7133 #define CHECK_TYPE(ins) if (!(ins)->type) UNVERIFIED
7134 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) UNVERIFIED
7135 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) UNVERIFIED
7136 #define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) UNVERIFIED
7137 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
7138 #define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
7139 #define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
7140 #define CHECK_TYPELOAD(klass) if (!(klass) || (klass)->exception_type) TYPE_LOAD_ERROR ((klass))
7141
7142 /* offset from br.s -> br like opcodes */
7143 #define BIG_BRANCH_OFFSET 13
7144
7145 static gboolean
7146 ip_in_bb (MonoCompile *cfg, MonoBasicBlock *bb, const guint8* ip)
7147 {
7148         MonoBasicBlock *b = cfg->cil_offset_to_bb [ip - cfg->cil_start];
7149
7150         return b == NULL || b == bb;
7151 }
7152
7153 static int
7154 get_basic_blocks (MonoCompile *cfg, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
7155 {
7156         unsigned char *ip = start;
7157         unsigned char *target;
7158         int i;
7159         guint cli_addr;
7160         MonoBasicBlock *bblock;
7161         const MonoOpcode *opcode;
7162
7163         while (ip < end) {
7164                 cli_addr = ip - start;
7165                 i = mono_opcode_value ((const guint8 **)&ip, end);
7166                 if (i < 0)
7167                         UNVERIFIED;
7168                 opcode = &mono_opcodes [i];
7169                 switch (opcode->argument) {
7170                 case MonoInlineNone:
7171                         ip++; 
7172                         break;
7173                 case MonoInlineString:
7174                 case MonoInlineType:
7175                 case MonoInlineField:
7176                 case MonoInlineMethod:
7177                 case MonoInlineTok:
7178                 case MonoInlineSig:
7179                 case MonoShortInlineR:
7180                 case MonoInlineI:
7181                         ip += 5;
7182                         break;
7183                 case MonoInlineVar:
7184                         ip += 3;
7185                         break;
7186                 case MonoShortInlineVar:
7187                 case MonoShortInlineI:
7188                         ip += 2;
7189                         break;
7190                 case MonoShortInlineBrTarget:
7191                         target = start + cli_addr + 2 + (signed char)ip [1];
7192                         GET_BBLOCK (cfg, bblock, target);
7193                         ip += 2;
7194                         if (ip < end)
7195                                 GET_BBLOCK (cfg, bblock, ip);
7196                         break;
7197                 case MonoInlineBrTarget:
7198                         target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
7199                         GET_BBLOCK (cfg, bblock, target);
7200                         ip += 5;
7201                         if (ip < end)
7202                                 GET_BBLOCK (cfg, bblock, ip);
7203                         break;
7204                 case MonoInlineSwitch: {
7205                         guint32 n = read32 (ip + 1);
7206                         guint32 j;
7207                         ip += 5;
7208                         cli_addr += 5 + 4 * n;
7209                         target = start + cli_addr;
7210                         GET_BBLOCK (cfg, bblock, target);
7211                         
7212                         for (j = 0; j < n; ++j) {
7213                                 target = start + cli_addr + (gint32)read32 (ip);
7214                                 GET_BBLOCK (cfg, bblock, target);
7215                                 ip += 4;
7216                         }
7217                         break;
7218                 }
7219                 case MonoInlineR:
7220                 case MonoInlineI8:
7221                         ip += 9;
7222                         break;
7223                 default:
7224                         g_assert_not_reached ();
7225                 }
7226
7227                 if (i == CEE_THROW) {
7228                         unsigned char *bb_start = ip - 1;
7229                         
7230                         /* Find the start of the bblock containing the throw */
7231                         bblock = NULL;
7232                         while ((bb_start >= start) && !bblock) {
7233                                 bblock = cfg->cil_offset_to_bb [(bb_start) - start];
7234                                 bb_start --;
7235                         }
7236                         if (bblock)
7237                                 bblock->out_of_line = 1;
7238                 }
7239         }
7240         return 0;
7241 unverified:
7242 exception_exit:
7243         *pos = ip;
7244         return 1;
7245 }
7246
7247 static inline MonoMethod *
7248 mini_get_method_allow_open (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
7249 {
7250         MonoMethod *method;
7251
7252         if (m->wrapper_type != MONO_WRAPPER_NONE) {
7253                 method = mono_method_get_wrapper_data (m, token);
7254                 if (context) {
7255                         MonoError error;
7256                         method = mono_class_inflate_generic_method_checked (method, context, &error);
7257                         g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
7258                 }
7259         } else {
7260                 method = mono_get_method_full (m->klass->image, token, klass, context);
7261         }
7262
7263         return method;
7264 }
7265
7266 static inline MonoMethod *
7267 mini_get_method (MonoCompile *cfg, MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
7268 {
7269         MonoMethod *method = mini_get_method_allow_open (m, token, klass, context);
7270
7271         if (method && cfg && !cfg->gshared && mono_class_is_open_constructed_type (&method->klass->byval_arg))
7272                 return NULL;
7273
7274         return method;
7275 }
7276
7277 static inline MonoClass*
7278 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
7279 {
7280         MonoError error;
7281         MonoClass *klass;
7282
7283         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7284                 klass = mono_method_get_wrapper_data (method, token);
7285                 if (context)
7286                         klass = mono_class_inflate_generic_class (klass, context);
7287         } else {
7288                 klass = mono_class_get_and_inflate_typespec_checked (method->klass->image, token, context, &error);
7289                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
7290         }
7291         if (klass)
7292                 mono_class_init (klass);
7293         return klass;
7294 }
7295
7296 static inline MonoMethodSignature*
7297 mini_get_signature (MonoMethod *method, guint32 token, MonoGenericContext *context)
7298 {
7299         MonoMethodSignature *fsig;
7300
7301         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7302                 fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
7303         } else {
7304                 fsig = mono_metadata_parse_signature (method->klass->image, token);
7305         }
7306         if (context) {
7307                 MonoError error;
7308                 fsig = mono_inflate_generic_signature(fsig, context, &error);
7309                 // FIXME:
7310                 g_assert(mono_error_ok(&error));
7311         }
7312         return fsig;
7313 }
7314
7315 static MonoMethod*
7316 throw_exception (void)
7317 {
7318         static MonoMethod *method = NULL;
7319
7320         if (!method) {
7321                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
7322                 method = mono_class_get_method_from_name (secman->securitymanager, "ThrowException", 1);
7323         }
7324         g_assert (method);
7325         return method;
7326 }
7327
7328 static void
7329 emit_throw_exception (MonoCompile *cfg, MonoException *ex)
7330 {
7331         MonoMethod *thrower = throw_exception ();
7332         MonoInst *args [1];
7333
7334         EMIT_NEW_PCONST (cfg, args [0], ex);
7335         mono_emit_method_call (cfg, thrower, args, NULL);
7336 }
7337
7338 /*
7339  * Return the original method is a wrapper is specified. We can only access 
7340  * the custom attributes from the original method.
7341  */
7342 static MonoMethod*
7343 get_original_method (MonoMethod *method)
7344 {
7345         if (method->wrapper_type == MONO_WRAPPER_NONE)
7346                 return method;
7347
7348         /* native code (which is like Critical) can call any managed method XXX FIXME XXX to validate all usages */
7349         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)
7350                 return NULL;
7351
7352         /* in other cases we need to find the original method */
7353         return mono_marshal_method_from_wrapper (method);
7354 }
7355
7356 static void
7357 ensure_method_is_allowed_to_access_field (MonoCompile *cfg, MonoMethod *caller, MonoClassField *field)
7358 {
7359         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
7360         MonoException *ex = mono_security_core_clr_is_field_access_allowed (get_original_method (caller), field);
7361         if (ex)
7362                 emit_throw_exception (cfg, ex);
7363 }
7364
7365 static void
7366 ensure_method_is_allowed_to_call_method (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee)
7367 {
7368         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
7369         MonoException *ex = mono_security_core_clr_is_call_allowed (get_original_method (caller), callee);
7370         if (ex)
7371                 emit_throw_exception (cfg, ex);
7372 }
7373
7374 /*
7375  * Check that the IL instructions at ip are the array initialization
7376  * sequence and return the pointer to the data and the size.
7377  */
7378 static const char*
7379 initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, MonoClass *klass, guint32 len, int *out_size, guint32 *out_field_token)
7380 {
7381         /*
7382          * newarr[System.Int32]
7383          * dup
7384          * ldtoken field valuetype ...
7385          * call void class [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle)
7386          */
7387         if (ip [0] == CEE_DUP && ip [1] == CEE_LDTOKEN && ip [5] == 0x4 && ip [6] == CEE_CALL) {
7388                 MonoError error;
7389                 guint32 token = read32 (ip + 7);
7390                 guint32 field_token = read32 (ip + 2);
7391                 guint32 field_index = field_token & 0xffffff;
7392                 guint32 rva;
7393                 const char *data_ptr;
7394                 int size = 0;
7395                 MonoMethod *cmethod;
7396                 MonoClass *dummy_class;
7397                 MonoClassField *field = mono_field_from_token_checked (method->klass->image, field_token, &dummy_class, NULL, &error);
7398                 int dummy_align;
7399
7400                 if (!field) {
7401                         mono_error_cleanup (&error); /* FIXME don't swallow the error */
7402                         return NULL;
7403                 }
7404
7405                 *out_field_token = field_token;
7406
7407                 cmethod = mini_get_method (NULL, method, token, NULL, NULL);
7408                 if (!cmethod)
7409                         return NULL;
7410                 if (strcmp (cmethod->name, "InitializeArray") || strcmp (cmethod->klass->name, "RuntimeHelpers") || cmethod->klass->image != mono_defaults.corlib)
7411                         return NULL;
7412                 switch (mono_type_get_underlying_type (&klass->byval_arg)->type) {
7413                 case MONO_TYPE_BOOLEAN:
7414                 case MONO_TYPE_I1:
7415                 case MONO_TYPE_U1:
7416                         size = 1; break;
7417                 /* we need to swap on big endian, so punt. Should we handle R4 and R8 as well? */
7418 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
7419                 case MONO_TYPE_CHAR:
7420                 case MONO_TYPE_I2:
7421                 case MONO_TYPE_U2:
7422                         size = 2; break;
7423                 case MONO_TYPE_I4:
7424                 case MONO_TYPE_U4:
7425                 case MONO_TYPE_R4:
7426                         size = 4; break;
7427                 case MONO_TYPE_R8:
7428                 case MONO_TYPE_I8:
7429                 case MONO_TYPE_U8:
7430                         size = 8; break;
7431 #endif
7432                 default:
7433                         return NULL;
7434                 }
7435                 size *= len;
7436                 if (size > mono_type_size (field->type, &dummy_align))
7437                     return NULL;
7438                 *out_size = size;
7439                 /*g_print ("optimized in %s: size: %d, numelems: %d\n", method->name, size, newarr->inst_newa_len->inst_c0);*/
7440                 if (!image_is_dynamic (method->klass->image)) {
7441                         field_index = read32 (ip + 2) & 0xffffff;
7442                         mono_metadata_field_info (method->klass->image, field_index - 1, NULL, &rva, NULL);
7443                         data_ptr = mono_image_rva_map (method->klass->image, rva);
7444                         /*g_print ("field: 0x%08x, rva: %d, rva_ptr: %p\n", read32 (ip + 2), rva, data_ptr);*/
7445                         /* for aot code we do the lookup on load */
7446                         if (aot && data_ptr)
7447                                 return GUINT_TO_POINTER (rva);
7448                 } else {
7449                         /*FIXME is it possible to AOT a SRE assembly not meant to be saved? */ 
7450                         g_assert (!aot);
7451                         data_ptr = mono_field_get_data (field);
7452                 }
7453                 return data_ptr;
7454         }
7455         return NULL;
7456 }
7457
7458 static void
7459 set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsigned char *ip)
7460 {
7461         char *method_fname = mono_method_full_name (method, TRUE);
7462         char *method_code;
7463         MonoMethodHeader *header = mono_method_get_header (method);
7464
7465         if (header->code_size == 0)
7466                 method_code = g_strdup ("method body is empty.");
7467         else
7468                 method_code = mono_disasm_code_one (NULL, method, ip, NULL);
7469         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
7470         cfg->exception_message = g_strdup_printf ("Invalid IL code in %s: %s\n", method_fname, method_code);
7471         g_free (method_fname);
7472         g_free (method_code);
7473         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
7474 }
7475
7476 static void
7477 set_exception_object (MonoCompile *cfg, MonoException *exception)
7478 {
7479         mono_cfg_set_exception (cfg, MONO_EXCEPTION_OBJECT_SUPPLIED);
7480         MONO_GC_REGISTER_ROOT_SINGLE (cfg->exception_ptr, MONO_ROOT_SOURCE_JIT, "jit exception");
7481         cfg->exception_ptr = exception;
7482 }
7483
7484 static void
7485 emit_stloc_ir (MonoCompile *cfg, MonoInst **sp, MonoMethodHeader *header, int n)
7486 {
7487         MonoInst *ins;
7488         guint32 opcode = mono_type_to_regmove (cfg, header->locals [n]);
7489         if ((opcode == OP_MOVE) && cfg->cbb->last_ins == sp [0]  &&
7490                         ((sp [0]->opcode == OP_ICONST) || (sp [0]->opcode == OP_I8CONST))) {
7491                 /* Optimize reg-reg moves away */
7492                 /* 
7493                  * Can't optimize other opcodes, since sp[0] might point to
7494                  * the last ins of a decomposed opcode.
7495                  */
7496                 sp [0]->dreg = (cfg)->locals [n]->dreg;
7497         } else {
7498                 EMIT_NEW_LOCSTORE (cfg, ins, n, *sp);
7499         }
7500 }
7501
7502 /*
7503  * ldloca inhibits many optimizations so try to get rid of it in common
7504  * cases.
7505  */
7506 static inline unsigned char *
7507 emit_optimized_ldloca_ir (MonoCompile *cfg, unsigned char *ip, unsigned char *end, int size)
7508 {
7509         int local, token;
7510         MonoClass *klass;
7511         MonoType *type;
7512
7513         if (size == 1) {
7514                 local = ip [1];
7515                 ip += 2;
7516         } else {
7517                 local = read16 (ip + 2);
7518                 ip += 4;
7519         }
7520         
7521         if (ip + 6 < end && (ip [0] == CEE_PREFIX1) && (ip [1] == CEE_INITOBJ) && ip_in_bb (cfg, cfg->cbb, ip + 1)) {
7522                 /* From the INITOBJ case */
7523                 token = read32 (ip + 2);
7524                 klass = mini_get_class (cfg->current_method, token, cfg->generic_context);
7525                 CHECK_TYPELOAD (klass);
7526                 type = mini_get_underlying_type (&klass->byval_arg);
7527                 emit_init_local (cfg, local, type, TRUE);
7528                 return ip + 6;
7529         }
7530  exception_exit:
7531         return NULL;
7532 }
7533
7534 static gboolean
7535 is_exception_class (MonoClass *klass)
7536 {
7537         while (klass) {
7538                 if (klass == mono_defaults.exception_class)
7539                         return TRUE;
7540                 klass = klass->parent;
7541         }
7542         return FALSE;
7543 }
7544
7545 /*
7546  * is_jit_optimizer_disabled:
7547  *
7548  *   Determine whenever M's assembly has a DebuggableAttribute with the
7549  * IsJITOptimizerDisabled flag set.
7550  */
7551 static gboolean
7552 is_jit_optimizer_disabled (MonoMethod *m)
7553 {
7554         MonoAssembly *ass = m->klass->image->assembly;
7555         MonoCustomAttrInfo* attrs;
7556         static MonoClass *klass;
7557         int i;
7558         gboolean val = FALSE;
7559
7560         g_assert (ass);
7561         if (ass->jit_optimizer_disabled_inited)
7562                 return ass->jit_optimizer_disabled;
7563
7564         if (!klass)
7565                 klass = mono_class_from_name (mono_defaults.corlib, "System.Diagnostics", "DebuggableAttribute");
7566         if (!klass) {
7567                 /* Linked away */
7568                 ass->jit_optimizer_disabled = FALSE;
7569                 mono_memory_barrier ();
7570                 ass->jit_optimizer_disabled_inited = TRUE;
7571                 return FALSE;
7572         }
7573
7574         attrs = mono_custom_attrs_from_assembly (ass);
7575         if (attrs) {
7576                 for (i = 0; i < attrs->num_attrs; ++i) {
7577                         MonoCustomAttrEntry *attr = &attrs->attrs [i];
7578                         const gchar *p;
7579                         MonoMethodSignature *sig;
7580
7581                         if (!attr->ctor || attr->ctor->klass != klass)
7582                                 continue;
7583                         /* Decode the attribute. See reflection.c */
7584                         p = (const char*)attr->data;
7585                         g_assert (read16 (p) == 0x0001);
7586                         p += 2;
7587
7588                         // FIXME: Support named parameters
7589                         sig = mono_method_signature (attr->ctor);
7590                         if (sig->param_count != 2 || sig->params [0]->type != MONO_TYPE_BOOLEAN || sig->params [1]->type != MONO_TYPE_BOOLEAN)
7591                                 continue;
7592                         /* Two boolean arguments */
7593                         p ++;
7594                         val = *p;
7595                 }
7596                 mono_custom_attrs_free (attrs);
7597         }
7598
7599         ass->jit_optimizer_disabled = val;
7600         mono_memory_barrier ();
7601         ass->jit_optimizer_disabled_inited = TRUE;
7602
7603         return val;
7604 }
7605
7606 static gboolean
7607 is_supported_tail_call (MonoCompile *cfg, MonoMethod *method, MonoMethod *cmethod, MonoMethodSignature *fsig, int call_opcode)
7608 {
7609         gboolean supported_tail_call;
7610         int i;
7611
7612 #ifdef MONO_ARCH_HAVE_OP_TAIL_CALL
7613         supported_tail_call = mono_arch_tail_call_supported (cfg, mono_method_signature (method), mono_method_signature (cmethod));
7614 #else
7615         supported_tail_call = mono_metadata_signature_equal (mono_method_signature (method), mono_method_signature (cmethod)) && !MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->ret);
7616 #endif
7617
7618         for (i = 0; i < fsig->param_count; ++i) {
7619                 if (fsig->params [i]->byref || fsig->params [i]->type == MONO_TYPE_PTR || fsig->params [i]->type == MONO_TYPE_FNPTR)
7620                         /* These can point to the current method's stack */
7621                         supported_tail_call = FALSE;
7622         }
7623         if (fsig->hasthis && cmethod->klass->valuetype)
7624                 /* this might point to the current method's stack */
7625                 supported_tail_call = FALSE;
7626         if (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
7627                 supported_tail_call = FALSE;
7628         if (cfg->method->save_lmf)
7629                 supported_tail_call = FALSE;
7630         if (cmethod->wrapper_type && cmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD)
7631                 supported_tail_call = FALSE;
7632         if (call_opcode != CEE_CALL)
7633                 supported_tail_call = FALSE;
7634
7635         /* Debugging support */
7636 #if 0
7637         if (supported_tail_call) {
7638                 if (!mono_debug_count ())
7639                         supported_tail_call = FALSE;
7640         }
7641 #endif
7642
7643         return supported_tail_call;
7644 }
7645
7646 /*
7647  * handle_ctor_call:
7648  *
7649  *   Handle calls made to ctors from NEWOBJ opcodes.
7650  */
7651 static void
7652 handle_ctor_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used,
7653                                   MonoInst **sp, guint8 *ip, int *inline_costs)
7654 {
7655         MonoInst *vtable_arg = NULL, *callvirt_this_arg = NULL, *ins;
7656
7657         if (cmethod->klass->valuetype && mono_class_generic_sharing_enabled (cmethod->klass) &&
7658                                         mono_method_is_generic_sharable (cmethod, TRUE)) {
7659                 if (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst) {
7660                         mono_class_vtable (cfg->domain, cmethod->klass);
7661                         CHECK_TYPELOAD (cmethod->klass);
7662
7663                         vtable_arg = emit_get_rgctx_method (cfg, context_used,
7664                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
7665                 } else {
7666                         if (context_used) {
7667                                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
7668                                                                                                    cmethod->klass, MONO_RGCTX_INFO_VTABLE);
7669                         } else {
7670                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
7671
7672                                 CHECK_TYPELOAD (cmethod->klass);
7673                                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
7674                         }
7675                 }
7676         }
7677
7678         /* Avoid virtual calls to ctors if possible */
7679         if (mono_class_is_marshalbyref (cmethod->klass))
7680                 callvirt_this_arg = sp [0];
7681
7682         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_ctor (cfg, cmethod, fsig, sp))) {
7683                 g_assert (MONO_TYPE_IS_VOID (fsig->ret));
7684                 CHECK_CFG_EXCEPTION;
7685         } else if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used && !vtable_arg &&
7686                            mono_method_check_inlining (cfg, cmethod) &&
7687                            !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE)) {
7688                 int costs;
7689
7690                 if ((costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, FALSE))) {
7691                         cfg->real_offset += 5;
7692
7693                         *inline_costs += costs - 5;
7694                 } else {
7695                         INLINE_FAILURE ("inline failure");
7696                         // FIXME-VT: Clean this up
7697                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))
7698                                 GSHAREDVT_FAILURE(*ip);
7699                         mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, callvirt_this_arg, NULL, NULL);
7700                 }
7701         } else if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
7702                 MonoInst *addr;
7703
7704                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE);
7705                 mono_emit_calli (cfg, fsig, sp, addr, NULL, vtable_arg);
7706         } else if (context_used &&
7707                            ((!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
7708                                  !mono_class_generic_sharing_enabled (cmethod->klass)) || cfg->gsharedvt)) {
7709                 MonoInst *cmethod_addr;
7710
7711                 /* Generic calls made out of gsharedvt methods cannot be patched, so use an indirect call */
7712
7713                 cmethod_addr = emit_get_rgctx_method (cfg, context_used,
7714                                                                                           cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
7715
7716                 mono_emit_calli (cfg, fsig, sp, cmethod_addr, NULL, vtable_arg);
7717         } else {
7718                 INLINE_FAILURE ("ctor call");
7719                 ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp,
7720                                                                                   callvirt_this_arg, NULL, vtable_arg);
7721         }
7722  exception_exit:
7723         return;
7724 }
7725
7726 static MonoMethodSignature*
7727 sig_to_rgctx_sig (MonoMethodSignature *sig)
7728 {
7729         // FIXME: memory allocation
7730         MonoMethodSignature *res;
7731         int i;
7732
7733         res = g_malloc (MONO_SIZEOF_METHOD_SIGNATURE + (sig->param_count + 1) * sizeof (MonoType*));
7734         memcpy (res, sig, MONO_SIZEOF_METHOD_SIGNATURE);
7735         res->param_count = sig->param_count + 1;
7736         for (i = 0; i < sig->param_count; ++i)
7737                 res->params [i] = sig->params [i];
7738         res->params [sig->param_count] = &mono_defaults.int_class->byval_arg;
7739         return res;
7740 }
7741
7742 /*
7743  * mono_method_to_ir:
7744  *
7745  *   Translate the .net IL into linear IR.
7746  */
7747 int
7748 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
7749                    MonoInst *return_var, MonoInst **inline_args, 
7750                    guint inline_offset, gboolean is_virtual_call)
7751 {
7752         MonoError error;
7753         MonoInst *ins, **sp, **stack_start;
7754         MonoBasicBlock *tblock = NULL, *init_localsbb = NULL;
7755         MonoSimpleBasicBlock *bb = NULL, *original_bb = NULL;
7756         MonoMethod *cmethod, *method_definition;
7757         MonoInst **arg_array;
7758         MonoMethodHeader *header;
7759         MonoImage *image;
7760         guint32 token, ins_flag;
7761         MonoClass *klass;
7762         MonoClass *constrained_class = NULL;
7763         unsigned char *ip, *end, *target, *err_pos;
7764         MonoMethodSignature *sig;
7765         MonoGenericContext *generic_context = NULL;
7766         MonoGenericContainer *generic_container = NULL;
7767         MonoType **param_types;
7768         int i, n, start_new_bblock, dreg;
7769         int num_calls = 0, inline_costs = 0;
7770         int breakpoint_id = 0;
7771         guint num_args;
7772         GSList *class_inits = NULL;
7773         gboolean dont_verify, dont_verify_stloc, readonly = FALSE;
7774         int context_used;
7775         gboolean init_locals, seq_points, skip_dead_blocks;
7776         gboolean sym_seq_points = FALSE;
7777         MonoDebugMethodInfo *minfo;
7778         MonoBitSet *seq_point_locs = NULL;
7779         MonoBitSet *seq_point_set_locs = NULL;
7780
7781         cfg->disable_inline = is_jit_optimizer_disabled (method);
7782
7783         /* serialization and xdomain stuff may need access to private fields and methods */
7784         dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
7785         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE;
7786         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH;
7787         dont_verify |= method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; /* bug #77896 */
7788         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP;
7789         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP_INVOKE;
7790
7791         /* still some type unsafety issues in marshal wrappers... (unknown is PtrToStructure) */
7792         dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE;
7793         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_UNKNOWN;
7794         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED;
7795         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_STELEMREF;
7796
7797         image = method->klass->image;
7798         header = mono_method_get_header (method);
7799         if (!header) {
7800                 MonoLoaderError *error;
7801
7802                 if ((error = mono_loader_get_last_error ())) {
7803                         mono_cfg_set_exception (cfg, error->exception_type);
7804                 } else {
7805                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
7806                         cfg->exception_message = g_strdup_printf ("Missing or incorrect header for method %s", cfg->method->name);
7807                 }
7808                 goto exception_exit;
7809         }
7810         generic_container = mono_method_get_generic_container (method);
7811         sig = mono_method_signature (method);
7812         num_args = sig->hasthis + sig->param_count;
7813         ip = (unsigned char*)header->code;
7814         cfg->cil_start = ip;
7815         end = ip + header->code_size;
7816         cfg->stat_cil_code_size += header->code_size;
7817
7818         seq_points = cfg->gen_seq_points && cfg->method == method;
7819
7820         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
7821                 /* We could hit a seq point before attaching to the JIT (#8338) */
7822                 seq_points = FALSE;
7823         }
7824
7825         if (cfg->gen_sdb_seq_points && cfg->method == method) {
7826                 minfo = mono_debug_lookup_method (method);
7827                 if (minfo) {
7828                         MonoSymSeqPoint *sps;
7829                         int i, n_il_offsets;
7830
7831                         mono_debug_get_seq_points (minfo, NULL, NULL, NULL, &sps, &n_il_offsets);
7832                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
7833                         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);
7834                         sym_seq_points = TRUE;
7835                         for (i = 0; i < n_il_offsets; ++i) {
7836                                 if (sps [i].il_offset < header->code_size)
7837                                         mono_bitset_set_fast (seq_point_locs, sps [i].il_offset);
7838                         }
7839                         g_free (sps);
7840                 } else if (!method->wrapper_type && !method->dynamic && mono_debug_image_has_debug_info (method->klass->image)) {
7841                         /* Methods without line number info like auto-generated property accessors */
7842                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
7843                         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);
7844                         sym_seq_points = TRUE;
7845                 }
7846         }
7847
7848         /* 
7849          * Methods without init_locals set could cause asserts in various passes
7850          * (#497220). To work around this, we emit dummy initialization opcodes
7851          * (OP_DUMMY_ICONST etc.) which generate no code. These are only supported
7852          * on some platforms.
7853          */
7854         if ((cfg->opt & MONO_OPT_UNSAFE) && ARCH_HAVE_DUMMY_INIT)
7855                 init_locals = header->init_locals;
7856         else
7857                 init_locals = TRUE;
7858
7859         method_definition = method;
7860         while (method_definition->is_inflated) {
7861                 MonoMethodInflated *imethod = (MonoMethodInflated *) method_definition;
7862                 method_definition = imethod->declaring;
7863         }
7864
7865         /* SkipVerification is not allowed if core-clr is enabled */
7866         if (!dont_verify && mini_assembly_can_skip_verification (cfg->domain, method)) {
7867                 dont_verify = TRUE;
7868                 dont_verify_stloc = TRUE;
7869         }
7870
7871         if (sig->is_inflated)
7872                 generic_context = mono_method_get_context (method);
7873         else if (generic_container)
7874                 generic_context = &generic_container->context;
7875         cfg->generic_context = generic_context;
7876
7877         if (!cfg->gshared)
7878                 g_assert (!sig->has_type_parameters);
7879
7880         if (sig->generic_param_count && method->wrapper_type == MONO_WRAPPER_NONE) {
7881                 g_assert (method->is_inflated);
7882                 g_assert (mono_method_get_context (method)->method_inst);
7883         }
7884         if (method->is_inflated && mono_method_get_context (method)->method_inst)
7885                 g_assert (sig->generic_param_count);
7886
7887         if (cfg->method == method) {
7888                 cfg->real_offset = 0;
7889         } else {
7890                 cfg->real_offset = inline_offset;
7891         }
7892
7893         cfg->cil_offset_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoBasicBlock*) * header->code_size);
7894         cfg->cil_offset_to_bb_len = header->code_size;
7895
7896         cfg->current_method = method;
7897
7898         if (cfg->verbose_level > 2)
7899                 printf ("method to IR %s\n", mono_method_full_name (method, TRUE));
7900
7901         param_types = mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * num_args);
7902         if (sig->hasthis)
7903                 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
7904         for (n = 0; n < sig->param_count; ++n)
7905                 param_types [n + sig->hasthis] = sig->params [n];
7906         cfg->arg_types = param_types;
7907
7908         cfg->dont_inline = g_list_prepend (cfg->dont_inline, method);
7909         if (cfg->method == method) {
7910
7911                 if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
7912                         cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
7913
7914                 /* ENTRY BLOCK */
7915                 NEW_BBLOCK (cfg, start_bblock);
7916                 cfg->bb_entry = start_bblock;
7917                 start_bblock->cil_code = NULL;
7918                 start_bblock->cil_length = 0;
7919
7920                 /* EXIT BLOCK */
7921                 NEW_BBLOCK (cfg, end_bblock);
7922                 cfg->bb_exit = end_bblock;
7923                 end_bblock->cil_code = NULL;
7924                 end_bblock->cil_length = 0;
7925                 end_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
7926                 g_assert (cfg->num_bblocks == 2);
7927
7928                 arg_array = cfg->args;
7929
7930                 if (header->num_clauses) {
7931                         cfg->spvars = g_hash_table_new (NULL, NULL);
7932                         cfg->exvars = g_hash_table_new (NULL, NULL);
7933                 }
7934                 /* handle exception clauses */
7935                 for (i = 0; i < header->num_clauses; ++i) {
7936                         MonoBasicBlock *try_bb;
7937                         MonoExceptionClause *clause = &header->clauses [i];
7938                         GET_BBLOCK (cfg, try_bb, ip + clause->try_offset);
7939
7940                         try_bb->real_offset = clause->try_offset;
7941                         try_bb->try_start = TRUE;
7942                         try_bb->region = ((i + 1) << 8) | clause->flags;
7943                         GET_BBLOCK (cfg, tblock, ip + clause->handler_offset);
7944                         tblock->real_offset = clause->handler_offset;
7945                         tblock->flags |= BB_EXCEPTION_HANDLER;
7946
7947                         /*
7948                          * Linking the try block with the EH block hinders inlining as we won't be able to 
7949                          * merge the bblocks from inlining and produce an artificial hole for no good reason.
7950                          */
7951                         if (COMPILE_LLVM (cfg))
7952                                 link_bblock (cfg, try_bb, tblock);
7953
7954                         if (*(ip + clause->handler_offset) == CEE_POP)
7955                                 tblock->flags |= BB_EXCEPTION_DEAD_OBJ;
7956
7957                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
7958                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER ||
7959                             clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
7960                                 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
7961                                 MONO_ADD_INS (tblock, ins);
7962
7963                                 if (seq_points && clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY && clause->flags != MONO_EXCEPTION_CLAUSE_FILTER) {
7964                                         /* finally clauses already have a seq point */
7965                                         /* seq points for filter clauses are emitted below */
7966                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
7967                                         MONO_ADD_INS (tblock, ins);
7968                                 }
7969
7970                                 /* todo: is a fault block unsafe to optimize? */
7971                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
7972                                         tblock->flags |= BB_EXCEPTION_UNSAFE;
7973                         }
7974
7975                         /*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);
7976                           while (p < end) {
7977                           printf ("%s", mono_disasm_code_one (NULL, method, p, &p));
7978                           }*/
7979                         /* catch and filter blocks get the exception object on the stack */
7980                         if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
7981                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
7982
7983                                 /* mostly like handle_stack_args (), but just sets the input args */
7984                                 /* printf ("handling clause at IL_%04x\n", clause->handler_offset); */
7985                                 tblock->in_scount = 1;
7986                                 tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
7987                                 tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
7988
7989                                 cfg->cbb = tblock;
7990
7991 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
7992                                 /* The EH code passes in the exception in a register to both JITted and LLVM compiled code */
7993                                 if (!cfg->compile_llvm) {
7994                                         MONO_INST_NEW (cfg, ins, OP_GET_EX_OBJ);
7995                                         ins->dreg = tblock->in_stack [0]->dreg;
7996                                         MONO_ADD_INS (tblock, ins);
7997                                 }
7998 #else
7999                                 MonoInst *dummy_use;
8000
8001                                 /* 
8002                                  * Add a dummy use for the exvar so its liveness info will be
8003                                  * correct.
8004                                  */
8005                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, tblock->in_stack [0]);
8006 #endif
8007
8008                                 if (seq_points && clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
8009                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
8010                                         MONO_ADD_INS (tblock, ins);
8011                                 }
8012                                 
8013                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
8014                                         GET_BBLOCK (cfg, tblock, ip + clause->data.filter_offset);
8015                                         tblock->flags |= BB_EXCEPTION_HANDLER;
8016                                         tblock->real_offset = clause->data.filter_offset;
8017                                         tblock->in_scount = 1;
8018                                         tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
8019                                         /* The filter block shares the exvar with the handler block */
8020                                         tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
8021                                         MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
8022                                         MONO_ADD_INS (tblock, ins);
8023                                 }
8024                         }
8025
8026                         if (clause->flags != MONO_EXCEPTION_CLAUSE_FILTER &&
8027                                         clause->data.catch_class &&
8028                                         cfg->gshared &&
8029                                         mono_class_check_context_used (clause->data.catch_class)) {
8030                                 /*
8031                                  * In shared generic code with catch
8032                                  * clauses containing type variables
8033                                  * the exception handling code has to
8034                                  * be able to get to the rgctx.
8035                                  * Therefore we have to make sure that
8036                                  * the vtable/mrgctx argument (for
8037                                  * static or generic methods) or the
8038                                  * "this" argument (for non-static
8039                                  * methods) are live.
8040                                  */
8041                                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
8042                                                 mini_method_get_context (method)->method_inst ||
8043                                                 method->klass->valuetype) {
8044                                         mono_get_vtable_var (cfg);
8045                                 } else {
8046                                         MonoInst *dummy_use;
8047
8048                                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, arg_array [0]);
8049                                 }
8050                         }
8051                 }
8052         } else {
8053                 arg_array = (MonoInst **) alloca (sizeof (MonoInst *) * num_args);
8054                 cfg->cbb = start_bblock;
8055                 cfg->args = arg_array;
8056                 mono_save_args (cfg, sig, inline_args);
8057         }
8058
8059         /* FIRST CODE BLOCK */
8060         NEW_BBLOCK (cfg, tblock);
8061         tblock->cil_code = ip;
8062         cfg->cbb = tblock;
8063         cfg->ip = ip;
8064
8065         ADD_BBLOCK (cfg, tblock);
8066
8067         if (cfg->method == method) {
8068                 breakpoint_id = mono_debugger_method_has_breakpoint (method);
8069                 if (breakpoint_id) {
8070                         MONO_INST_NEW (cfg, ins, OP_BREAK);
8071                         MONO_ADD_INS (cfg->cbb, ins);
8072                 }
8073         }
8074
8075         /* we use a separate basic block for the initialization code */
8076         NEW_BBLOCK (cfg, init_localsbb);
8077         cfg->bb_init = init_localsbb;
8078         init_localsbb->real_offset = cfg->real_offset;
8079         start_bblock->next_bb = init_localsbb;
8080         init_localsbb->next_bb = cfg->cbb;
8081         link_bblock (cfg, start_bblock, init_localsbb);
8082         link_bblock (cfg, init_localsbb, cfg->cbb);
8083                 
8084         cfg->cbb = init_localsbb;
8085
8086         if (cfg->gsharedvt && cfg->method == method) {
8087                 MonoGSharedVtMethodInfo *info;
8088                 MonoInst *var, *locals_var;
8089                 int dreg;
8090
8091                 info = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoGSharedVtMethodInfo));
8092                 info->method = cfg->method;
8093                 info->count_entries = 16;
8094                 info->entries = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
8095                 cfg->gsharedvt_info = info;
8096
8097                 var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8098                 /* prevent it from being register allocated */
8099                 //var->flags |= MONO_INST_VOLATILE;
8100                 cfg->gsharedvt_info_var = var;
8101
8102                 ins = emit_get_rgctx_gsharedvt_method (cfg, mini_method_check_context_used (cfg, method), method, info);
8103                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, var->dreg, ins->dreg);
8104
8105                 /* Allocate locals */
8106                 locals_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8107                 /* prevent it from being register allocated */
8108                 //locals_var->flags |= MONO_INST_VOLATILE;
8109                 cfg->gsharedvt_locals_var = locals_var;
8110
8111                 dreg = alloc_ireg (cfg);
8112                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, dreg, var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, locals_size));
8113
8114                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
8115                 ins->dreg = locals_var->dreg;
8116                 ins->sreg1 = dreg;
8117                 MONO_ADD_INS (cfg->cbb, ins);
8118                 cfg->gsharedvt_locals_var_ins = ins;
8119                 
8120                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
8121                 /*
8122                 if (init_locals)
8123                         ins->flags |= MONO_INST_INIT;
8124                 */
8125         }
8126
8127         if (mono_security_core_clr_enabled ()) {
8128                 /* check if this is native code, e.g. an icall or a p/invoke */
8129                 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
8130                         MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
8131                         if (wrapped) {
8132                                 gboolean pinvk = (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL);
8133                                 gboolean icall = (wrapped->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL);
8134
8135                                 /* if this ia a native call then it can only be JITted from platform code */
8136                                 if ((icall || pinvk) && method->klass && method->klass->image) {
8137                                         if (!mono_security_core_clr_is_platform_image (method->klass->image)) {
8138                                                 MonoException *ex = icall ? mono_get_exception_security () : 
8139                                                         mono_get_exception_method_access ();
8140                                                 emit_throw_exception (cfg, ex);
8141                                         }
8142                                 }
8143                         }
8144                 }
8145         }
8146
8147         CHECK_CFG_EXCEPTION;
8148
8149         if (header->code_size == 0)
8150                 UNVERIFIED;
8151
8152         if (get_basic_blocks (cfg, header, cfg->real_offset, ip, end, &err_pos)) {
8153                 ip = err_pos;
8154                 UNVERIFIED;
8155         }
8156
8157         if (cfg->method == method)
8158                 mono_debug_init_method (cfg, cfg->cbb, breakpoint_id);
8159
8160         for (n = 0; n < header->num_locals; ++n) {
8161                 if (header->locals [n]->type == MONO_TYPE_VOID && !header->locals [n]->byref)
8162                         UNVERIFIED;
8163         }
8164         class_inits = NULL;
8165
8166         /* We force the vtable variable here for all shared methods
8167            for the possibility that they might show up in a stack
8168            trace where their exact instantiation is needed. */
8169         if (cfg->gshared && method == cfg->method) {
8170                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
8171                                 mini_method_get_context (method)->method_inst ||
8172                                 method->klass->valuetype) {
8173                         mono_get_vtable_var (cfg);
8174                 } else {
8175                         /* FIXME: Is there a better way to do this?
8176                            We need the variable live for the duration
8177                            of the whole method. */
8178                         cfg->args [0]->flags |= MONO_INST_VOLATILE;
8179                 }
8180         }
8181
8182         /* add a check for this != NULL to inlined methods */
8183         if (is_virtual_call) {
8184                 MonoInst *arg_ins;
8185
8186                 NEW_ARGLOAD (cfg, arg_ins, 0);
8187                 MONO_ADD_INS (cfg->cbb, arg_ins);
8188                 MONO_EMIT_NEW_CHECK_THIS (cfg, arg_ins->dreg);
8189         }
8190
8191         skip_dead_blocks = !dont_verify;
8192         if (skip_dead_blocks) {
8193                 original_bb = bb = mono_basic_block_split (method, &cfg->error);
8194                 CHECK_CFG_ERROR;
8195                 g_assert (bb);
8196         }
8197
8198         /* we use a spare stack slot in SWITCH and NEWOBJ and others */
8199         stack_start = sp = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
8200
8201         ins_flag = 0;
8202         start_new_bblock = 0;
8203         while (ip < end) {
8204                 if (cfg->method == method)
8205                         cfg->real_offset = ip - header->code;
8206                 else
8207                         cfg->real_offset = inline_offset;
8208                 cfg->ip = ip;
8209
8210                 context_used = 0;
8211
8212                 if (start_new_bblock) {
8213                         cfg->cbb->cil_length = ip - cfg->cbb->cil_code;
8214                         if (start_new_bblock == 2) {
8215                                 g_assert (ip == tblock->cil_code);
8216                         } else {
8217                                 GET_BBLOCK (cfg, tblock, ip);
8218                         }
8219                         cfg->cbb->next_bb = tblock;
8220                         cfg->cbb = tblock;
8221                         start_new_bblock = 0;
8222                         for (i = 0; i < cfg->cbb->in_scount; ++i) {
8223                                 if (cfg->verbose_level > 3)
8224                                         printf ("loading %d from temp %d\n", i, (int)cfg->cbb->in_stack [i]->inst_c0);
8225                                 EMIT_NEW_TEMPLOAD (cfg, ins, cfg->cbb->in_stack [i]->inst_c0);
8226                                 *sp++ = ins;
8227                         }
8228                         if (class_inits)
8229                                 g_slist_free (class_inits);
8230                         class_inits = NULL;
8231                 } else {
8232                         if ((tblock = cfg->cil_offset_to_bb [ip - cfg->cil_start]) && (tblock != cfg->cbb)) {
8233                                 link_bblock (cfg, cfg->cbb, tblock);
8234                                 if (sp != stack_start) {
8235                                         handle_stack_args (cfg, stack_start, sp - stack_start);
8236                                         sp = stack_start;
8237                                         CHECK_UNVERIFIABLE (cfg);
8238                                 }
8239                                 cfg->cbb->next_bb = tblock;
8240                                 cfg->cbb = tblock;
8241                                 for (i = 0; i < cfg->cbb->in_scount; ++i) {
8242                                         if (cfg->verbose_level > 3)
8243                                                 printf ("loading %d from temp %d\n", i, (int)cfg->cbb->in_stack [i]->inst_c0);
8244                                         EMIT_NEW_TEMPLOAD (cfg, ins, cfg->cbb->in_stack [i]->inst_c0);
8245                                         *sp++ = ins;
8246                                 }
8247                                 g_slist_free (class_inits);
8248                                 class_inits = NULL;
8249                         }
8250                 }
8251
8252                 if (skip_dead_blocks) {
8253                         int ip_offset = ip - header->code;
8254
8255                         if (ip_offset == bb->end)
8256                                 bb = bb->next;
8257
8258                         if (bb->dead) {
8259                                 int op_size = mono_opcode_size (ip, end);
8260                                 g_assert (op_size > 0); /*The BB formation pass must catch all bad ops*/
8261
8262                                 if (cfg->verbose_level > 3) printf ("SKIPPING DEAD OP at %x\n", ip_offset);
8263
8264                                 if (ip_offset + op_size == bb->end) {
8265                                         MONO_INST_NEW (cfg, ins, OP_NOP);
8266                                         MONO_ADD_INS (cfg->cbb, ins);
8267                                         start_new_bblock = 1;
8268                                 }
8269
8270                                 ip += op_size;
8271                                 continue;
8272                         }
8273                 }
8274                 /*
8275                  * Sequence points are points where the debugger can place a breakpoint.
8276                  * Currently, we generate these automatically at points where the IL
8277                  * stack is empty.
8278                  */
8279                 if (seq_points && ((!sym_seq_points && (sp == stack_start)) || (sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code)))) {
8280                         /*
8281                          * Make methods interruptable at the beginning, and at the targets of
8282                          * backward branches.
8283                          * Also, do this at the start of every bblock in methods with clauses too,
8284                          * to be able to handle instructions with inprecise control flow like
8285                          * throw/endfinally.
8286                          * Backward branches are handled at the end of method-to-ir ().
8287                          */
8288                         gboolean intr_loc = ip == header->code || (!cfg->cbb->last_ins && cfg->header->num_clauses);
8289                         gboolean sym_seq_point = sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code);
8290
8291                         /* Avoid sequence points on empty IL like .volatile */
8292                         // FIXME: Enable this
8293                         //if (!(cfg->cbb->last_ins && cfg->cbb->last_ins->opcode == OP_SEQ_POINT)) {
8294                         NEW_SEQ_POINT (cfg, ins, ip - header->code, intr_loc);
8295                         if ((sp != stack_start) && !sym_seq_point)
8296                                 ins->flags |= MONO_INST_NONEMPTY_STACK;
8297                         MONO_ADD_INS (cfg->cbb, ins);
8298
8299                         if (sym_seq_points)
8300                                 mono_bitset_set_fast (seq_point_set_locs, ip - header->code);
8301                 }
8302
8303                 cfg->cbb->real_offset = cfg->real_offset;
8304
8305                 if ((cfg->method == method) && cfg->coverage_info) {
8306                         guint32 cil_offset = ip - header->code;
8307                         cfg->coverage_info->data [cil_offset].cil_code = ip;
8308
8309                         /* TODO: Use an increment here */
8310 #if defined(TARGET_X86)
8311                         MONO_INST_NEW (cfg, ins, OP_STORE_MEM_IMM);
8312                         ins->inst_p0 = &(cfg->coverage_info->data [cil_offset].count);
8313                         ins->inst_imm = 1;
8314                         MONO_ADD_INS (cfg->cbb, ins);
8315 #else
8316                         EMIT_NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
8317                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, ins->dreg, 0, 1);
8318 #endif
8319                 }
8320
8321                 if (cfg->verbose_level > 3)
8322                         printf ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
8323
8324                 switch (*ip) {
8325                 case CEE_NOP:
8326                         if (seq_points && !sym_seq_points && sp != stack_start) {
8327                                 /*
8328                                  * The C# compiler uses these nops to notify the JIT that it should
8329                                  * insert seq points.
8330                                  */
8331                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, FALSE);
8332                                 MONO_ADD_INS (cfg->cbb, ins);
8333                         }
8334                         if (cfg->keep_cil_nops)
8335                                 MONO_INST_NEW (cfg, ins, OP_HARD_NOP);
8336                         else
8337                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8338                         ip++;
8339                         MONO_ADD_INS (cfg->cbb, ins);
8340                         break;
8341                 case CEE_BREAK:
8342                         if (should_insert_brekpoint (cfg->method)) {
8343                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
8344                         } else {
8345                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8346                         }
8347                         ip++;
8348                         MONO_ADD_INS (cfg->cbb, ins);
8349                         break;
8350                 case CEE_LDARG_0:
8351                 case CEE_LDARG_1:
8352                 case CEE_LDARG_2:
8353                 case CEE_LDARG_3:
8354                         CHECK_STACK_OVF (1);
8355                         n = (*ip)-CEE_LDARG_0;
8356                         CHECK_ARG (n);
8357                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8358                         ip++;
8359                         *sp++ = ins;
8360                         break;
8361                 case CEE_LDLOC_0:
8362                 case CEE_LDLOC_1:
8363                 case CEE_LDLOC_2:
8364                 case CEE_LDLOC_3:
8365                         CHECK_STACK_OVF (1);
8366                         n = (*ip)-CEE_LDLOC_0;
8367                         CHECK_LOCAL (n);
8368                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8369                         ip++;
8370                         *sp++ = ins;
8371                         break;
8372                 case CEE_STLOC_0:
8373                 case CEE_STLOC_1:
8374                 case CEE_STLOC_2:
8375                 case CEE_STLOC_3: {
8376                         CHECK_STACK (1);
8377                         n = (*ip)-CEE_STLOC_0;
8378                         CHECK_LOCAL (n);
8379                         --sp;
8380                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
8381                                 UNVERIFIED;
8382                         emit_stloc_ir (cfg, sp, header, n);
8383                         ++ip;
8384                         inline_costs += 1;
8385                         break;
8386                         }
8387                 case CEE_LDARG_S:
8388                         CHECK_OPSIZE (2);
8389                         CHECK_STACK_OVF (1);
8390                         n = ip [1];
8391                         CHECK_ARG (n);
8392                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8393                         *sp++ = ins;
8394                         ip += 2;
8395                         break;
8396                 case CEE_LDARGA_S:
8397                         CHECK_OPSIZE (2);
8398                         CHECK_STACK_OVF (1);
8399                         n = ip [1];
8400                         CHECK_ARG (n);
8401                         NEW_ARGLOADA (cfg, ins, n);
8402                         MONO_ADD_INS (cfg->cbb, ins);
8403                         *sp++ = ins;
8404                         ip += 2;
8405                         break;
8406                 case CEE_STARG_S:
8407                         CHECK_OPSIZE (2);
8408                         CHECK_STACK (1);
8409                         --sp;
8410                         n = ip [1];
8411                         CHECK_ARG (n);
8412                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [ip [1]], *sp))
8413                                 UNVERIFIED;
8414                         EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
8415                         ip += 2;
8416                         break;
8417                 case CEE_LDLOC_S:
8418                         CHECK_OPSIZE (2);
8419                         CHECK_STACK_OVF (1);
8420                         n = ip [1];
8421                         CHECK_LOCAL (n);
8422                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8423                         *sp++ = ins;
8424                         ip += 2;
8425                         break;
8426                 case CEE_LDLOCA_S: {
8427                         unsigned char *tmp_ip;
8428                         CHECK_OPSIZE (2);
8429                         CHECK_STACK_OVF (1);
8430                         CHECK_LOCAL (ip [1]);
8431
8432                         if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 1))) {
8433                                 ip = tmp_ip;
8434                                 inline_costs += 1;
8435                                 break;
8436                         }
8437
8438                         EMIT_NEW_LOCLOADA (cfg, ins, ip [1]);
8439                         *sp++ = ins;
8440                         ip += 2;
8441                         break;
8442                 }
8443                 case CEE_STLOC_S:
8444                         CHECK_OPSIZE (2);
8445                         CHECK_STACK (1);
8446                         --sp;
8447                         CHECK_LOCAL (ip [1]);
8448                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [ip [1]], *sp))
8449                                 UNVERIFIED;
8450                         emit_stloc_ir (cfg, sp, header, ip [1]);
8451                         ip += 2;
8452                         inline_costs += 1;
8453                         break;
8454                 case CEE_LDNULL:
8455                         CHECK_STACK_OVF (1);
8456                         EMIT_NEW_PCONST (cfg, ins, NULL);
8457                         ins->type = STACK_OBJ;
8458                         ++ip;
8459                         *sp++ = ins;
8460                         break;
8461                 case CEE_LDC_I4_M1:
8462                         CHECK_STACK_OVF (1);
8463                         EMIT_NEW_ICONST (cfg, ins, -1);
8464                         ++ip;
8465                         *sp++ = ins;
8466                         break;
8467                 case CEE_LDC_I4_0:
8468                 case CEE_LDC_I4_1:
8469                 case CEE_LDC_I4_2:
8470                 case CEE_LDC_I4_3:
8471                 case CEE_LDC_I4_4:
8472                 case CEE_LDC_I4_5:
8473                 case CEE_LDC_I4_6:
8474                 case CEE_LDC_I4_7:
8475                 case CEE_LDC_I4_8:
8476                         CHECK_STACK_OVF (1);
8477                         EMIT_NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
8478                         ++ip;
8479                         *sp++ = ins;
8480                         break;
8481                 case CEE_LDC_I4_S:
8482                         CHECK_OPSIZE (2);
8483                         CHECK_STACK_OVF (1);
8484                         ++ip;
8485                         EMIT_NEW_ICONST (cfg, ins, *((signed char*)ip));
8486                         ++ip;
8487                         *sp++ = ins;
8488                         break;
8489                 case CEE_LDC_I4:
8490                         CHECK_OPSIZE (5);
8491                         CHECK_STACK_OVF (1);
8492                         EMIT_NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
8493                         ip += 5;
8494                         *sp++ = ins;
8495                         break;
8496                 case CEE_LDC_I8:
8497                         CHECK_OPSIZE (9);
8498                         CHECK_STACK_OVF (1);
8499                         MONO_INST_NEW (cfg, ins, OP_I8CONST);
8500                         ins->type = STACK_I8;
8501                         ins->dreg = alloc_dreg (cfg, STACK_I8);
8502                         ++ip;
8503                         ins->inst_l = (gint64)read64 (ip);
8504                         MONO_ADD_INS (cfg->cbb, ins);
8505                         ip += 8;
8506                         *sp++ = ins;
8507                         break;
8508                 case CEE_LDC_R4: {
8509                         float *f;
8510                         gboolean use_aotconst = FALSE;
8511
8512 #ifdef TARGET_POWERPC
8513                         /* FIXME: Clean this up */
8514                         if (cfg->compile_aot)
8515                                 use_aotconst = TRUE;
8516 #endif
8517
8518                         /* FIXME: we should really allocate this only late in the compilation process */
8519                         f = mono_domain_alloc (cfg->domain, sizeof (float));
8520                         CHECK_OPSIZE (5);
8521                         CHECK_STACK_OVF (1);
8522
8523                         if (use_aotconst) {
8524                                 MonoInst *cons;
8525                                 int dreg;
8526
8527                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R4, f);
8528
8529                                 dreg = alloc_freg (cfg);
8530                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR4_MEMBASE, dreg, cons->dreg, 0);
8531                                 ins->type = cfg->r4_stack_type;
8532                         } else {
8533                                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
8534                                 ins->type = cfg->r4_stack_type;
8535                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8536                                 ins->inst_p0 = f;
8537                                 MONO_ADD_INS (cfg->cbb, ins);
8538                         }
8539                         ++ip;
8540                         readr4 (ip, f);
8541                         ip += 4;
8542                         *sp++ = ins;                    
8543                         break;
8544                 }
8545                 case CEE_LDC_R8: {
8546                         double *d;
8547                         gboolean use_aotconst = FALSE;
8548
8549 #ifdef TARGET_POWERPC
8550                         /* FIXME: Clean this up */
8551                         if (cfg->compile_aot)
8552                                 use_aotconst = TRUE;
8553 #endif
8554
8555                         /* FIXME: we should really allocate this only late in the compilation process */
8556                         d = mono_domain_alloc (cfg->domain, sizeof (double));
8557                         CHECK_OPSIZE (9);
8558                         CHECK_STACK_OVF (1);
8559
8560                         if (use_aotconst) {
8561                                 MonoInst *cons;
8562                                 int dreg;
8563
8564                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R8, d);
8565
8566                                 dreg = alloc_freg (cfg);
8567                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR8_MEMBASE, dreg, cons->dreg, 0);
8568                                 ins->type = STACK_R8;
8569                         } else {
8570                                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
8571                                 ins->type = STACK_R8;
8572                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8573                                 ins->inst_p0 = d;
8574                                 MONO_ADD_INS (cfg->cbb, ins);
8575                         }
8576                         ++ip;
8577                         readr8 (ip, d);
8578                         ip += 8;
8579                         *sp++ = ins;
8580                         break;
8581                 }
8582                 case CEE_DUP: {
8583                         MonoInst *temp, *store;
8584                         CHECK_STACK (1);
8585                         CHECK_STACK_OVF (1);
8586                         sp--;
8587                         ins = *sp;
8588
8589                         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
8590                         EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
8591
8592                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8593                         *sp++ = ins;
8594
8595                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8596                         *sp++ = ins;
8597
8598                         ++ip;
8599                         inline_costs += 2;
8600                         break;
8601                 }
8602                 case CEE_POP:
8603                         CHECK_STACK (1);
8604                         ip++;
8605                         --sp;
8606
8607 #ifdef TARGET_X86
8608                         if (sp [0]->type == STACK_R8)
8609                                 /* we need to pop the value from the x86 FP stack */
8610                                 MONO_EMIT_NEW_UNALU (cfg, OP_X86_FPOP, -1, sp [0]->dreg);
8611 #endif
8612                         break;
8613                 case CEE_JMP: {
8614                         MonoCallInst *call;
8615
8616                         INLINE_FAILURE ("jmp");
8617                         GSHAREDVT_FAILURE (*ip);
8618
8619                         CHECK_OPSIZE (5);
8620                         if (stack_start != sp)
8621                                 UNVERIFIED;
8622                         token = read32 (ip + 1);
8623                         /* FIXME: check the signature matches */
8624                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
8625
8626                         if (!cmethod || mono_loader_get_last_error ())
8627                                 LOAD_ERROR;
8628  
8629                         if (cfg->gshared && mono_method_check_context_used (cmethod))
8630                                 GENERIC_SHARING_FAILURE (CEE_JMP);
8631
8632                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
8633
8634                         if (ARCH_HAVE_OP_TAIL_CALL) {
8635                                 MonoMethodSignature *fsig = mono_method_signature (cmethod);
8636                                 int i, n;
8637
8638                                 /* Handle tail calls similarly to calls */
8639                                 n = fsig->param_count + fsig->hasthis;
8640
8641                                 DISABLE_AOT (cfg);
8642
8643                                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
8644                                 call->method = cmethod;
8645                                 call->tail_call = TRUE;
8646                                 call->signature = mono_method_signature (cmethod);
8647                                 call->args = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
8648                                 call->inst.inst_p0 = cmethod;
8649                                 for (i = 0; i < n; ++i)
8650                                         EMIT_NEW_ARGLOAD (cfg, call->args [i], i);
8651
8652                                 mono_arch_emit_call (cfg, call);
8653                                 cfg->param_area = MAX(cfg->param_area, call->stack_usage);
8654                                 MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
8655                         } else {
8656                                 for (i = 0; i < num_args; ++i)
8657                                         /* Prevent arguments from being optimized away */
8658                                         arg_array [i]->flags |= MONO_INST_VOLATILE;
8659
8660                                 MONO_INST_NEW_CALL (cfg, call, OP_JMP);
8661                                 ins = (MonoInst*)call;
8662                                 ins->inst_p0 = cmethod;
8663                                 MONO_ADD_INS (cfg->cbb, ins);
8664                         }
8665
8666                         ip += 5;
8667                         start_new_bblock = 1;
8668                         break;
8669                 }
8670                 case CEE_CALLI: {
8671                         MonoInst *addr;
8672                         MonoMethodSignature *fsig;
8673
8674                         CHECK_OPSIZE (5);
8675                         token = read32 (ip + 1);
8676
8677                         ins = NULL;
8678
8679                         //GSHAREDVT_FAILURE (*ip);
8680                         cmethod = NULL;
8681                         CHECK_STACK (1);
8682                         --sp;
8683                         addr = *sp;
8684                         fsig = mini_get_signature (method, token, generic_context);
8685
8686                         if (method->dynamic && fsig->pinvoke) {
8687                                 MonoInst *args [3];
8688
8689                                 /*
8690                                  * This is a call through a function pointer using a pinvoke
8691                                  * signature. Have to create a wrapper and call that instead.
8692                                  * FIXME: This is very slow, need to create a wrapper at JIT time
8693                                  * instead based on the signature.
8694                                  */
8695                                 EMIT_NEW_IMAGECONST (cfg, args [0], method->klass->image);
8696                                 EMIT_NEW_PCONST (cfg, args [1], fsig);
8697                                 args [2] = addr;
8698                                 addr = mono_emit_jit_icall (cfg, mono_get_native_calli_wrapper, args);
8699                         }
8700
8701                         n = fsig->param_count + fsig->hasthis;
8702
8703                         CHECK_STACK (n);
8704
8705                         //g_assert (!virtual || fsig->hasthis);
8706
8707                         sp -= n;
8708
8709                         inline_costs += 10 * num_calls++;
8710
8711                         /*
8712                          * Making generic calls out of gsharedvt methods.
8713                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
8714                          * patching gshared method addresses into a gsharedvt method.
8715                          */
8716                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
8717                                 /*
8718                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
8719                                  */
8720                                 MonoInst *callee = addr;
8721
8722                                 if (method->wrapper_type != MONO_WRAPPER_DELEGATE_INVOKE)
8723                                         /* Not tested */
8724                                         GSHAREDVT_FAILURE (*ip);
8725
8726                                 addr = emit_get_rgctx_sig (cfg, context_used,
8727                                                                                           fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
8728                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
8729                                 goto calli_end;
8730                         }
8731
8732                         /* Prevent inlining of methods with indirect calls */
8733                         INLINE_FAILURE ("indirect call");
8734
8735                         if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST || addr->opcode == OP_GOT_ENTRY) {
8736                                 int info_type;
8737                                 gpointer info_data;
8738
8739                                 /*
8740                                  * Instead of emitting an indirect call, emit a direct call
8741                                  * with the contents of the aotconst as the patch info.
8742                                  */
8743                                 if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST) {
8744                                         info_type = addr->inst_c1;
8745                                         info_data = addr->inst_p0;
8746                                 } else {
8747                                         info_type = addr->inst_right->inst_c1;
8748                                         info_data = addr->inst_right->inst_left;
8749                                 }
8750
8751                                 if (info_type == MONO_PATCH_INFO_ICALL_ADDR || info_type == MONO_PATCH_INFO_JIT_ICALL_ADDR) {
8752                                         ins = (MonoInst*)mono_emit_abs_call (cfg, info_type, info_data, fsig, sp);
8753                                         NULLIFY_INS (addr);
8754                                         goto calli_end;
8755                                 }
8756                         }
8757                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8758
8759                         calli_end:
8760
8761                         /* End of call, INS should contain the result of the call, if any */
8762
8763                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8764                                 g_assert (ins);
8765                                 *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
8766                         }
8767
8768                         CHECK_CFG_EXCEPTION;
8769
8770                         ip += 5;
8771                         ins_flag = 0;
8772                         constrained_class = NULL;
8773                         break;
8774                 }
8775                 case CEE_CALL:
8776                 case CEE_CALLVIRT: {
8777                         MonoInst *addr = NULL;
8778                         MonoMethodSignature *fsig = NULL;
8779                         int array_rank = 0;
8780                         int virtual = *ip == CEE_CALLVIRT;
8781                         gboolean pass_imt_from_rgctx = FALSE;
8782                         MonoInst *imt_arg = NULL;
8783                         MonoInst *keep_this_alive = NULL;
8784                         gboolean pass_vtable = FALSE;
8785                         gboolean pass_mrgctx = FALSE;
8786                         MonoInst *vtable_arg = NULL;
8787                         gboolean check_this = FALSE;
8788                         gboolean supported_tail_call = FALSE;
8789                         gboolean tail_call = FALSE;
8790                         gboolean need_seq_point = FALSE;
8791                         guint32 call_opcode = *ip;
8792                         gboolean emit_widen = TRUE;
8793                         gboolean push_res = TRUE;
8794                         gboolean skip_ret = FALSE;
8795                         gboolean delegate_invoke = FALSE;
8796                         gboolean direct_icall = FALSE;
8797                         gboolean constrained_partial_call = FALSE;
8798                         MonoMethod *cil_method;
8799
8800                         CHECK_OPSIZE (5);
8801                         token = read32 (ip + 1);
8802
8803                         ins = NULL;
8804
8805                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
8806                         cil_method = cmethod;
8807                                 
8808                         if (constrained_class) {
8809                                 if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->gshared) {
8810                                         if (!mini_is_gsharedvt_klass (constrained_class)) {
8811                                                 g_assert (!cmethod->klass->valuetype);
8812                                                 if (!mini_type_is_reference (&constrained_class->byval_arg))
8813                                                         constrained_partial_call = TRUE;
8814                                         }
8815                                 }
8816
8817                                 if (method->wrapper_type != MONO_WRAPPER_NONE) {
8818                                         if (cfg->verbose_level > 2)
8819                                                 printf ("DM Constrained call to %s\n", mono_type_get_full_name (constrained_class));
8820                                         if (!((constrained_class->byval_arg.type == MONO_TYPE_VAR ||
8821                                                    constrained_class->byval_arg.type == MONO_TYPE_MVAR) &&
8822                                                   cfg->gshared)) {
8823                                                 cmethod = mono_get_method_constrained_with_method (image, cil_method, constrained_class, generic_context, &cfg->error);
8824                                                 CHECK_CFG_ERROR;
8825                                         }
8826                                 } else {
8827                                         if (cfg->verbose_level > 2)
8828                                                 printf ("Constrained call to %s\n", mono_type_get_full_name (constrained_class));
8829
8830                                         if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->gshared) {
8831                                                 /* 
8832                                                  * This is needed since get_method_constrained can't find 
8833                                                  * the method in klass representing a type var.
8834                                                  * The type var is guaranteed to be a reference type in this
8835                                                  * case.
8836                                                  */
8837                                                 if (!mini_is_gsharedvt_klass (constrained_class))
8838                                                         g_assert (!cmethod->klass->valuetype);
8839                                         } else {
8840                                                 cmethod = mono_get_method_constrained_checked (image, token, constrained_class, generic_context, &cil_method, &cfg->error);
8841                                                 CHECK_CFG_ERROR;
8842                                         }
8843                                 }
8844                         }
8845                                         
8846                         if (!cmethod || mono_loader_get_last_error ())
8847                                 LOAD_ERROR;
8848                         if (!dont_verify && !cfg->skip_visibility) {
8849                                 MonoMethod *target_method = cil_method;
8850                                 if (method->is_inflated) {
8851                                         target_method = mini_get_method_allow_open (method, token, NULL, &(mono_method_get_generic_container (method_definition)->context));
8852                                 }
8853                                 if (!mono_method_can_access_method (method_definition, target_method) &&
8854                                         !mono_method_can_access_method (method, cil_method))
8855                                         METHOD_ACCESS_FAILURE (method, cil_method);
8856                         }
8857
8858                         if (mono_security_core_clr_enabled ())
8859                                 ensure_method_is_allowed_to_call_method (cfg, method, cil_method);
8860
8861                         if (!virtual && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
8862                                 /* MS.NET seems to silently convert this to a callvirt */
8863                                 virtual = 1;
8864
8865                         {
8866                                 /*
8867                                  * MS.NET accepts non virtual calls to virtual final methods of transparent proxy classes and
8868                                  * converts to a callvirt.
8869                                  *
8870                                  * tests/bug-515884.il is an example of this behavior
8871                                  */
8872                                 const int test_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_STATIC;
8873                                 const int expected_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL;
8874                                 if (!virtual && mono_class_is_marshalbyref (cmethod->klass) && (cmethod->flags & test_flags) == expected_flags && cfg->method->wrapper_type == MONO_WRAPPER_NONE)
8875                                         virtual = 1;
8876                         }
8877
8878                         if (!cmethod->klass->inited)
8879                                 if (!mono_class_init (cmethod->klass))
8880                                         TYPE_LOAD_ERROR (cmethod->klass);
8881
8882                         fsig = mono_method_signature (cmethod);
8883                         if (!fsig)
8884                                 LOAD_ERROR;
8885                         if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
8886                                 mini_class_is_system_array (cmethod->klass)) {
8887                                 array_rank = cmethod->klass->rank;
8888                         } else if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && icall_is_direct_callable (cfg, cmethod)) {
8889                                 direct_icall = TRUE;
8890                         } else if (fsig->pinvoke) {
8891                                 MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
8892                                 fsig = mono_method_signature (wrapper);
8893                         } else if (constrained_class) {
8894                         } else {
8895                                 fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
8896                                 CHECK_CFG_ERROR;
8897                         }
8898
8899                         /* See code below */
8900                         if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
8901                                 MonoBasicBlock *tbb;
8902
8903                                 GET_BBLOCK (cfg, tbb, ip + 5);
8904                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
8905                                         /*
8906                                          * We want to extend the try block to cover the call, but we can't do it if the
8907                                          * call is made directly since its followed by an exception check.
8908                                          */
8909                                         direct_icall = FALSE;
8910                                 }
8911                         }
8912
8913                         mono_save_token_info (cfg, image, token, cil_method);
8914
8915                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip + 5 - header->code)))
8916                                 need_seq_point = TRUE;
8917
8918                         /* Don't support calls made using type arguments for now */
8919                         /*
8920                           if (cfg->gsharedvt) {
8921                           if (mini_is_gsharedvt_signature (fsig))
8922                           GSHAREDVT_FAILURE (*ip);
8923                           }
8924                         */
8925
8926                         if (cmethod->string_ctor && method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE)
8927                                 g_assert_not_reached ();
8928
8929                         n = fsig->param_count + fsig->hasthis;
8930
8931                         if (!cfg->gshared && cmethod->klass->generic_container)
8932                                 UNVERIFIED;
8933
8934                         if (!cfg->gshared)
8935                                 g_assert (!mono_method_check_context_used (cmethod));
8936
8937                         CHECK_STACK (n);
8938
8939                         //g_assert (!virtual || fsig->hasthis);
8940
8941                         sp -= n;
8942
8943                         if (constrained_class) {
8944                                 if (mini_is_gsharedvt_klass (constrained_class)) {
8945                                         if ((cmethod->klass != mono_defaults.object_class) && constrained_class->valuetype && cmethod->klass->valuetype) {
8946                                                 /* The 'Own method' case below */
8947                                         } else if (cmethod->klass->image != mono_defaults.corlib && !(cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !cmethod->klass->valuetype) {
8948                                                 /* 'The type parameter is instantiated as a reference type' case below. */
8949                                         } else {
8950                                                 ins = handle_constrained_gsharedvt_call (cfg, cmethod, fsig, sp, constrained_class, &emit_widen);
8951                                                 CHECK_CFG_EXCEPTION;
8952                                                 g_assert (ins);
8953                                                 goto call_end;
8954                                         }
8955                                 }
8956
8957                                 /*
8958                                  * We have the `constrained.' prefix opcode.
8959                                  */
8960                                 if (constrained_partial_call) {
8961                                         gboolean need_box = TRUE;
8962
8963                                         /*
8964                                          * The receiver is a valuetype, but the exact type is not known at compile time. This means the
8965                                          * called method is not known at compile time either. The called method could end up being
8966                                          * one of the methods on the parent classes (object/valuetype/enum), in which case we need
8967                                          * to box the receiver.
8968                                          * A simple solution would be to box always and make a normal virtual call, but that would
8969                                          * be bad performance wise.
8970                                          */
8971                                         if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE && cmethod->klass->generic_class) {
8972                                                 /*
8973                                                  * The parent classes implement no generic interfaces, so the called method will be a vtype method, so no boxing neccessary.
8974                                                  */
8975                                                 need_box = FALSE;
8976                                         }
8977
8978                                         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)) {
8979                                                 /* The called method is not virtual, i.e. Object:GetType (), the receiver is a vtype, has to box */
8980                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
8981                                                 ins->klass = constrained_class;
8982                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
8983                                                 CHECK_CFG_EXCEPTION;
8984                                         } else if (need_box) {
8985                                                 MonoInst *box_type;
8986                                                 MonoBasicBlock *is_ref_bb, *end_bb;
8987                                                 MonoInst *nonbox_call;
8988
8989                                                 /*
8990                                                  * Determine at runtime whenever the called method is defined on object/valuetype/enum, and emit a boxing call
8991                                                  * if needed.
8992                                                  * FIXME: It is possible to inline the called method in a lot of cases, i.e. for T_INT,
8993                                                  * the no-box case goes to a method in Int32, while the box case goes to a method in Enum.
8994                                                  */
8995                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
8996
8997                                                 NEW_BBLOCK (cfg, is_ref_bb);
8998                                                 NEW_BBLOCK (cfg, end_bb);
8999
9000                                                 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);
9001                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, box_type->dreg, 1);
9002                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
9003
9004                                                 /* Non-ref case */
9005                                                 nonbox_call = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9006
9007                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
9008
9009                                                 /* Ref case */
9010                                                 MONO_START_BB (cfg, is_ref_bb);
9011                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9012                                                 ins->klass = constrained_class;
9013                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9014                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9015
9016                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
9017
9018                                                 MONO_START_BB (cfg, end_bb);
9019                                                 cfg->cbb = end_bb;
9020
9021                                                 nonbox_call->dreg = ins->dreg;
9022                                                 goto call_end;
9023                                         } else {
9024                                                 g_assert (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE);
9025                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
9026                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9027                                                 goto call_end;
9028                                         }
9029                                 } else if (constrained_class->valuetype && (cmethod->klass == mono_defaults.object_class || cmethod->klass == mono_defaults.enum_class->parent || cmethod->klass == mono_defaults.enum_class)) {
9030                                         /*
9031                                          * The type parameter is instantiated as a valuetype,
9032                                          * but that type doesn't override the method we're
9033                                          * calling, so we need to box `this'.
9034                                          */
9035                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9036                                         ins->klass = constrained_class;
9037                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9038                                         CHECK_CFG_EXCEPTION;
9039                                 } else if (!constrained_class->valuetype) {
9040                                         int dreg = alloc_ireg_ref (cfg);
9041
9042                                         /*
9043                                          * The type parameter is instantiated as a reference
9044                                          * type.  We have a managed pointer on the stack, so
9045                                          * we need to dereference it here.
9046                                          */
9047                                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, sp [0]->dreg, 0);
9048                                         ins->type = STACK_OBJ;
9049                                         sp [0] = ins;
9050                                 } else {
9051                                         if (cmethod->klass->valuetype) {
9052                                                 /* Own method */
9053                                         } else {
9054                                                 /* Interface method */
9055                                                 int ioffset, slot;
9056
9057                                                 mono_class_setup_vtable (constrained_class);
9058                                                 CHECK_TYPELOAD (constrained_class);
9059                                                 ioffset = mono_class_interface_offset (constrained_class, cmethod->klass);
9060                                                 if (ioffset == -1)
9061                                                         TYPE_LOAD_ERROR (constrained_class);
9062                                                 slot = mono_method_get_vtable_slot (cmethod);
9063                                                 if (slot == -1)
9064                                                         TYPE_LOAD_ERROR (cmethod->klass);
9065                                                 cmethod = constrained_class->vtable [ioffset + slot];
9066
9067                                                 if (cmethod->klass == mono_defaults.enum_class) {
9068                                                         /* Enum implements some interfaces, so treat this as the first case */
9069                                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9070                                                         ins->klass = constrained_class;
9071                                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9072                                                         CHECK_CFG_EXCEPTION;
9073                                                 }
9074                                         }
9075                                         virtual = 0;
9076                                 }
9077                                 constrained_class = NULL;
9078                         }
9079
9080                         if (check_call_signature (cfg, fsig, sp))
9081                                 UNVERIFIED;
9082
9083                         if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (cmethod->name, "Invoke"))
9084                                 delegate_invoke = TRUE;
9085
9086                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_sharable_method (cfg, cmethod, fsig, sp))) {
9087                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9088                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
9089                                         emit_widen = FALSE;
9090                                 }
9091
9092                                 goto call_end;
9093                         }
9094
9095                         /* 
9096                          * If the callee is a shared method, then its static cctor
9097                          * might not get called after the call was patched.
9098                          */
9099                         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)) {
9100                                 emit_class_init (cfg, cmethod->klass);
9101                                 CHECK_TYPELOAD (cmethod->klass);
9102                         }
9103
9104                         check_method_sharing (cfg, cmethod, &pass_vtable, &pass_mrgctx);
9105
9106                         if (cfg->gshared) {
9107                                 MonoGenericContext *cmethod_context = mono_method_get_context (cmethod);
9108
9109                                 context_used = mini_method_check_context_used (cfg, cmethod);
9110
9111                                 if (context_used && (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
9112                                         /* Generic method interface
9113                                            calls are resolved via a
9114                                            helper function and don't
9115                                            need an imt. */
9116                                         if (!cmethod_context || !cmethod_context->method_inst)
9117                                                 pass_imt_from_rgctx = TRUE;
9118                                 }
9119
9120                                 /*
9121                                  * If a shared method calls another
9122                                  * shared method then the caller must
9123                                  * have a generic sharing context
9124                                  * because the magic trampoline
9125                                  * requires it.  FIXME: We shouldn't
9126                                  * have to force the vtable/mrgctx
9127                                  * variable here.  Instead there
9128                                  * should be a flag in the cfg to
9129                                  * request a generic sharing context.
9130                                  */
9131                                 if (context_used &&
9132                                                 ((method->flags & METHOD_ATTRIBUTE_STATIC) || method->klass->valuetype))
9133                                         mono_get_vtable_var (cfg);
9134                         }
9135
9136                         if (pass_vtable) {
9137                                 if (context_used) {
9138                                         vtable_arg = emit_get_rgctx_klass (cfg, context_used, cmethod->klass, MONO_RGCTX_INFO_VTABLE);
9139                                 } else {
9140                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
9141
9142                                         CHECK_TYPELOAD (cmethod->klass);
9143                                         EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
9144                                 }
9145                         }
9146
9147                         if (pass_mrgctx) {
9148                                 g_assert (!vtable_arg);
9149
9150                                 if (!cfg->compile_aot) {
9151                                         /* 
9152                                          * emit_get_rgctx_method () calls mono_class_vtable () so check 
9153                                          * for type load errors before.
9154                                          */
9155                                         mono_class_setup_vtable (cmethod->klass);
9156                                         CHECK_TYPELOAD (cmethod->klass);
9157                                 }
9158
9159                                 vtable_arg = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
9160
9161                                 /* !marshalbyref is needed to properly handle generic methods + remoting */
9162                                 if ((!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
9163                                          MONO_METHOD_IS_FINAL (cmethod)) &&
9164                                         !mono_class_is_marshalbyref (cmethod->klass)) {
9165                                         if (virtual)
9166                                                 check_this = TRUE;
9167                                         virtual = 0;
9168                                 }
9169                         }
9170
9171                         if (pass_imt_from_rgctx) {
9172                                 g_assert (!pass_vtable);
9173
9174                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9175                                         cmethod, MONO_RGCTX_INFO_METHOD);
9176                         }
9177
9178                         if (check_this)
9179                                 MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9180
9181                         /* Calling virtual generic methods */
9182                         if (virtual && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) && 
9183                             !(MONO_METHOD_IS_FINAL (cmethod) && 
9184                               cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) &&
9185                             fsig->generic_param_count && 
9186                                 !(cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) &&
9187                                 !cfg->llvm_only) {
9188                                 MonoInst *this_temp, *this_arg_temp, *store;
9189                                 MonoInst *iargs [4];
9190                                 gboolean use_imt = FALSE;
9191
9192                                 g_assert (fsig->is_inflated);
9193
9194                                 /* Prevent inlining of methods that contain indirect calls */
9195                                 INLINE_FAILURE ("virtual generic call");
9196
9197                                 if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))
9198                                         GSHAREDVT_FAILURE (*ip);
9199
9200 #if MONO_ARCH_HAVE_GENERALIZED_IMT_THUNK && defined(MONO_ARCH_GSHARED_SUPPORTED)
9201                                 if (cmethod->wrapper_type == MONO_WRAPPER_NONE)
9202                                         use_imt = TRUE;
9203 #endif
9204
9205                                 if (use_imt) {
9206                                         g_assert (!imt_arg);
9207                                         if (!context_used)
9208                                                 g_assert (cmethod->is_inflated);
9209                                         imt_arg = emit_get_rgctx_method (cfg, context_used,
9210                                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
9211                                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, sp [0], imt_arg, NULL);
9212                                 } else {
9213                                         this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
9214                                         NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
9215                                         MONO_ADD_INS (cfg->cbb, store);
9216
9217                                         /* FIXME: This should be a managed pointer */
9218                                         this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
9219
9220                                         EMIT_NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
9221                                         iargs [1] = emit_get_rgctx_method (cfg, context_used,
9222                                                                                                            cmethod, MONO_RGCTX_INFO_METHOD);
9223                                         EMIT_NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
9224                                         addr = mono_emit_jit_icall (cfg,
9225                                                                                                 mono_helper_compile_generic_method, iargs);
9226
9227                                         EMIT_NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
9228
9229                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9230                                 }
9231
9232                                 goto call_end;
9233                         }
9234
9235                         /*
9236                          * Implement a workaround for the inherent races involved in locking:
9237                          * Monitor.Enter ()
9238                          * try {
9239                          * } finally {
9240                          *    Monitor.Exit ()
9241                          * }
9242                          * If a thread abort happens between the call to Monitor.Enter () and the start of the
9243                          * try block, the Exit () won't be executed, see:
9244                          * http://www.bluebytesoftware.com/blog/2007/01/30/MonitorEnterThreadAbortsAndOrphanedLocks.aspx
9245                          * To work around this, we extend such try blocks to include the last x bytes
9246                          * of the Monitor.Enter () call.
9247                          */
9248                         if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
9249                                 MonoBasicBlock *tbb;
9250
9251                                 GET_BBLOCK (cfg, tbb, ip + 5);
9252                                 /* 
9253                                  * Only extend try blocks with a finally, to avoid catching exceptions thrown
9254                                  * from Monitor.Enter like ArgumentNullException.
9255                                  */
9256                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
9257                                         /* Mark this bblock as needing to be extended */
9258                                         tbb->extend_try_block = TRUE;
9259                                 }
9260                         }
9261
9262                         /* Conversion to a JIT intrinsic */
9263                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_method (cfg, cmethod, fsig, sp))) {
9264                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9265                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
9266                                         emit_widen = FALSE;
9267                                 }
9268                                 goto call_end;
9269                         }
9270
9271                         /* Inlining */
9272                         if ((cfg->opt & MONO_OPT_INLINE) &&
9273                                 (!virtual || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || MONO_METHOD_IS_FINAL (cmethod)) &&
9274                             mono_method_check_inlining (cfg, cmethod)) {
9275                                 int costs;
9276                                 gboolean always = FALSE;
9277
9278                                 if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
9279                                         (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
9280                                         /* Prevent inlining of methods that call wrappers */
9281                                         INLINE_FAILURE ("wrapper call");
9282                                         cmethod = mono_marshal_get_native_wrapper (cmethod, TRUE, FALSE);
9283                                         always = TRUE;
9284                                 }
9285
9286                                 costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, always);
9287                                 if (costs) {
9288                                         cfg->real_offset += 5;
9289
9290                                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9291                                                 /* *sp is already set by inline_method */
9292                                                 sp++;
9293                                                 push_res = FALSE;
9294                                         }
9295
9296                                         inline_costs += costs;
9297
9298                                         goto call_end;
9299                                 }
9300                         }
9301
9302                         /* Tail recursion elimination */
9303                         if ((cfg->opt & MONO_OPT_TAILC) && call_opcode == CEE_CALL && cmethod == method && ip [5] == CEE_RET && !vtable_arg) {
9304                                 gboolean has_vtargs = FALSE;
9305                                 int i;
9306
9307                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9308                                 INLINE_FAILURE ("tail call");
9309
9310                                 /* keep it simple */
9311                                 for (i =  fsig->param_count - 1; i >= 0; i--) {
9312                                         if (MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->params [i])) 
9313                                                 has_vtargs = TRUE;
9314                                 }
9315
9316                                 if (!has_vtargs) {
9317                                         for (i = 0; i < n; ++i)
9318                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9319                                         MONO_INST_NEW (cfg, ins, OP_BR);
9320                                         MONO_ADD_INS (cfg->cbb, ins);
9321                                         tblock = start_bblock->out_bb [0];
9322                                         link_bblock (cfg, cfg->cbb, tblock);
9323                                         ins->inst_target_bb = tblock;
9324                                         start_new_bblock = 1;
9325
9326                                         /* skip the CEE_RET, too */
9327                                         if (ip_in_bb (cfg, cfg->cbb, ip + 5))
9328                                                 skip_ret = TRUE;
9329                                         push_res = FALSE;
9330                                         goto call_end;
9331                                 }
9332                         }
9333
9334                         inline_costs += 10 * num_calls++;
9335
9336                         /*
9337                          * Making generic calls out of gsharedvt methods.
9338                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
9339                          * patching gshared method addresses into a gsharedvt method.
9340                          */
9341                         if (cfg->gsharedvt && (mini_is_gsharedvt_signature (fsig) || cmethod->is_inflated || cmethod->klass->generic_class) &&
9342                                 !(cmethod->klass->rank && cmethod->klass->byval_arg.type != MONO_TYPE_SZARRAY)) {
9343                                 MonoRgctxInfoType info_type;
9344
9345                                 if (virtual) {
9346                                         //if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
9347                                                 //GSHAREDVT_FAILURE (*ip);
9348                                         // disable for possible remoting calls
9349                                         if (fsig->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class))
9350                                                 GSHAREDVT_FAILURE (*ip);
9351                                         if (fsig->generic_param_count) {
9352                                                 /* virtual generic call */
9353                                                 g_assert (!imt_arg);
9354                                                 /* Same as the virtual generic case above */
9355                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9356                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9357                                                 /* This is not needed, as the trampoline code will pass one, and it might be passed in the same reg as the imt arg */
9358                                                 vtable_arg = NULL;
9359                                         } else if ((cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !imt_arg) {
9360                                                 /* This can happen when we call a fully instantiated iface method */
9361                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9362                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9363                                                 vtable_arg = NULL;
9364                                         }
9365                                 }
9366
9367                                 if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (cmethod->name, "Invoke")))
9368                                         keep_this_alive = sp [0];
9369
9370                                 if (virtual && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))
9371                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
9372                                 else
9373                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE;
9374                                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, info_type);
9375
9376                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9377                                 goto call_end;
9378                         }
9379
9380                         /* Generic sharing */
9381
9382                         /*
9383                          * Use this if the callee is gsharedvt sharable too, since
9384                          * at runtime we might find an instantiation so the call cannot
9385                          * be patched (the 'no_patch' code path in mini-trampolines.c).
9386                          */
9387                         if (context_used && !imt_arg && !array_rank && !delegate_invoke &&
9388                                 (!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
9389                                  !mono_class_generic_sharing_enabled (cmethod->klass)) &&
9390                                 (!virtual || MONO_METHOD_IS_FINAL (cmethod) ||
9391                                  !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))) {
9392                                 INLINE_FAILURE ("gshared");
9393
9394                                 g_assert (cfg->gshared && cmethod);
9395                                 g_assert (!addr);
9396
9397                                 /*
9398                                  * We are compiling a call to a
9399                                  * generic method from shared code,
9400                                  * which means that we have to look up
9401                                  * the method in the rgctx and do an
9402                                  * indirect call.
9403                                  */
9404                                 if (fsig->hasthis)
9405                                         MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9406
9407                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
9408                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9409                                 goto call_end;
9410                         }
9411
9412                         /* Direct calls to icalls */
9413                         if (direct_icall) {
9414                                 MonoMethod *wrapper;
9415                                 int costs;
9416
9417                                 /* Inline the wrapper */
9418                                 wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
9419
9420                                 costs = inline_method (cfg, wrapper, fsig, sp, ip, cfg->real_offset, TRUE);
9421                                 g_assert (costs > 0);
9422                                 cfg->real_offset += 5;
9423
9424                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9425                                         /* *sp is already set by inline_method */
9426                                         sp++;
9427                                         push_res = FALSE;
9428                                 }
9429
9430                                 inline_costs += costs;
9431
9432                                 goto call_end;
9433                         }
9434                                         
9435                         /* Array methods */
9436                         if (array_rank) {
9437                                 MonoInst *addr;
9438
9439                                 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ 
9440                                         MonoInst *val = sp [fsig->param_count];
9441
9442                                         if (val->type == STACK_OBJ) {
9443                                                 MonoInst *iargs [2];
9444
9445                                                 iargs [0] = sp [0];
9446                                                 iargs [1] = val;
9447                                                 
9448                                                 mono_emit_jit_icall (cfg, mono_helper_stelem_ref_check, iargs);
9449                                         }
9450                                         
9451                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, TRUE);
9452                                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, fsig->params [fsig->param_count - 1], addr->dreg, 0, val->dreg);
9453                                         if (cfg->gen_write_barriers && val->type == STACK_OBJ && !(val->opcode == OP_PCONST && val->inst_c0 == 0))
9454                                                 emit_write_barrier (cfg, addr, val);
9455                                         if (cfg->gen_write_barriers && mini_is_gsharedvt_klass (cmethod->klass))
9456                                                 GSHAREDVT_FAILURE (*ip);
9457                                 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
9458                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9459
9460                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, addr->dreg, 0);
9461                                 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
9462                                         if (!cmethod->klass->element_class->valuetype && !readonly)
9463                                                 mini_emit_check_array_type (cfg, sp [0], cmethod->klass);
9464                                         CHECK_TYPELOAD (cmethod->klass);
9465                                         
9466                                         readonly = FALSE;
9467                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9468                                         ins = addr;
9469                                 } else {
9470                                         g_assert_not_reached ();
9471                                 }
9472
9473                                 emit_widen = FALSE;
9474                                 goto call_end;
9475                         }
9476
9477                         ins = mini_redirect_call (cfg, cmethod, fsig, sp, virtual ? sp [0] : NULL);
9478                         if (ins)
9479                                 goto call_end;
9480
9481                         /* Tail prefix / tail call optimization */
9482
9483                         /* FIXME: Enabling TAILC breaks some inlining/stack trace/etc tests */
9484                         /* FIXME: runtime generic context pointer for jumps? */
9485                         /* FIXME: handle this for generic sharing eventually */
9486                         if ((ins_flag & MONO_INST_TAILCALL) &&
9487                                 !vtable_arg && !cfg->gshared && is_supported_tail_call (cfg, method, cmethod, fsig, call_opcode))
9488                                 supported_tail_call = TRUE;
9489
9490                         if (supported_tail_call) {
9491                                 MonoCallInst *call;
9492
9493                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9494                                 INLINE_FAILURE ("tail call");
9495
9496                                 //printf ("HIT: %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
9497
9498                                 if (ARCH_HAVE_OP_TAIL_CALL) {
9499                                         /* Handle tail calls similarly to normal calls */
9500                                         tail_call = TRUE;
9501                                 } else {
9502                                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
9503
9504                                         MONO_INST_NEW_CALL (cfg, call, OP_JMP);
9505                                         call->tail_call = TRUE;
9506                                         call->method = cmethod;
9507                                         call->signature = mono_method_signature (cmethod);
9508
9509                                         /*
9510                                          * We implement tail calls by storing the actual arguments into the 
9511                                          * argument variables, then emitting a CEE_JMP.
9512                                          */
9513                                         for (i = 0; i < n; ++i) {
9514                                                 /* Prevent argument from being register allocated */
9515                                                 arg_array [i]->flags |= MONO_INST_VOLATILE;
9516                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9517                                         }
9518                                         ins = (MonoInst*)call;
9519                                         ins->inst_p0 = cmethod;
9520                                         ins->inst_p1 = arg_array [0];
9521                                         MONO_ADD_INS (cfg->cbb, ins);
9522                                         link_bblock (cfg, cfg->cbb, end_bblock);
9523                                         start_new_bblock = 1;
9524
9525                                         // FIXME: Eliminate unreachable epilogs
9526
9527                                         /*
9528                                          * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9529                                          * only reachable from this call.
9530                                          */
9531                                         GET_BBLOCK (cfg, tblock, ip + 5);
9532                                         if (tblock == cfg->cbb || tblock->in_count == 0)
9533                                                 skip_ret = TRUE;
9534                                         push_res = FALSE;
9535
9536                                         goto call_end;
9537                                 }
9538                         }
9539
9540                         /* 
9541                          * Synchronized wrappers.
9542                          * Its hard to determine where to replace a method with its synchronized
9543                          * wrapper without causing an infinite recursion. The current solution is
9544                          * to add the synchronized wrapper in the trampolines, and to
9545                          * change the called method to a dummy wrapper, and resolve that wrapper
9546                          * to the real method in mono_jit_compile_method ().
9547                          */
9548                         if (cfg->method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
9549                                 MonoMethod *orig = mono_marshal_method_from_wrapper (cfg->method);
9550                                 if (cmethod == orig || (cmethod->is_inflated && mono_method_get_declaring_generic_method (cmethod) == orig))
9551                                         cmethod = mono_marshal_get_synchronized_inner_wrapper (cmethod);
9552                         }
9553
9554                         /*
9555                          * Interface calls in llvm-only mode are complicated becase the callee might need an rgctx arg,
9556                          * (i.e. its a vtype method), and there is no way to for the caller to know this at compile time.
9557                          * So we make resolve_iface_call return the rgctx, and do two calls with different signatures
9558                          * based on whenever there is an rgctx or not.
9559                          */
9560                         if (cfg->llvm_only && virtual && cmethod && (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
9561                                 MonoInst *args [16], *icall_args [16];
9562                                 MonoBasicBlock *rgctx_bb, *end_bb;
9563                                 MonoInst *call1, *call2, *call_target;
9564                                 MonoMethodSignature *rgctx_sig;
9565                                 int rgctx_reg, tmp_reg;
9566
9567                                 MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
9568
9569                                 NEW_BBLOCK (cfg, rgctx_bb);
9570                                 NEW_BBLOCK (cfg, end_bb);
9571
9572                                 // FIXME: Optimize this
9573
9574                                 guint32 imt_slot = mono_method_get_imt_slot (cmethod);
9575
9576                                 icall_args [0] = sp [0];
9577                                 EMIT_NEW_ICONST (cfg, icall_args [1], imt_slot);
9578                                 if (imt_arg) {
9579                                         icall_args [2] = imt_arg;
9580                                 } else {
9581                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_METHODCONST, cmethod);
9582                                         icall_args [2] = ins;
9583                                 }
9584
9585                                 rgctx_reg = alloc_preg (cfg);
9586                                 MONO_EMIT_NEW_PCONST (cfg, rgctx_reg, NULL);
9587                                 EMIT_NEW_VARLOADA_VREG (cfg, icall_args [3], rgctx_reg, &mono_defaults.int_class->byval_arg);
9588                                 //EMIT_NEW_PCONST (cfg, icall_args [3], NULL);
9589
9590                                 call_target = mono_emit_jit_icall (cfg, mono_resolve_iface_call, icall_args);
9591
9592                                 // FIXME: Only do this if needed (generic calls)
9593
9594                                 // Check whenever to pass an rgctx
9595                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rgctx_reg, 0);
9596                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, rgctx_bb);
9597                                 /* Non rgctx case */
9598                                 call1 = mono_emit_calli (cfg, fsig, sp, call_target, NULL, vtable_arg);
9599                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
9600                                 /* Rgctx case */
9601                                 MONO_START_BB (cfg, rgctx_bb);
9602                                 /* Make a call with an rgctx */
9603                                 g_assert (fsig->param_count + 2 < 16);
9604                                 args [0] = sp [0];
9605                                 for (i = 0; i < fsig->param_count; ++i)
9606                                         args [i + 1] = sp [i + 1];
9607                                 tmp_reg = alloc_preg (cfg);
9608                                 EMIT_NEW_UNALU (cfg, args [fsig->param_count + 1], OP_MOVE, tmp_reg, rgctx_reg);
9609                                 rgctx_sig = sig_to_rgctx_sig (fsig);
9610                                 call2 = mono_emit_calli (cfg, rgctx_sig, args, call_target, NULL, NULL);
9611                                 call2->dreg = call1->dreg;
9612                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
9613                                 /* End */
9614                                 MONO_START_BB (cfg, end_bb);
9615                                 ins = call1;
9616                                 goto call_end;
9617                         }
9618
9619                         /* Common call */
9620                         INLINE_FAILURE ("call");
9621                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, tail_call, sp, virtual ? sp [0] : NULL,
9622                                                                                           imt_arg, vtable_arg);
9623
9624                         if (tail_call) {
9625                                 link_bblock (cfg, cfg->cbb, end_bblock);
9626                                 start_new_bblock = 1;
9627
9628                                 // FIXME: Eliminate unreachable epilogs
9629
9630                                 /*
9631                                  * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9632                                  * only reachable from this call.
9633                                  */
9634                                 GET_BBLOCK (cfg, tblock, ip + 5);
9635                                 if (tblock == cfg->cbb || tblock->in_count == 0)
9636                                         skip_ret = TRUE;
9637                                 push_res = FALSE;
9638                         }
9639
9640                         call_end:
9641
9642                         /* End of call, INS should contain the result of the call, if any */
9643
9644                         if (push_res && !MONO_TYPE_IS_VOID (fsig->ret)) {
9645                                 g_assert (ins);
9646                                 if (emit_widen)
9647                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
9648                                 else
9649                                         *sp++ = ins;
9650                         }
9651
9652                         if (keep_this_alive) {
9653                                 MonoInst *dummy_use;
9654
9655                                 /* See mono_emit_method_call_full () */
9656                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, keep_this_alive);
9657                         }
9658
9659                         CHECK_CFG_EXCEPTION;
9660
9661                         ip += 5;
9662                         if (skip_ret) {
9663                                 g_assert (*ip == CEE_RET);
9664                                 ip += 1;
9665                         }
9666                         ins_flag = 0;
9667                         constrained_class = NULL;
9668                         if (need_seq_point)
9669                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
9670                         break;
9671                 }
9672                 case CEE_RET:
9673                         if (cfg->method != method) {
9674                                 /* return from inlined method */
9675                                 /* 
9676                                  * If in_count == 0, that means the ret is unreachable due to
9677                                  * being preceeded by a throw. In that case, inline_method () will
9678                                  * handle setting the return value 
9679                                  * (test case: test_0_inline_throw ()).
9680                                  */
9681                                 if (return_var && cfg->cbb->in_count) {
9682                                         MonoType *ret_type = mono_method_signature (method)->ret;
9683
9684                                         MonoInst *store;
9685                                         CHECK_STACK (1);
9686                                         --sp;
9687
9688                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
9689                                                 UNVERIFIED;
9690
9691                                         //g_assert (returnvar != -1);
9692                                         EMIT_NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
9693                                         cfg->ret_var_set = TRUE;
9694                                 } 
9695                         } else {
9696                                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
9697
9698                                 if (cfg->lmf_var && cfg->cbb->in_count && !cfg->llvm_only)
9699                                         emit_pop_lmf (cfg);
9700
9701                                 if (cfg->ret) {
9702                                         MonoType *ret_type = mini_get_underlying_type (mono_method_signature (method)->ret);
9703
9704                                         if (seq_points && !sym_seq_points) {
9705                                                 /* 
9706                                                  * Place a seq point here too even through the IL stack is not
9707                                                  * empty, so a step over on
9708                                                  * call <FOO>
9709                                                  * ret
9710                                                  * will work correctly.
9711                                                  */
9712                                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, TRUE);
9713                                                 MONO_ADD_INS (cfg->cbb, ins);
9714                                         }
9715
9716                                         g_assert (!return_var);
9717                                         CHECK_STACK (1);
9718                                         --sp;
9719
9720                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
9721                                                 UNVERIFIED;
9722
9723                                         if (mini_type_to_stind (cfg, ret_type) == CEE_STOBJ) {
9724                                                 MonoInst *ret_addr;
9725
9726                                                 if (!cfg->vret_addr) {
9727                                                         MonoInst *ins;
9728
9729                                                         EMIT_NEW_VARSTORE (cfg, ins, cfg->ret, ret_type, (*sp));
9730                                                 } else {
9731                                                         EMIT_NEW_RETLOADA (cfg, ret_addr);
9732
9733                                                         EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STOREV_MEMBASE, ret_addr->dreg, 0, (*sp)->dreg);
9734                                                         ins->klass = mono_class_from_mono_type (ret_type);
9735                                                 }
9736                                         } else {
9737 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
9738                                                 if (COMPILE_SOFT_FLOAT (cfg) && !ret_type->byref && ret_type->type == MONO_TYPE_R4) {
9739                                                         MonoInst *iargs [1];
9740                                                         MonoInst *conv;
9741
9742                                                         iargs [0] = *sp;
9743                                                         conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
9744                                                         mono_arch_emit_setret (cfg, method, conv);
9745                                                 } else {
9746                                                         mono_arch_emit_setret (cfg, method, *sp);
9747                                                 }
9748 #else
9749                                                 mono_arch_emit_setret (cfg, method, *sp);
9750 #endif
9751                                         }
9752                                 }
9753                         }
9754                         if (sp != stack_start)
9755                                 UNVERIFIED;
9756                         MONO_INST_NEW (cfg, ins, OP_BR);
9757                         ip++;
9758                         ins->inst_target_bb = end_bblock;
9759                         MONO_ADD_INS (cfg->cbb, ins);
9760                         link_bblock (cfg, cfg->cbb, end_bblock);
9761                         start_new_bblock = 1;
9762                         break;
9763                 case CEE_BR_S:
9764                         CHECK_OPSIZE (2);
9765                         MONO_INST_NEW (cfg, ins, OP_BR);
9766                         ip++;
9767                         target = ip + 1 + (signed char)(*ip);
9768                         ++ip;
9769                         GET_BBLOCK (cfg, tblock, target);
9770                         link_bblock (cfg, cfg->cbb, tblock);
9771                         ins->inst_target_bb = tblock;
9772                         if (sp != stack_start) {
9773                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9774                                 sp = stack_start;
9775                                 CHECK_UNVERIFIABLE (cfg);
9776                         }
9777                         MONO_ADD_INS (cfg->cbb, ins);
9778                         start_new_bblock = 1;
9779                         inline_costs += BRANCH_COST;
9780                         break;
9781                 case CEE_BEQ_S:
9782                 case CEE_BGE_S:
9783                 case CEE_BGT_S:
9784                 case CEE_BLE_S:
9785                 case CEE_BLT_S:
9786                 case CEE_BNE_UN_S:
9787                 case CEE_BGE_UN_S:
9788                 case CEE_BGT_UN_S:
9789                 case CEE_BLE_UN_S:
9790                 case CEE_BLT_UN_S:
9791                         CHECK_OPSIZE (2);
9792                         CHECK_STACK (2);
9793                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
9794                         ip++;
9795                         target = ip + 1 + *(signed char*)ip;
9796                         ip++;
9797
9798                         ADD_BINCOND (NULL);
9799
9800                         sp = stack_start;
9801                         inline_costs += BRANCH_COST;
9802                         break;
9803                 case CEE_BR:
9804                         CHECK_OPSIZE (5);
9805                         MONO_INST_NEW (cfg, ins, OP_BR);
9806                         ip++;
9807
9808                         target = ip + 4 + (gint32)read32(ip);
9809                         ip += 4;
9810                         GET_BBLOCK (cfg, tblock, target);
9811                         link_bblock (cfg, cfg->cbb, tblock);
9812                         ins->inst_target_bb = tblock;
9813                         if (sp != stack_start) {
9814                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9815                                 sp = stack_start;
9816                                 CHECK_UNVERIFIABLE (cfg);
9817                         }
9818
9819                         MONO_ADD_INS (cfg->cbb, ins);
9820
9821                         start_new_bblock = 1;
9822                         inline_costs += BRANCH_COST;
9823                         break;
9824                 case CEE_BRFALSE_S:
9825                 case CEE_BRTRUE_S:
9826                 case CEE_BRFALSE:
9827                 case CEE_BRTRUE: {
9828                         MonoInst *cmp;
9829                         gboolean is_short = ((*ip) == CEE_BRFALSE_S) || ((*ip) == CEE_BRTRUE_S);
9830                         gboolean is_true = ((*ip) == CEE_BRTRUE_S) || ((*ip) == CEE_BRTRUE);
9831                         guint32 opsize = is_short ? 1 : 4;
9832
9833                         CHECK_OPSIZE (opsize);
9834                         CHECK_STACK (1);
9835                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
9836                                 UNVERIFIED;
9837                         ip ++;
9838                         target = ip + opsize + (is_short ? *(signed char*)ip : (gint32)read32(ip));
9839                         ip += opsize;
9840
9841                         sp--;
9842
9843                         GET_BBLOCK (cfg, tblock, target);
9844                         link_bblock (cfg, cfg->cbb, tblock);
9845                         GET_BBLOCK (cfg, tblock, ip);
9846                         link_bblock (cfg, cfg->cbb, tblock);
9847
9848                         if (sp != stack_start) {
9849                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9850                                 CHECK_UNVERIFIABLE (cfg);
9851                         }
9852
9853                         MONO_INST_NEW(cfg, cmp, OP_ICOMPARE_IMM);
9854                         cmp->sreg1 = sp [0]->dreg;
9855                         type_from_op (cfg, cmp, sp [0], NULL);
9856                         CHECK_TYPE (cmp);
9857
9858 #if SIZEOF_REGISTER == 4
9859                         if (cmp->opcode == OP_LCOMPARE_IMM) {
9860                                 /* Convert it to OP_LCOMPARE */
9861                                 MONO_INST_NEW (cfg, ins, OP_I8CONST);
9862                                 ins->type = STACK_I8;
9863                                 ins->dreg = alloc_dreg (cfg, STACK_I8);
9864                                 ins->inst_l = 0;
9865                                 MONO_ADD_INS (cfg->cbb, ins);
9866                                 cmp->opcode = OP_LCOMPARE;
9867                                 cmp->sreg2 = ins->dreg;
9868                         }
9869 #endif
9870                         MONO_ADD_INS (cfg->cbb, cmp);
9871
9872                         MONO_INST_NEW (cfg, ins, is_true ? CEE_BNE_UN : CEE_BEQ);
9873                         type_from_op (cfg, ins, sp [0], NULL);
9874                         MONO_ADD_INS (cfg->cbb, ins);
9875                         ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);
9876                         GET_BBLOCK (cfg, tblock, target);
9877                         ins->inst_true_bb = tblock;
9878                         GET_BBLOCK (cfg, tblock, ip);
9879                         ins->inst_false_bb = tblock;
9880                         start_new_bblock = 2;
9881
9882                         sp = stack_start;
9883                         inline_costs += BRANCH_COST;
9884                         break;
9885                 }
9886                 case CEE_BEQ:
9887                 case CEE_BGE:
9888                 case CEE_BGT:
9889                 case CEE_BLE:
9890                 case CEE_BLT:
9891                 case CEE_BNE_UN:
9892                 case CEE_BGE_UN:
9893                 case CEE_BGT_UN:
9894                 case CEE_BLE_UN:
9895                 case CEE_BLT_UN:
9896                         CHECK_OPSIZE (5);
9897                         CHECK_STACK (2);
9898                         MONO_INST_NEW (cfg, ins, *ip);
9899                         ip++;
9900                         target = ip + 4 + (gint32)read32(ip);
9901                         ip += 4;
9902
9903                         ADD_BINCOND (NULL);
9904
9905                         sp = stack_start;
9906                         inline_costs += BRANCH_COST;
9907                         break;
9908                 case CEE_SWITCH: {
9909                         MonoInst *src1;
9910                         MonoBasicBlock **targets;
9911                         MonoBasicBlock *default_bblock;
9912                         MonoJumpInfoBBTable *table;
9913                         int offset_reg = alloc_preg (cfg);
9914                         int target_reg = alloc_preg (cfg);
9915                         int table_reg = alloc_preg (cfg);
9916                         int sum_reg = alloc_preg (cfg);
9917                         gboolean use_op_switch;
9918
9919                         CHECK_OPSIZE (5);
9920                         CHECK_STACK (1);
9921                         n = read32 (ip + 1);
9922                         --sp;
9923                         src1 = sp [0];
9924                         if ((src1->type != STACK_I4) && (src1->type != STACK_PTR)) 
9925                                 UNVERIFIED;
9926
9927                         ip += 5;
9928                         CHECK_OPSIZE (n * sizeof (guint32));
9929                         target = ip + n * sizeof (guint32);
9930
9931                         GET_BBLOCK (cfg, default_bblock, target);
9932                         default_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
9933
9934                         targets = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * n);
9935                         for (i = 0; i < n; ++i) {
9936                                 GET_BBLOCK (cfg, tblock, target + (gint32)read32(ip));
9937                                 targets [i] = tblock;
9938                                 targets [i]->flags |= BB_INDIRECT_JUMP_TARGET;
9939                                 ip += 4;
9940                         }
9941
9942                         if (sp != stack_start) {
9943                                 /* 
9944                                  * Link the current bb with the targets as well, so handle_stack_args
9945                                  * will set their in_stack correctly.
9946                                  */
9947                                 link_bblock (cfg, cfg->cbb, default_bblock);
9948                                 for (i = 0; i < n; ++i)
9949                                         link_bblock (cfg, cfg->cbb, targets [i]);
9950
9951                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9952                                 sp = stack_start;
9953                                 CHECK_UNVERIFIABLE (cfg);
9954
9955                                 /* Undo the links */
9956                                 mono_unlink_bblock (cfg, cfg->cbb, default_bblock);
9957                                 for (i = 0; i < n; ++i)
9958                                         mono_unlink_bblock (cfg, cfg->cbb, targets [i]);
9959                         }
9960
9961                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, src1->dreg, n);
9962                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBGE_UN, default_bblock);
9963
9964                         for (i = 0; i < n; ++i)
9965                                 link_bblock (cfg, cfg->cbb, targets [i]);
9966
9967                         table = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
9968                         table->table = targets;
9969                         table->table_size = n;
9970
9971                         use_op_switch = FALSE;
9972 #ifdef TARGET_ARM
9973                         /* ARM implements SWITCH statements differently */
9974                         /* FIXME: Make it use the generic implementation */
9975                         if (!cfg->compile_aot)
9976                                 use_op_switch = TRUE;
9977 #endif
9978
9979                         if (COMPILE_LLVM (cfg))
9980                                 use_op_switch = TRUE;
9981
9982                         cfg->cbb->has_jump_table = 1;
9983
9984                         if (use_op_switch) {
9985                                 MONO_INST_NEW (cfg, ins, OP_SWITCH);
9986                                 ins->sreg1 = src1->dreg;
9987                                 ins->inst_p0 = table;
9988                                 ins->inst_many_bb = targets;
9989                                 ins->klass = GUINT_TO_POINTER (n);
9990                                 MONO_ADD_INS (cfg->cbb, ins);
9991                         } else {
9992                                 if (sizeof (gpointer) == 8)
9993                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 3);
9994                                 else
9995                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 2);
9996
9997 #if SIZEOF_REGISTER == 8
9998                                 /* The upper word might not be zero, and we add it to a 64 bit address later */
9999                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, offset_reg, offset_reg);
10000 #endif
10001
10002                                 if (cfg->compile_aot) {
10003                                         MONO_EMIT_NEW_AOTCONST (cfg, table_reg, table, MONO_PATCH_INFO_SWITCH);
10004                                 } else {
10005                                         MONO_INST_NEW (cfg, ins, OP_JUMP_TABLE);
10006                                         ins->inst_c1 = MONO_PATCH_INFO_SWITCH;
10007                                         ins->inst_p0 = table;
10008                                         ins->dreg = table_reg;
10009                                         MONO_ADD_INS (cfg->cbb, ins);
10010                                 }
10011
10012                                 /* FIXME: Use load_memindex */
10013                                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, table_reg, offset_reg);
10014                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, target_reg, sum_reg, 0);
10015                                 MONO_EMIT_NEW_UNALU (cfg, OP_BR_REG, -1, target_reg);
10016                         }
10017                         start_new_bblock = 1;
10018                         inline_costs += (BRANCH_COST * 2);
10019                         break;
10020                 }
10021                 case CEE_LDIND_I1:
10022                 case CEE_LDIND_U1:
10023                 case CEE_LDIND_I2:
10024                 case CEE_LDIND_U2:
10025                 case CEE_LDIND_I4:
10026                 case CEE_LDIND_U4:
10027                 case CEE_LDIND_I8:
10028                 case CEE_LDIND_I:
10029                 case CEE_LDIND_R4:
10030                 case CEE_LDIND_R8:
10031                 case CEE_LDIND_REF:
10032                         CHECK_STACK (1);
10033                         --sp;
10034
10035                         switch (*ip) {
10036                         case CEE_LDIND_R4:
10037                         case CEE_LDIND_R8:
10038                                 dreg = alloc_freg (cfg);
10039                                 break;
10040                         case CEE_LDIND_I8:
10041                                 dreg = alloc_lreg (cfg);
10042                                 break;
10043                         case CEE_LDIND_REF:
10044                                 dreg = alloc_ireg_ref (cfg);
10045                                 break;
10046                         default:
10047                                 dreg = alloc_preg (cfg);
10048                         }
10049
10050                         NEW_LOAD_MEMBASE (cfg, ins, ldind_to_load_membase (*ip), dreg, sp [0]->dreg, 0);
10051                         ins->type = ldind_type [*ip - CEE_LDIND_I1];
10052                         if (*ip == CEE_LDIND_R4)
10053                                 ins->type = cfg->r4_stack_type;
10054                         ins->flags |= ins_flag;
10055                         MONO_ADD_INS (cfg->cbb, ins);
10056                         *sp++ = ins;
10057                         if (ins_flag & MONO_INST_VOLATILE) {
10058                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10059                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10060                         }
10061                         ins_flag = 0;
10062                         ++ip;
10063                         break;
10064                 case CEE_STIND_REF:
10065                 case CEE_STIND_I1:
10066                 case CEE_STIND_I2:
10067                 case CEE_STIND_I4:
10068                 case CEE_STIND_I8:
10069                 case CEE_STIND_R4:
10070                 case CEE_STIND_R8:
10071                 case CEE_STIND_I:
10072                         CHECK_STACK (2);
10073                         sp -= 2;
10074
10075                         if (ins_flag & MONO_INST_VOLATILE) {
10076                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
10077                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
10078                         }
10079
10080                         NEW_STORE_MEMBASE (cfg, ins, stind_to_store_membase (*ip), sp [0]->dreg, 0, sp [1]->dreg);
10081                         ins->flags |= ins_flag;
10082                         ins_flag = 0;
10083
10084                         MONO_ADD_INS (cfg->cbb, ins);
10085
10086                         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)))
10087                                 emit_write_barrier (cfg, sp [0], sp [1]);
10088
10089                         inline_costs += 1;
10090                         ++ip;
10091                         break;
10092
10093                 case CEE_MUL:
10094                         CHECK_STACK (2);
10095
10096                         MONO_INST_NEW (cfg, ins, (*ip));
10097                         sp -= 2;
10098                         ins->sreg1 = sp [0]->dreg;
10099                         ins->sreg2 = sp [1]->dreg;
10100                         type_from_op (cfg, ins, sp [0], sp [1]);
10101                         CHECK_TYPE (ins);
10102                         ins->dreg = alloc_dreg ((cfg), (ins)->type);
10103
10104                         /* Use the immediate opcodes if possible */
10105                         if ((sp [1]->opcode == OP_ICONST) && mono_arch_is_inst_imm (sp [1]->inst_c0)) {
10106                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
10107                                 if (imm_opcode != -1) {
10108                                         ins->opcode = imm_opcode;
10109                                         ins->inst_p1 = (gpointer)(gssize)(sp [1]->inst_c0);
10110                                         ins->sreg2 = -1;
10111
10112                                         NULLIFY_INS (sp [1]);
10113                                 }
10114                         }
10115
10116                         MONO_ADD_INS ((cfg)->cbb, (ins));
10117
10118                         *sp++ = mono_decompose_opcode (cfg, ins);
10119                         ip++;
10120                         break;
10121                 case CEE_ADD:
10122                 case CEE_SUB:
10123                 case CEE_DIV:
10124                 case CEE_DIV_UN:
10125                 case CEE_REM:
10126                 case CEE_REM_UN:
10127                 case CEE_AND:
10128                 case CEE_OR:
10129                 case CEE_XOR:
10130                 case CEE_SHL:
10131                 case CEE_SHR:
10132                 case CEE_SHR_UN:
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                         add_widen_op (cfg, ins, &sp [0], &sp [1]);
10142                         ins->dreg = alloc_dreg ((cfg), (ins)->type);
10143
10144                         /* FIXME: Pass opcode to is_inst_imm */
10145
10146                         /* Use the immediate opcodes if possible */
10147                         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)) {
10148                                 int imm_opcode;
10149
10150                                 imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
10151 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
10152                                 /* Keep emulated opcodes which are optimized away later */
10153                                 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) {
10154                                         imm_opcode = mono_op_to_op_imm (ins->opcode);
10155                                 }
10156 #endif
10157                                 if (imm_opcode != -1) {
10158                                         ins->opcode = imm_opcode;
10159                                         if (sp [1]->opcode == OP_I8CONST) {
10160 #if SIZEOF_REGISTER == 8
10161                                                 ins->inst_imm = sp [1]->inst_l;
10162 #else
10163                                                 ins->inst_ls_word = sp [1]->inst_ls_word;
10164                                                 ins->inst_ms_word = sp [1]->inst_ms_word;
10165 #endif
10166                                         }
10167                                         else
10168                                                 ins->inst_imm = (gssize)(sp [1]->inst_c0);
10169                                         ins->sreg2 = -1;
10170
10171                                         /* Might be followed by an instruction added by add_widen_op */
10172                                         if (sp [1]->next == NULL)
10173                                                 NULLIFY_INS (sp [1]);
10174                                 }
10175                         }
10176                         MONO_ADD_INS ((cfg)->cbb, (ins));
10177
10178                         *sp++ = mono_decompose_opcode (cfg, ins);
10179                         ip++;
10180                         break;
10181                 case CEE_NEG:
10182                 case CEE_NOT:
10183                 case CEE_CONV_I1:
10184                 case CEE_CONV_I2:
10185                 case CEE_CONV_I4:
10186                 case CEE_CONV_R4:
10187                 case CEE_CONV_R8:
10188                 case CEE_CONV_U4:
10189                 case CEE_CONV_I8:
10190                 case CEE_CONV_U8:
10191                 case CEE_CONV_OVF_I8:
10192                 case CEE_CONV_OVF_U8:
10193                 case CEE_CONV_R_UN:
10194                         CHECK_STACK (1);
10195
10196                         /* Special case this earlier so we have long constants in the IR */
10197                         if ((((*ip) == CEE_CONV_I8) || ((*ip) == CEE_CONV_U8)) && (sp [-1]->opcode == OP_ICONST)) {
10198                                 int data = sp [-1]->inst_c0;
10199                                 sp [-1]->opcode = OP_I8CONST;
10200                                 sp [-1]->type = STACK_I8;
10201 #if SIZEOF_REGISTER == 8
10202                                 if ((*ip) == CEE_CONV_U8)
10203                                         sp [-1]->inst_c0 = (guint32)data;
10204                                 else
10205                                         sp [-1]->inst_c0 = data;
10206 #else
10207                                 sp [-1]->inst_ls_word = data;
10208                                 if ((*ip) == CEE_CONV_U8)
10209                                         sp [-1]->inst_ms_word = 0;
10210                                 else
10211                                         sp [-1]->inst_ms_word = (data < 0) ? -1 : 0;
10212 #endif
10213                                 sp [-1]->dreg = alloc_dreg (cfg, STACK_I8);
10214                         }
10215                         else {
10216                                 ADD_UNOP (*ip);
10217                         }
10218                         ip++;
10219                         break;
10220                 case CEE_CONV_OVF_I4:
10221                 case CEE_CONV_OVF_I1:
10222                 case CEE_CONV_OVF_I2:
10223                 case CEE_CONV_OVF_I:
10224                 case CEE_CONV_OVF_U:
10225                         CHECK_STACK (1);
10226
10227                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
10228                                 ADD_UNOP (CEE_CONV_OVF_I8);
10229                                 ADD_UNOP (*ip);
10230                         } else {
10231                                 ADD_UNOP (*ip);
10232                         }
10233                         ip++;
10234                         break;
10235                 case CEE_CONV_OVF_U1:
10236                 case CEE_CONV_OVF_U2:
10237                 case CEE_CONV_OVF_U4:
10238                         CHECK_STACK (1);
10239
10240                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
10241                                 ADD_UNOP (CEE_CONV_OVF_U8);
10242                                 ADD_UNOP (*ip);
10243                         } else {
10244                                 ADD_UNOP (*ip);
10245                         }
10246                         ip++;
10247                         break;
10248                 case CEE_CONV_OVF_I1_UN:
10249                 case CEE_CONV_OVF_I2_UN:
10250                 case CEE_CONV_OVF_I4_UN:
10251                 case CEE_CONV_OVF_I8_UN:
10252                 case CEE_CONV_OVF_U1_UN:
10253                 case CEE_CONV_OVF_U2_UN:
10254                 case CEE_CONV_OVF_U4_UN:
10255                 case CEE_CONV_OVF_U8_UN:
10256                 case CEE_CONV_OVF_I_UN:
10257                 case CEE_CONV_OVF_U_UN:
10258                 case CEE_CONV_U2:
10259                 case CEE_CONV_U1:
10260                 case CEE_CONV_I:
10261                 case CEE_CONV_U:
10262                         CHECK_STACK (1);
10263                         ADD_UNOP (*ip);
10264                         CHECK_CFG_EXCEPTION;
10265                         ip++;
10266                         break;
10267                 case CEE_ADD_OVF:
10268                 case CEE_ADD_OVF_UN:
10269                 case CEE_MUL_OVF:
10270                 case CEE_MUL_OVF_UN:
10271                 case CEE_SUB_OVF:
10272                 case CEE_SUB_OVF_UN:
10273                         CHECK_STACK (2);
10274                         ADD_BINOP (*ip);
10275                         ip++;
10276                         break;
10277                 case CEE_CPOBJ:
10278                         GSHAREDVT_FAILURE (*ip);
10279                         CHECK_OPSIZE (5);
10280                         CHECK_STACK (2);
10281                         token = read32 (ip + 1);
10282                         klass = mini_get_class (method, token, generic_context);
10283                         CHECK_TYPELOAD (klass);
10284                         sp -= 2;
10285                         if (generic_class_is_reference_type (cfg, klass)) {
10286                                 MonoInst *store, *load;
10287                                 int dreg = alloc_ireg_ref (cfg);
10288
10289                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, dreg, sp [1]->dreg, 0);
10290                                 load->flags |= ins_flag;
10291                                 MONO_ADD_INS (cfg->cbb, load);
10292
10293                                 NEW_STORE_MEMBASE (cfg, store, OP_STORE_MEMBASE_REG, sp [0]->dreg, 0, dreg);
10294                                 store->flags |= ins_flag;
10295                                 MONO_ADD_INS (cfg->cbb, store);
10296
10297                                 if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER)
10298                                         emit_write_barrier (cfg, sp [0], sp [1]);
10299                         } else {
10300                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
10301                         }
10302                         ins_flag = 0;
10303                         ip += 5;
10304                         break;
10305                 case CEE_LDOBJ: {
10306                         int loc_index = -1;
10307                         int stloc_len = 0;
10308
10309                         CHECK_OPSIZE (5);
10310                         CHECK_STACK (1);
10311                         --sp;
10312                         token = read32 (ip + 1);
10313                         klass = mini_get_class (method, token, generic_context);
10314                         CHECK_TYPELOAD (klass);
10315
10316                         /* Optimize the common ldobj+stloc combination */
10317                         switch (ip [5]) {
10318                         case CEE_STLOC_S:
10319                                 loc_index = ip [6];
10320                                 stloc_len = 2;
10321                                 break;
10322                         case CEE_STLOC_0:
10323                         case CEE_STLOC_1:
10324                         case CEE_STLOC_2:
10325                         case CEE_STLOC_3:
10326                                 loc_index = ip [5] - CEE_STLOC_0;
10327                                 stloc_len = 1;
10328                                 break;
10329                         default:
10330                                 break;
10331                         }
10332
10333                         if ((loc_index != -1) && ip_in_bb (cfg, cfg->cbb, ip + 5)) {
10334                                 CHECK_LOCAL (loc_index);
10335
10336                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10337                                 ins->dreg = cfg->locals [loc_index]->dreg;
10338                                 ins->flags |= ins_flag;
10339                                 ip += 5;
10340                                 ip += stloc_len;
10341                                 if (ins_flag & MONO_INST_VOLATILE) {
10342                                         /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10343                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10344                                 }
10345                                 ins_flag = 0;
10346                                 break;
10347                         }
10348
10349                         /* Optimize the ldobj+stobj combination */
10350                         /* The reference case ends up being a load+store anyway */
10351                         /* Skip this if the operation is volatile. */
10352                         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)) {
10353                                 CHECK_STACK (1);
10354
10355                                 sp --;
10356
10357                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
10358
10359                                 ip += 5 + 5;
10360                                 ins_flag = 0;
10361                                 break;
10362                         }
10363
10364                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10365                         ins->flags |= ins_flag;
10366                         *sp++ = ins;
10367
10368                         if (ins_flag & MONO_INST_VOLATILE) {
10369                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10370                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10371                         }
10372
10373                         ip += 5;
10374                         ins_flag = 0;
10375                         inline_costs += 1;
10376                         break;
10377                 }
10378                 case CEE_LDSTR:
10379                         CHECK_STACK_OVF (1);
10380                         CHECK_OPSIZE (5);
10381                         n = read32 (ip + 1);
10382
10383                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
10384                                 EMIT_NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
10385                                 ins->type = STACK_OBJ;
10386                                 *sp = ins;
10387                         }
10388                         else if (method->wrapper_type != MONO_WRAPPER_NONE) {
10389                                 MonoInst *iargs [1];
10390                                 char *str = mono_method_get_wrapper_data (method, n);
10391
10392                                 if (cfg->compile_aot)
10393                                         EMIT_NEW_LDSTRLITCONST (cfg, iargs [0], str);
10394                                 else
10395                                         EMIT_NEW_PCONST (cfg, iargs [0], str);
10396                                 *sp = mono_emit_jit_icall (cfg, mono_string_new_wrapper, iargs);
10397                         } else {
10398                                 if (cfg->opt & MONO_OPT_SHARED) {
10399                                         MonoInst *iargs [3];
10400
10401                                         if (cfg->compile_aot) {
10402                                                 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
10403                                         }
10404                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10405                                         EMIT_NEW_IMAGECONST (cfg, iargs [1], image);
10406                                         EMIT_NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
10407                                         *sp = mono_emit_jit_icall (cfg, mono_ldstr, iargs);
10408                                         mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
10409                                 } else {
10410                                         if (cfg->cbb->out_of_line) {
10411                                                 MonoInst *iargs [2];
10412
10413                                                 if (image == mono_defaults.corlib) {
10414                                                         /* 
10415                                                          * Avoid relocations in AOT and save some space by using a 
10416                                                          * version of helper_ldstr specialized to mscorlib.
10417                                                          */
10418                                                         EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (n));
10419                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr_mscorlib, iargs);
10420                                                 } else {
10421                                                         /* Avoid creating the string object */
10422                                                         EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
10423                                                         EMIT_NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n));
10424                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr, iargs);
10425                                                 }
10426                                         } 
10427                                         else
10428                                         if (cfg->compile_aot) {
10429                                                 NEW_LDSTRCONST (cfg, ins, image, n);
10430                                                 *sp = ins;
10431                                                 MONO_ADD_INS (cfg->cbb, ins);
10432                                         } 
10433                                         else {
10434                                                 NEW_PCONST (cfg, ins, NULL);
10435                                                 ins->type = STACK_OBJ;
10436                                                 ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
10437                                                 if (!ins->inst_p0)
10438                                                         OUT_OF_MEMORY_FAILURE;
10439
10440                                                 *sp = ins;
10441                                                 MONO_ADD_INS (cfg->cbb, ins);
10442                                         }
10443                                 }
10444                         }
10445
10446                         sp++;
10447                         ip += 5;
10448                         break;
10449                 case CEE_NEWOBJ: {
10450                         MonoInst *iargs [2];
10451                         MonoMethodSignature *fsig;
10452                         MonoInst this_ins;
10453                         MonoInst *alloc;
10454                         MonoInst *vtable_arg = NULL;
10455
10456                         CHECK_OPSIZE (5);
10457                         token = read32 (ip + 1);
10458                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
10459                         if (!cmethod || mono_loader_get_last_error ())
10460                                 LOAD_ERROR;
10461                         fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
10462                         CHECK_CFG_ERROR;
10463
10464                         mono_save_token_info (cfg, image, token, cmethod);
10465
10466                         if (!mono_class_init (cmethod->klass))
10467                                 TYPE_LOAD_ERROR (cmethod->klass);
10468
10469                         context_used = mini_method_check_context_used (cfg, cmethod);
10470
10471                         if (mono_security_core_clr_enabled ())
10472                                 ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
10473
10474                         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)) {
10475                                 emit_class_init (cfg, cmethod->klass);
10476                                 CHECK_TYPELOAD (cmethod->klass);
10477                         }
10478
10479                         /*
10480                         if (cfg->gsharedvt) {
10481                                 if (mini_is_gsharedvt_variable_signature (sig))
10482                                         GSHAREDVT_FAILURE (*ip);
10483                         }
10484                         */
10485
10486                         n = fsig->param_count;
10487                         CHECK_STACK (n);
10488
10489                         /* 
10490                          * Generate smaller code for the common newobj <exception> instruction in
10491                          * argument checking code.
10492                          */
10493                         if (cfg->cbb->out_of_line && cmethod->klass->image == mono_defaults.corlib &&
10494                                 is_exception_class (cmethod->klass) && n <= 2 &&
10495                                 ((n < 1) || (!fsig->params [0]->byref && fsig->params [0]->type == MONO_TYPE_STRING)) && 
10496                                 ((n < 2) || (!fsig->params [1]->byref && fsig->params [1]->type == MONO_TYPE_STRING))) {
10497                                 MonoInst *iargs [3];
10498
10499                                 sp -= n;
10500
10501                                 EMIT_NEW_ICONST (cfg, iargs [0], cmethod->klass->type_token);
10502                                 switch (n) {
10503                                 case 0:
10504                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_0, iargs);
10505                                         break;
10506                                 case 1:
10507                                         iargs [1] = sp [0];
10508                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_1, iargs);
10509                                         break;
10510                                 case 2:
10511                                         iargs [1] = sp [0];
10512                                         iargs [2] = sp [1];
10513                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_2, iargs);
10514                                         break;
10515                                 default:
10516                                         g_assert_not_reached ();
10517                                 }
10518
10519                                 ip += 5;
10520                                 inline_costs += 5;
10521                                 break;
10522                         }
10523
10524                         /* move the args to allow room for 'this' in the first position */
10525                         while (n--) {
10526                                 --sp;
10527                                 sp [1] = sp [0];
10528                         }
10529
10530                         /* check_call_signature () requires sp[0] to be set */
10531                         this_ins.type = STACK_OBJ;
10532                         sp [0] = &this_ins;
10533                         if (check_call_signature (cfg, fsig, sp))
10534                                 UNVERIFIED;
10535
10536                         iargs [0] = NULL;
10537
10538                         if (mini_class_is_system_array (cmethod->klass)) {
10539                                 *sp = emit_get_rgctx_method (cfg, context_used,
10540                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
10541
10542                                 /* Avoid varargs in the common case */
10543                                 if (fsig->param_count == 1)
10544                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_1, sp);
10545                                 else if (fsig->param_count == 2)
10546                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_2, sp);
10547                                 else if (fsig->param_count == 3)
10548                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_3, sp);
10549                                 else if (fsig->param_count == 4)
10550                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_4, sp);
10551                                 else
10552                                         alloc = handle_array_new (cfg, fsig->param_count, sp, ip);
10553                         } else if (cmethod->string_ctor) {
10554                                 g_assert (!context_used);
10555                                 g_assert (!vtable_arg);
10556                                 /* we simply pass a null pointer */
10557                                 EMIT_NEW_PCONST (cfg, *sp, NULL); 
10558                                 /* now call the string ctor */
10559                                 alloc = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, NULL, NULL, NULL);
10560                         } else {
10561                                 if (cmethod->klass->valuetype) {
10562                                         iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
10563                                         emit_init_rvar (cfg, iargs [0]->dreg, &cmethod->klass->byval_arg);
10564                                         EMIT_NEW_TEMPLOADA (cfg, *sp, iargs [0]->inst_c0);
10565
10566                                         alloc = NULL;
10567
10568                                         /* 
10569                                          * The code generated by mini_emit_virtual_call () expects
10570                                          * iargs [0] to be a boxed instance, but luckily the vcall
10571                                          * will be transformed into a normal call there.
10572                                          */
10573                                 } else if (context_used) {
10574                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, context_used);
10575                                         *sp = alloc;
10576                                 } else {
10577                                         MonoVTable *vtable = NULL;
10578
10579                                         if (!cfg->compile_aot)
10580                                                 vtable = mono_class_vtable (cfg->domain, cmethod->klass);
10581                                         CHECK_TYPELOAD (cmethod->klass);
10582
10583                                         /*
10584                                          * TypeInitializationExceptions thrown from the mono_runtime_class_init
10585                                          * call in mono_jit_runtime_invoke () can abort the finalizer thread.
10586                                          * As a workaround, we call class cctors before allocating objects.
10587                                          */
10588                                         if (mini_field_access_needs_cctor_run (cfg, method, cmethod->klass, vtable) && !(g_slist_find (class_inits, cmethod->klass))) {
10589                                                 emit_class_init (cfg, cmethod->klass);
10590                                                 if (cfg->verbose_level > 2)
10591                                                         printf ("class %s.%s needs init call for ctor\n", cmethod->klass->name_space, cmethod->klass->name);
10592                                                 class_inits = g_slist_prepend (class_inits, cmethod->klass);
10593                                         }
10594
10595                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, 0);
10596                                         *sp = alloc;
10597                                 }
10598                                 CHECK_CFG_EXCEPTION; /*for handle_alloc*/
10599
10600                                 if (alloc)
10601                                         MONO_EMIT_NEW_UNALU (cfg, OP_NOT_NULL, -1, alloc->dreg);
10602
10603                                 /* Now call the actual ctor */
10604                                 handle_ctor_call (cfg, cmethod, fsig, context_used, sp, ip, &inline_costs);
10605                                 CHECK_CFG_EXCEPTION;
10606                         }
10607
10608                         if (alloc == NULL) {
10609                                 /* Valuetype */
10610                                 EMIT_NEW_TEMPLOAD (cfg, ins, iargs [0]->inst_c0);
10611                                 type_to_eval_stack_type (cfg, &ins->klass->byval_arg, ins);
10612                                 *sp++= ins;
10613                         } else {
10614                                 *sp++ = alloc;
10615                         }
10616                         
10617                         ip += 5;
10618                         inline_costs += 5;
10619                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip - header->code)))
10620                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
10621                         break;
10622                 }
10623                 case CEE_CASTCLASS:
10624                         CHECK_STACK (1);
10625                         --sp;
10626                         CHECK_OPSIZE (5);
10627                         token = read32 (ip + 1);
10628                         klass = mini_get_class (method, token, generic_context);
10629                         CHECK_TYPELOAD (klass);
10630                         if (sp [0]->type != STACK_OBJ)
10631                                 UNVERIFIED;
10632
10633                         ins = handle_castclass (cfg, klass, *sp, ip, &inline_costs);
10634                         CHECK_CFG_EXCEPTION;
10635
10636                         *sp ++ = ins;
10637                         ip += 5;
10638                         break;
10639                 case CEE_ISINST: {
10640                         CHECK_STACK (1);
10641                         --sp;
10642                         CHECK_OPSIZE (5);
10643                         token = read32 (ip + 1);
10644                         klass = mini_get_class (method, token, generic_context);
10645                         CHECK_TYPELOAD (klass);
10646                         if (sp [0]->type != STACK_OBJ)
10647                                 UNVERIFIED;
10648  
10649                         context_used = mini_class_check_context_used (cfg, klass);
10650
10651                         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
10652                                 MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
10653                                 MonoInst *args [3];
10654                                 int idx;
10655
10656                                 /* obj */
10657                                 args [0] = *sp;
10658
10659                                 /* klass */
10660                                 EMIT_NEW_CLASSCONST (cfg, args [1], klass);
10661
10662                                 /* inline cache*/
10663                                 if (cfg->compile_aot) {
10664                                         idx = get_castclass_cache_idx (cfg);
10665                                         EMIT_NEW_AOTCONST (cfg, args [2], MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
10666                                 } else {
10667                                         EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));
10668                                 }
10669
10670                                 *sp++ = mono_emit_method_call (cfg, mono_isinst, args, NULL);
10671                                 ip += 5;
10672                                 inline_costs += 2;
10673                         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
10674                                 MonoMethod *mono_isinst;
10675                                 MonoInst *iargs [1];
10676                                 int costs;
10677
10678                                 mono_isinst = mono_marshal_get_isinst (klass); 
10679                                 iargs [0] = sp [0];
10680
10681                                 costs = inline_method (cfg, mono_isinst, mono_method_signature (mono_isinst), 
10682                                                                            iargs, ip, cfg->real_offset, TRUE);
10683                                 CHECK_CFG_EXCEPTION;
10684                                 g_assert (costs > 0);
10685                                 
10686                                 ip += 5;
10687                                 cfg->real_offset += 5;
10688
10689                                 *sp++= iargs [0];
10690
10691                                 inline_costs += costs;
10692                         }
10693                         else {
10694                                 ins = handle_isinst (cfg, klass, *sp, context_used);
10695                                 CHECK_CFG_EXCEPTION;
10696                                 *sp ++ = ins;
10697                                 ip += 5;
10698                         }
10699                         break;
10700                 }
10701                 case CEE_UNBOX_ANY: {
10702                         MonoInst *res, *addr;
10703
10704                         CHECK_STACK (1);
10705                         --sp;
10706                         CHECK_OPSIZE (5);
10707                         token = read32 (ip + 1);
10708                         klass = mini_get_class (method, token, generic_context);
10709                         CHECK_TYPELOAD (klass);
10710
10711                         mono_save_token_info (cfg, image, token, klass);
10712
10713                         context_used = mini_class_check_context_used (cfg, klass);
10714
10715                         if (mini_is_gsharedvt_klass (klass)) {
10716                                 res = handle_unbox_gsharedvt (cfg, klass, *sp);
10717                                 inline_costs += 2;
10718                         } else if (generic_class_is_reference_type (cfg, klass)) {
10719                                 res = handle_castclass (cfg, klass, *sp, ip, &inline_costs);
10720                                 CHECK_CFG_EXCEPTION;
10721                         } else if (mono_class_is_nullable (klass)) {
10722                                 res = handle_unbox_nullable (cfg, *sp, klass, context_used);
10723                         } else {
10724                                 addr = handle_unbox (cfg, klass, sp, context_used);
10725                                 /* LDOBJ */
10726                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
10727                                 res = ins;
10728                                 inline_costs += 2;
10729                         }
10730
10731                         *sp ++ = res;
10732                         ip += 5;
10733                         break;
10734                 }
10735                 case CEE_BOX: {
10736                         MonoInst *val;
10737                         MonoClass *enum_class;
10738                         MonoMethod *has_flag;
10739
10740                         CHECK_STACK (1);
10741                         --sp;
10742                         val = *sp;
10743                         CHECK_OPSIZE (5);
10744                         token = read32 (ip + 1);
10745                         klass = mini_get_class (method, token, generic_context);
10746                         CHECK_TYPELOAD (klass);
10747
10748                         mono_save_token_info (cfg, image, token, klass);
10749
10750                         context_used = mini_class_check_context_used (cfg, klass);
10751
10752                         if (generic_class_is_reference_type (cfg, klass)) {
10753                                 *sp++ = val;
10754                                 ip += 5;
10755                                 break;
10756                         }
10757
10758                         if (klass == mono_defaults.void_class)
10759                                 UNVERIFIED;
10760                         if (target_type_is_incompatible (cfg, &klass->byval_arg, *sp))
10761                                 UNVERIFIED;
10762                         /* frequent check in generic code: box (struct), brtrue */
10763
10764                         /*
10765                          * Look for:
10766                          *
10767                          *   <push int/long ptr>
10768                          *   <push int/long>
10769                          *   box MyFlags
10770                          *   constrained. MyFlags
10771                          *   callvirt instace bool class [mscorlib] System.Enum::HasFlag (class [mscorlib] System.Enum)
10772                          *
10773                          * If we find this sequence and the operand types on box and constrained
10774                          * are equal, we can emit a specialized instruction sequence instead of
10775                          * the very slow HasFlag () call.
10776                          */
10777                         if ((cfg->opt & MONO_OPT_INTRINS) &&
10778                             /* Cheap checks first. */
10779                             ip + 5 + 6 + 5 < end &&
10780                             ip [5] == CEE_PREFIX1 &&
10781                             ip [6] == CEE_CONSTRAINED_ &&
10782                             ip [11] == CEE_CALLVIRT &&
10783                             ip_in_bb (cfg, cfg->cbb, ip + 5 + 6 + 5) &&
10784                             mono_class_is_enum (klass) &&
10785                             (enum_class = mini_get_class (method, read32 (ip + 7), generic_context)) &&
10786                             (has_flag = mini_get_method (cfg, method, read32 (ip + 12), NULL, generic_context)) &&
10787                             has_flag->klass == mono_defaults.enum_class &&
10788                             !strcmp (has_flag->name, "HasFlag") &&
10789                             has_flag->signature->hasthis &&
10790                             has_flag->signature->param_count == 1) {
10791                                 CHECK_TYPELOAD (enum_class);
10792
10793                                 if (enum_class == klass) {
10794                                         MonoInst *enum_this, *enum_flag;
10795
10796                                         ip += 5 + 6 + 5;
10797                                         --sp;
10798
10799                                         enum_this = sp [0];
10800                                         enum_flag = sp [1];
10801
10802                                         *sp++ = handle_enum_has_flag (cfg, klass, enum_this, enum_flag);
10803                                         break;
10804                                 }
10805                         }
10806
10807                         // FIXME: LLVM can't handle the inconsistent bb linking
10808                         if (!mono_class_is_nullable (klass) &&
10809                                 !mini_is_gsharedvt_klass (klass) &&
10810                                 ip + 5 < end && ip_in_bb (cfg, cfg->cbb, ip + 5) &&
10811                                 (ip [5] == CEE_BRTRUE || 
10812                                  ip [5] == CEE_BRTRUE_S ||
10813                                  ip [5] == CEE_BRFALSE ||
10814                                  ip [5] == CEE_BRFALSE_S)) {
10815                                 gboolean is_true = ip [5] == CEE_BRTRUE || ip [5] == CEE_BRTRUE_S;
10816                                 int dreg;
10817                                 MonoBasicBlock *true_bb, *false_bb;
10818
10819                                 ip += 5;
10820
10821                                 if (cfg->verbose_level > 3) {
10822                                         printf ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
10823                                         printf ("<box+brtrue opt>\n");
10824                                 }
10825
10826                                 switch (*ip) {
10827                                 case CEE_BRTRUE_S:
10828                                 case CEE_BRFALSE_S:
10829                                         CHECK_OPSIZE (2);
10830                                         ip++;
10831                                         target = ip + 1 + (signed char)(*ip);
10832                                         ip++;
10833                                         break;
10834                                 case CEE_BRTRUE:
10835                                 case CEE_BRFALSE:
10836                                         CHECK_OPSIZE (5);
10837                                         ip++;
10838                                         target = ip + 4 + (gint)(read32 (ip));
10839                                         ip += 4;
10840                                         break;
10841                                 default:
10842                                         g_assert_not_reached ();
10843                                 }
10844
10845                                 /* 
10846                                  * We need to link both bblocks, since it is needed for handling stack
10847                                  * arguments correctly (See test_0_box_brtrue_opt_regress_81102).
10848                                  * Branching to only one of them would lead to inconsistencies, so
10849                                  * generate an ICONST+BRTRUE, the branch opts will get rid of them.
10850                                  */
10851                                 GET_BBLOCK (cfg, true_bb, target);
10852                                 GET_BBLOCK (cfg, false_bb, ip);
10853
10854                                 mono_link_bblock (cfg, cfg->cbb, true_bb);
10855                                 mono_link_bblock (cfg, cfg->cbb, false_bb);
10856
10857                                 if (sp != stack_start) {
10858                                         handle_stack_args (cfg, stack_start, sp - stack_start);
10859                                         sp = stack_start;
10860                                         CHECK_UNVERIFIABLE (cfg);
10861                                 }
10862
10863                                 if (COMPILE_LLVM (cfg)) {
10864                                         dreg = alloc_ireg (cfg);
10865                                         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
10866                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, dreg, is_true ? 0 : 1);
10867
10868                                         MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, OP_IBEQ, true_bb, false_bb);
10869                                 } else {
10870                                         /* The JIT can't eliminate the iconst+compare */
10871                                         MONO_INST_NEW (cfg, ins, OP_BR);
10872                                         ins->inst_target_bb = is_true ? true_bb : false_bb;
10873                                         MONO_ADD_INS (cfg->cbb, ins);
10874                                 }
10875
10876                                 start_new_bblock = 1;
10877                                 break;
10878                         }
10879
10880                         *sp++ = handle_box (cfg, val, klass, context_used);
10881
10882                         CHECK_CFG_EXCEPTION;
10883                         ip += 5;
10884                         inline_costs += 1;
10885                         break;
10886                 }
10887                 case CEE_UNBOX: {
10888                         CHECK_STACK (1);
10889                         --sp;
10890                         CHECK_OPSIZE (5);
10891                         token = read32 (ip + 1);
10892                         klass = mini_get_class (method, token, generic_context);
10893                         CHECK_TYPELOAD (klass);
10894
10895                         mono_save_token_info (cfg, image, token, klass);
10896
10897                         context_used = mini_class_check_context_used (cfg, klass);
10898
10899                         if (mono_class_is_nullable (klass)) {
10900                                 MonoInst *val;
10901
10902                                 val = handle_unbox_nullable (cfg, *sp, klass, context_used);
10903                                 EMIT_NEW_VARLOADA (cfg, ins, get_vreg_to_inst (cfg, val->dreg), &val->klass->byval_arg);
10904
10905                                 *sp++= ins;
10906                         } else {
10907                                 ins = handle_unbox (cfg, klass, sp, context_used);
10908                                 *sp++ = ins;
10909                         }
10910                         ip += 5;
10911                         inline_costs += 2;
10912                         break;
10913                 }
10914                 case CEE_LDFLD:
10915                 case CEE_LDFLDA:
10916                 case CEE_STFLD:
10917                 case CEE_LDSFLD:
10918                 case CEE_LDSFLDA:
10919                 case CEE_STSFLD: {
10920                         MonoClassField *field;
10921 #ifndef DISABLE_REMOTING
10922                         int costs;
10923 #endif
10924                         guint foffset;
10925                         gboolean is_instance;
10926                         int op;
10927                         gpointer addr = NULL;
10928                         gboolean is_special_static;
10929                         MonoType *ftype;
10930                         MonoInst *store_val = NULL;
10931                         MonoInst *thread_ins;
10932
10933                         op = *ip;
10934                         is_instance = (op == CEE_LDFLD || op == CEE_LDFLDA || op == CEE_STFLD);
10935                         if (is_instance) {
10936                                 if (op == CEE_STFLD) {
10937                                         CHECK_STACK (2);
10938                                         sp -= 2;
10939                                         store_val = sp [1];
10940                                 } else {
10941                                         CHECK_STACK (1);
10942                                         --sp;
10943                                 }
10944                                 if (sp [0]->type == STACK_I4 || sp [0]->type == STACK_I8 || sp [0]->type == STACK_R8)
10945                                         UNVERIFIED;
10946                                 if (*ip != CEE_LDFLD && sp [0]->type == STACK_VTYPE)
10947                                         UNVERIFIED;
10948                         } else {
10949                                 if (op == CEE_STSFLD) {
10950                                         CHECK_STACK (1);
10951                                         sp--;
10952                                         store_val = sp [0];
10953                                 }
10954                         }
10955
10956                         CHECK_OPSIZE (5);
10957                         token = read32 (ip + 1);
10958                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
10959                                 field = mono_method_get_wrapper_data (method, token);
10960                                 klass = field->parent;
10961                         }
10962                         else {
10963                                 field = mono_field_from_token_checked (image, token, &klass, generic_context, &cfg->error);
10964                                 CHECK_CFG_ERROR;
10965                         }
10966                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
10967                                 FIELD_ACCESS_FAILURE (method, field);
10968                         mono_class_init (klass);
10969
10970                         /* if the class is Critical then transparent code cannot access it's fields */
10971                         if (!is_instance && mono_security_core_clr_enabled ())
10972                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
10973
10974                         /* XXX this is technically required but, so far (SL2), no [SecurityCritical] types (not many exists) have
10975                            any visible *instance* field  (in fact there's a single case for a static field in Marshal) XXX
10976                         if (mono_security_core_clr_enabled ())
10977                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
10978                         */
10979
10980                         ftype = mono_field_get_type (field);
10981
10982                         /*
10983                          * LDFLD etc. is usable on static fields as well, so convert those cases to
10984                          * the static case.
10985                          */
10986                         if (is_instance && ftype->attrs & FIELD_ATTRIBUTE_STATIC) {
10987                                 switch (op) {
10988                                 case CEE_LDFLD:
10989                                         op = CEE_LDSFLD;
10990                                         break;
10991                                 case CEE_STFLD:
10992                                         op = CEE_STSFLD;
10993                                         break;
10994                                 case CEE_LDFLDA:
10995                                         op = CEE_LDSFLDA;
10996                                         break;
10997                                 default:
10998                                         g_assert_not_reached ();
10999                                 }
11000                                 is_instance = FALSE;
11001                         }
11002
11003                         context_used = mini_class_check_context_used (cfg, klass);
11004
11005                         /* INSTANCE CASE */
11006
11007                         foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
11008                         if (op == CEE_STFLD) {
11009                                 if (target_type_is_incompatible (cfg, field->type, sp [1]))
11010                                         UNVERIFIED;
11011 #ifndef DISABLE_REMOTING
11012                                 if ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class) {
11013                                         MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type); 
11014                                         MonoInst *iargs [5];
11015
11016                                         GSHAREDVT_FAILURE (op);
11017
11018                                         iargs [0] = sp [0];
11019                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11020                                         EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
11021                                         EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : 
11022                                                     field->offset);
11023                                         iargs [4] = sp [1];
11024
11025                                         if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
11026                                                 costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), 
11027                                                                                            iargs, ip, cfg->real_offset, TRUE);
11028                                                 CHECK_CFG_EXCEPTION;
11029                                                 g_assert (costs > 0);
11030                                                       
11031                                                 cfg->real_offset += 5;
11032
11033                                                 inline_costs += costs;
11034                                         } else {
11035                                                 mono_emit_method_call (cfg, stfld_wrapper, iargs, NULL);
11036                                         }
11037                                 } else
11038 #endif
11039                                 {
11040                                         MonoInst *store;
11041
11042                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
11043
11044                                         if (mini_is_gsharedvt_klass (klass)) {
11045                                                 MonoInst *offset_ins;
11046
11047                                                 context_used = mini_class_check_context_used (cfg, klass);
11048
11049                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11050                                                 dreg = alloc_ireg_mp (cfg);
11051                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11052                                                 /* The decomposition will call mini_emit_stobj () which will emit a wbarrier if needed */
11053                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, dreg, 0, sp [1]->dreg);
11054                                         } else {
11055                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, sp [0]->dreg, foffset, sp [1]->dreg);
11056                                         }
11057                                         if (sp [0]->opcode != OP_LDADDR)
11058                                                 store->flags |= MONO_INST_FAULT;
11059
11060                                 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)) {
11061                                         /* insert call to write barrier */
11062                                         MonoInst *ptr;
11063                                         int dreg;
11064
11065                                         dreg = alloc_ireg_mp (cfg);
11066                                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
11067                                         emit_write_barrier (cfg, ptr, sp [1]);
11068                                 }
11069
11070                                         store->flags |= ins_flag;
11071                                 }
11072                                 ins_flag = 0;
11073                                 ip += 5;
11074                                 break;
11075                         }
11076
11077 #ifndef DISABLE_REMOTING
11078                         if (is_instance && ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class)) {
11079                                 MonoMethod *wrapper = (op == CEE_LDFLDA) ? mono_marshal_get_ldflda_wrapper (field->type) : mono_marshal_get_ldfld_wrapper (field->type); 
11080                                 MonoInst *iargs [4];
11081
11082                                 GSHAREDVT_FAILURE (op);
11083
11084                                 iargs [0] = sp [0];
11085                                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11086                                 EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
11087                                 EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
11088                                 if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
11089                                         costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), 
11090                                                                                    iargs, ip, cfg->real_offset, TRUE);
11091                                         CHECK_CFG_EXCEPTION;
11092                                         g_assert (costs > 0);
11093                                                       
11094                                         cfg->real_offset += 5;
11095
11096                                         *sp++ = iargs [0];
11097
11098                                         inline_costs += costs;
11099                                 } else {
11100                                         ins = mono_emit_method_call (cfg, wrapper, iargs, NULL);
11101                                         *sp++ = ins;
11102                                 }
11103                         } else 
11104 #endif
11105                         if (is_instance) {
11106                                 if (sp [0]->type == STACK_VTYPE) {
11107                                         MonoInst *var;
11108
11109                                         /* Have to compute the address of the variable */
11110
11111                                         var = get_vreg_to_inst (cfg, sp [0]->dreg);
11112                                         if (!var)
11113                                                 var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, sp [0]->dreg);
11114                                         else
11115                                                 g_assert (var->klass == klass);
11116                                         
11117                                         EMIT_NEW_VARLOADA (cfg, ins, var, &var->klass->byval_arg);
11118                                         sp [0] = ins;
11119                                 }
11120
11121                                 if (op == CEE_LDFLDA) {
11122                                         if (sp [0]->type == STACK_OBJ) {
11123                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
11124                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "NullReferenceException");
11125                                         }
11126
11127                                         dreg = alloc_ireg_mp (cfg);
11128
11129                                         if (mini_is_gsharedvt_klass (klass)) {
11130                                                 MonoInst *offset_ins;
11131
11132                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11133                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11134                                         } else {
11135                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
11136                                         }
11137                                         ins->klass = mono_class_from_mono_type (field->type);
11138                                         ins->type = STACK_MP;
11139                                         *sp++ = ins;
11140                                 } else {
11141                                         MonoInst *load;
11142
11143                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
11144
11145                                         if (mini_is_gsharedvt_klass (klass)) {
11146                                                 MonoInst *offset_ins;
11147
11148                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11149                                                 dreg = alloc_ireg_mp (cfg);
11150                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11151                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, dreg, 0);
11152                                         } else {
11153                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, sp [0]->dreg, foffset);
11154                                         }
11155                                         load->flags |= ins_flag;
11156                                         if (sp [0]->opcode != OP_LDADDR)
11157                                                 load->flags |= MONO_INST_FAULT;
11158                                         *sp++ = load;
11159                                 }
11160                         }
11161
11162                         if (is_instance) {
11163                                 ins_flag = 0;
11164                                 ip += 5;
11165                                 break;
11166                         }
11167
11168                         /* STATIC CASE */
11169                         context_used = mini_class_check_context_used (cfg, klass);
11170
11171                         if (ftype->attrs & FIELD_ATTRIBUTE_LITERAL)
11172                                 UNVERIFIED;
11173
11174                         /* The special_static_fields field is init'd in mono_class_vtable, so it needs
11175                          * to be called here.
11176                          */
11177                         if (!context_used && !(cfg->opt & MONO_OPT_SHARED)) {
11178                                 mono_class_vtable (cfg->domain, klass);
11179                                 CHECK_TYPELOAD (klass);
11180                         }
11181                         mono_domain_lock (cfg->domain);
11182                         if (cfg->domain->special_static_fields)
11183                                 addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
11184                         mono_domain_unlock (cfg->domain);
11185
11186                         is_special_static = mono_class_field_is_special_static (field);
11187
11188                         if (is_special_static && ((gsize)addr & 0x80000000) == 0)
11189                                 thread_ins = mono_get_thread_intrinsic (cfg);
11190                         else
11191                                 thread_ins = NULL;
11192
11193                         /* Generate IR to compute the field address */
11194                         if (is_special_static && ((gsize)addr & 0x80000000) == 0 && thread_ins && !(cfg->opt & MONO_OPT_SHARED) && !context_used) {
11195                                 /*
11196                                  * Fast access to TLS data
11197                                  * Inline version of get_thread_static_data () in
11198                                  * threads.c.
11199                                  */
11200                                 guint32 offset;
11201                                 int idx, static_data_reg, array_reg, dreg;
11202
11203                                 GSHAREDVT_FAILURE (op);
11204
11205                                 MONO_ADD_INS (cfg->cbb, thread_ins);
11206                                 static_data_reg = alloc_ireg (cfg);
11207                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, MONO_STRUCT_OFFSET (MonoInternalThread, static_data));
11208
11209                                 if (cfg->compile_aot) {
11210                                         int offset_reg, offset2_reg, idx_reg;
11211
11212                                         /* For TLS variables, this will return the TLS offset */
11213                                         EMIT_NEW_SFLDACONST (cfg, ins, field);
11214                                         offset_reg = ins->dreg;
11215                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset_reg, offset_reg, 0x7fffffff);
11216                                         idx_reg = alloc_ireg (cfg);
11217                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, idx_reg, offset_reg, 0x3f);
11218                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
11219                                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
11220                                         array_reg = alloc_ireg (cfg);
11221                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
11222                                         offset2_reg = alloc_ireg (cfg);
11223                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, offset2_reg, offset_reg, 6);
11224                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset2_reg, 0x1ffffff);
11225                                         dreg = alloc_ireg (cfg);
11226                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, array_reg, offset2_reg);
11227                                 } else {
11228                                         offset = (gsize)addr & 0x7fffffff;
11229                                         idx = offset & 0x3f;
11230
11231                                         array_reg = alloc_ireg (cfg);
11232                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, idx * sizeof (gpointer));
11233                                         dreg = alloc_ireg (cfg);
11234                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_ADD_IMM, dreg, array_reg, ((offset >> 6) & 0x1ffffff));
11235                                 }
11236                         } else if ((cfg->opt & MONO_OPT_SHARED) ||
11237                                         (cfg->compile_aot && is_special_static) ||
11238                                         (context_used && is_special_static)) {
11239                                 MonoInst *iargs [2];
11240
11241                                 g_assert (field->parent);
11242                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11243                                 if (context_used) {
11244                                         iargs [1] = emit_get_rgctx_field (cfg, context_used,
11245                                                 field, MONO_RGCTX_INFO_CLASS_FIELD);
11246                                 } else {
11247                                         EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
11248                                 }
11249                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
11250                         } else if (context_used) {
11251                                 MonoInst *static_data;
11252
11253                                 /*
11254                                 g_print ("sharing static field access in %s.%s.%s - depth %d offset %d\n",
11255                                         method->klass->name_space, method->klass->name, method->name,
11256                                         depth, field->offset);
11257                                 */
11258
11259                                 if (mono_class_needs_cctor_run (klass, method))
11260                                         emit_class_init (cfg, klass);
11261
11262                                 /*
11263                                  * The pointer we're computing here is
11264                                  *
11265                                  *   super_info.static_data + field->offset
11266                                  */
11267                                 static_data = emit_get_rgctx_klass (cfg, context_used,
11268                                         klass, MONO_RGCTX_INFO_STATIC_DATA);
11269
11270                                 if (mini_is_gsharedvt_klass (klass)) {
11271                                         MonoInst *offset_ins;
11272
11273                                         offset_ins = emit_get_rgctx_field (cfg, context_used, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11274                                         dreg = alloc_ireg_mp (cfg);
11275                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, static_data->dreg, offset_ins->dreg);
11276                                 } else if (field->offset == 0) {
11277                                         ins = static_data;
11278                                 } else {
11279                                         int addr_reg = mono_alloc_preg (cfg);
11280                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, addr_reg, static_data->dreg, field->offset);
11281                                 }
11282                                 } else if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
11283                                 MonoInst *iargs [2];
11284
11285                                 g_assert (field->parent);
11286                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11287                                 EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
11288                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
11289                         } else {
11290                                 MonoVTable *vtable = NULL;
11291
11292                                 if (!cfg->compile_aot)
11293                                         vtable = mono_class_vtable (cfg->domain, klass);
11294                                 CHECK_TYPELOAD (klass);
11295
11296                                 if (!addr) {
11297                                         if (mini_field_access_needs_cctor_run (cfg, method, klass, vtable)) {
11298                                                 if (!(g_slist_find (class_inits, klass))) {
11299                                                         emit_class_init (cfg, klass);
11300                                                         if (cfg->verbose_level > 2)
11301                                                                 printf ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, mono_field_get_name (field));
11302                                                         class_inits = g_slist_prepend (class_inits, klass);
11303                                                 }
11304                                         } else {
11305                                                 if (cfg->run_cctors) {
11306                                                         MonoException *ex;
11307                                                         /* This makes so that inline cannot trigger */
11308                                                         /* .cctors: too many apps depend on them */
11309                                                         /* running with a specific order... */
11310                                                         g_assert (vtable);
11311                                                         if (! vtable->initialized)
11312                                                                 INLINE_FAILURE ("class init");
11313                                                         ex = mono_runtime_class_init_full (vtable, FALSE);
11314                                                         if (ex) {
11315                                                                 set_exception_object (cfg, ex);
11316                                                                 goto exception_exit;
11317                                                         }
11318                                                 }
11319                                         }
11320                                         if (cfg->compile_aot)
11321                                                 EMIT_NEW_SFLDACONST (cfg, ins, field);
11322                                         else {
11323                                                 g_assert (vtable);
11324                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11325                                                 g_assert (addr);
11326                                                 EMIT_NEW_PCONST (cfg, ins, addr);
11327                                         }
11328                                 } else {
11329                                         MonoInst *iargs [1];
11330                                         EMIT_NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
11331                                         ins = mono_emit_jit_icall (cfg, mono_get_special_static_data, iargs);
11332                                 }
11333                         }
11334
11335                         /* Generate IR to do the actual load/store operation */
11336
11337                         if ((op == CEE_STFLD || op == CEE_STSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11338                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11339                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11340                         }
11341
11342                         if (op == CEE_LDSFLDA) {
11343                                 ins->klass = mono_class_from_mono_type (ftype);
11344                                 ins->type = STACK_PTR;
11345                                 *sp++ = ins;
11346                         } else if (op == CEE_STSFLD) {
11347                                 MonoInst *store;
11348
11349                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, ftype, ins->dreg, 0, store_val->dreg);
11350                                 store->flags |= ins_flag;
11351                         } else {
11352                                 gboolean is_const = FALSE;
11353                                 MonoVTable *vtable = NULL;
11354                                 gpointer addr = NULL;
11355
11356                                 if (!context_used) {
11357                                         vtable = mono_class_vtable (cfg->domain, klass);
11358                                         CHECK_TYPELOAD (klass);
11359                                 }
11360                                 if ((ftype->attrs & FIELD_ATTRIBUTE_INIT_ONLY) && (((addr = mono_aot_readonly_field_override (field)) != NULL) ||
11361                                                 (!context_used && !((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && vtable->initialized))) {
11362                                         int ro_type = ftype->type;
11363                                         if (!addr)
11364                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11365                                         if (ro_type == MONO_TYPE_VALUETYPE && ftype->data.klass->enumtype) {
11366                                                 ro_type = mono_class_enum_basetype (ftype->data.klass)->type;
11367                                         }
11368
11369                                         GSHAREDVT_FAILURE (op);
11370
11371                                         /* printf ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, mono_field_get_name (field));*/
11372                                         is_const = TRUE;
11373                                         switch (ro_type) {
11374                                         case MONO_TYPE_BOOLEAN:
11375                                         case MONO_TYPE_U1:
11376                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint8 *)addr));
11377                                                 sp++;
11378                                                 break;
11379                                         case MONO_TYPE_I1:
11380                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint8 *)addr));
11381                                                 sp++;
11382                                                 break;                                          
11383                                         case MONO_TYPE_CHAR:
11384                                         case MONO_TYPE_U2:
11385                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint16 *)addr));
11386                                                 sp++;
11387                                                 break;
11388                                         case MONO_TYPE_I2:
11389                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint16 *)addr));
11390                                                 sp++;
11391                                                 break;
11392                                                 break;
11393                                         case MONO_TYPE_I4:
11394                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint32 *)addr));
11395                                                 sp++;
11396                                                 break;                                          
11397                                         case MONO_TYPE_U4:
11398                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint32 *)addr));
11399                                                 sp++;
11400                                                 break;
11401                                         case MONO_TYPE_I:
11402                                         case MONO_TYPE_U:
11403                                         case MONO_TYPE_PTR:
11404                                         case MONO_TYPE_FNPTR:
11405                                                 EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11406                                                 type_to_eval_stack_type ((cfg), field->type, *sp);
11407                                                 sp++;
11408                                                 break;
11409                                         case MONO_TYPE_STRING:
11410                                         case MONO_TYPE_OBJECT:
11411                                         case MONO_TYPE_CLASS:
11412                                         case MONO_TYPE_SZARRAY:
11413                                         case MONO_TYPE_ARRAY:
11414                                                 if (!mono_gc_is_moving ()) {
11415                                                         EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11416                                                         type_to_eval_stack_type ((cfg), field->type, *sp);
11417                                                         sp++;
11418                                                 } else {
11419                                                         is_const = FALSE;
11420                                                 }
11421                                                 break;
11422                                         case MONO_TYPE_I8:
11423                                         case MONO_TYPE_U8:
11424                                                 EMIT_NEW_I8CONST (cfg, *sp, *((gint64 *)addr));
11425                                                 sp++;
11426                                                 break;
11427                                         case MONO_TYPE_R4:
11428                                         case MONO_TYPE_R8:
11429                                         case MONO_TYPE_VALUETYPE:
11430                                         default:
11431                                                 is_const = FALSE;
11432                                                 break;
11433                                         }
11434                                 }
11435
11436                                 if (!is_const) {
11437                                         MonoInst *load;
11438
11439                                         CHECK_STACK_OVF (1);
11440
11441                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, ins->dreg, 0);
11442                                         load->flags |= ins_flag;
11443                                         ins_flag = 0;
11444                                         *sp++ = load;
11445                                 }
11446                         }
11447
11448                         if ((op == CEE_LDFLD || op == CEE_LDSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11449                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
11450                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
11451                         }
11452
11453                         ins_flag = 0;
11454                         ip += 5;
11455                         break;
11456                 }
11457                 case CEE_STOBJ:
11458                         CHECK_STACK (2);
11459                         sp -= 2;
11460                         CHECK_OPSIZE (5);
11461                         token = read32 (ip + 1);
11462                         klass = mini_get_class (method, token, generic_context);
11463                         CHECK_TYPELOAD (klass);
11464                         if (ins_flag & MONO_INST_VOLATILE) {
11465                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11466                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11467                         }
11468                         /* FIXME: should check item at sp [1] is compatible with the type of the store. */
11469                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0, sp [1]->dreg);
11470                         ins->flags |= ins_flag;
11471                         if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER &&
11472                                         generic_class_is_reference_type (cfg, klass)) {
11473                                 /* insert call to write barrier */
11474                                 emit_write_barrier (cfg, sp [0], sp [1]);
11475                         }
11476                         ins_flag = 0;
11477                         ip += 5;
11478                         inline_costs += 1;
11479                         break;
11480
11481                         /*
11482                          * Array opcodes
11483                          */
11484                 case CEE_NEWARR: {
11485                         MonoInst *len_ins;
11486                         const char *data_ptr;
11487                         int data_size = 0;
11488                         guint32 field_token;
11489
11490                         CHECK_STACK (1);
11491                         --sp;
11492
11493                         CHECK_OPSIZE (5);
11494                         token = read32 (ip + 1);
11495
11496                         klass = mini_get_class (method, token, generic_context);
11497                         CHECK_TYPELOAD (klass);
11498
11499                         context_used = mini_class_check_context_used (cfg, klass);
11500
11501                         if (sp [0]->type == STACK_I8 || (SIZEOF_VOID_P == 8 && sp [0]->type == STACK_PTR)) {
11502                                 MONO_INST_NEW (cfg, ins, OP_LCONV_TO_OVF_U4);
11503                                 ins->sreg1 = sp [0]->dreg;
11504                                 ins->type = STACK_I4;
11505                                 ins->dreg = alloc_ireg (cfg);
11506                                 MONO_ADD_INS (cfg->cbb, ins);
11507                                 *sp = mono_decompose_opcode (cfg, ins);
11508                         }
11509
11510                         if (context_used) {
11511                                 MonoInst *args [3];
11512                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11513                                 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
11514
11515                                 /* FIXME: Use OP_NEWARR and decompose later to help abcrem */
11516
11517                                 /* vtable */
11518                                 args [0] = emit_get_rgctx_klass (cfg, context_used,
11519                                         array_class, MONO_RGCTX_INFO_VTABLE);
11520                                 /* array len */
11521                                 args [1] = sp [0];
11522
11523                                 if (managed_alloc)
11524                                         ins = mono_emit_method_call (cfg, managed_alloc, args, NULL);
11525                                 else
11526                                         ins = mono_emit_jit_icall (cfg, mono_array_new_specific, args);
11527                         } else {
11528                                 if (cfg->opt & MONO_OPT_SHARED) {
11529                                         /* Decompose now to avoid problems with references to the domainvar */
11530                                         MonoInst *iargs [3];
11531
11532                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11533                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11534                                         iargs [2] = sp [0];
11535
11536                                         ins = mono_emit_jit_icall (cfg, mono_array_new, iargs);
11537                                 } else {
11538                                         /* Decompose later since it is needed by abcrem */
11539                                         MonoClass *array_type = mono_array_class_get (klass, 1);
11540                                         mono_class_vtable (cfg->domain, array_type);
11541                                         CHECK_TYPELOAD (array_type);
11542
11543                                         MONO_INST_NEW (cfg, ins, OP_NEWARR);
11544                                         ins->dreg = alloc_ireg_ref (cfg);
11545                                         ins->sreg1 = sp [0]->dreg;
11546                                         ins->inst_newa_class = klass;
11547                                         ins->type = STACK_OBJ;
11548                                         ins->klass = array_type;
11549                                         MONO_ADD_INS (cfg->cbb, ins);
11550                                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11551                                         cfg->cbb->has_array_access = TRUE;
11552
11553                                         /* Needed so mono_emit_load_get_addr () gets called */
11554                                         mono_get_got_var (cfg);
11555                                 }
11556                         }
11557
11558                         len_ins = sp [0];
11559                         ip += 5;
11560                         *sp++ = ins;
11561                         inline_costs += 1;
11562
11563                         /* 
11564                          * we inline/optimize the initialization sequence if possible.
11565                          * we should also allocate the array as not cleared, since we spend as much time clearing to 0 as initializing
11566                          * for small sizes open code the memcpy
11567                          * ensure the rva field is big enough
11568                          */
11569                         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))) {
11570                                 MonoMethod *memcpy_method = get_memcpy_method ();
11571                                 MonoInst *iargs [3];
11572                                 int add_reg = alloc_ireg_mp (cfg);
11573
11574                                 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, add_reg, ins->dreg, MONO_STRUCT_OFFSET (MonoArray, vector));
11575                                 if (cfg->compile_aot) {
11576                                         EMIT_NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(field_token), STACK_PTR, NULL);
11577                                 } else {
11578                                         EMIT_NEW_PCONST (cfg, iargs [1], (char*)data_ptr);
11579                                 }
11580                                 EMIT_NEW_ICONST (cfg, iargs [2], data_size);
11581                                 mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
11582                                 ip += 11;
11583                         }
11584
11585                         break;
11586                 }
11587                 case CEE_LDLEN:
11588                         CHECK_STACK (1);
11589                         --sp;
11590                         if (sp [0]->type != STACK_OBJ)
11591                                 UNVERIFIED;
11592
11593                         MONO_INST_NEW (cfg, ins, OP_LDLEN);
11594                         ins->dreg = alloc_preg (cfg);
11595                         ins->sreg1 = sp [0]->dreg;
11596                         ins->type = STACK_I4;
11597                         /* This flag will be inherited by the decomposition */
11598                         ins->flags |= MONO_INST_FAULT;
11599                         MONO_ADD_INS (cfg->cbb, ins);
11600                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11601                         cfg->cbb->has_array_access = TRUE;
11602                         ip ++;
11603                         *sp++ = ins;
11604                         break;
11605                 case CEE_LDELEMA:
11606                         CHECK_STACK (2);
11607                         sp -= 2;
11608                         CHECK_OPSIZE (5);
11609                         if (sp [0]->type != STACK_OBJ)
11610                                 UNVERIFIED;
11611
11612                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11613
11614                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11615                         CHECK_TYPELOAD (klass);
11616                         /* we need to make sure that this array is exactly the type it needs
11617                          * to be for correctness. the wrappers are lax with their usage
11618                          * so we need to ignore them here
11619                          */
11620                         if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE && !readonly) {
11621                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11622                                 mini_emit_check_array_type (cfg, sp [0], array_class);
11623                                 CHECK_TYPELOAD (array_class);
11624                         }
11625
11626                         readonly = FALSE;
11627                         ins = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11628                         *sp++ = ins;
11629                         ip += 5;
11630                         break;
11631                 case CEE_LDELEM:
11632                 case CEE_LDELEM_I1:
11633                 case CEE_LDELEM_U1:
11634                 case CEE_LDELEM_I2:
11635                 case CEE_LDELEM_U2:
11636                 case CEE_LDELEM_I4:
11637                 case CEE_LDELEM_U4:
11638                 case CEE_LDELEM_I8:
11639                 case CEE_LDELEM_I:
11640                 case CEE_LDELEM_R4:
11641                 case CEE_LDELEM_R8:
11642                 case CEE_LDELEM_REF: {
11643                         MonoInst *addr;
11644
11645                         CHECK_STACK (2);
11646                         sp -= 2;
11647
11648                         if (*ip == CEE_LDELEM) {
11649                                 CHECK_OPSIZE (5);
11650                                 token = read32 (ip + 1);
11651                                 klass = mini_get_class (method, token, generic_context);
11652                                 CHECK_TYPELOAD (klass);
11653                                 mono_class_init (klass);
11654                         }
11655                         else
11656                                 klass = array_access_to_klass (*ip);
11657
11658                         if (sp [0]->type != STACK_OBJ)
11659                                 UNVERIFIED;
11660
11661                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11662
11663                         if (mini_is_gsharedvt_variable_klass (klass)) {
11664                                 // FIXME-VT: OP_ICONST optimization
11665                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11666                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11667                                 ins->opcode = OP_LOADV_MEMBASE;
11668                         } else if (sp [1]->opcode == OP_ICONST) {
11669                                 int array_reg = sp [0]->dreg;
11670                                 int index_reg = sp [1]->dreg;
11671                                 int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
11672
11673                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
11674                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset);
11675                         } else {
11676                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11677                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11678                         }
11679                         *sp++ = ins;
11680                         if (*ip == CEE_LDELEM)
11681                                 ip += 5;
11682                         else
11683                                 ++ip;
11684                         break;
11685                 }
11686                 case CEE_STELEM_I:
11687                 case CEE_STELEM_I1:
11688                 case CEE_STELEM_I2:
11689                 case CEE_STELEM_I4:
11690                 case CEE_STELEM_I8:
11691                 case CEE_STELEM_R4:
11692                 case CEE_STELEM_R8:
11693                 case CEE_STELEM_REF:
11694                 case CEE_STELEM: {
11695                         CHECK_STACK (3);
11696                         sp -= 3;
11697
11698                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11699
11700                         if (*ip == CEE_STELEM) {
11701                                 CHECK_OPSIZE (5);
11702                                 token = read32 (ip + 1);
11703                                 klass = mini_get_class (method, token, generic_context);
11704                                 CHECK_TYPELOAD (klass);
11705                                 mono_class_init (klass);
11706                         }
11707                         else
11708                                 klass = array_access_to_klass (*ip);
11709
11710                         if (sp [0]->type != STACK_OBJ)
11711                                 UNVERIFIED;
11712
11713                         emit_array_store (cfg, klass, sp, TRUE);
11714
11715                         if (*ip == CEE_STELEM)
11716                                 ip += 5;
11717                         else
11718                                 ++ip;
11719                         inline_costs += 1;
11720                         break;
11721                 }
11722                 case CEE_CKFINITE: {
11723                         CHECK_STACK (1);
11724                         --sp;
11725
11726                         MONO_INST_NEW (cfg, ins, OP_CKFINITE);
11727                         ins->sreg1 = sp [0]->dreg;
11728                         ins->dreg = alloc_freg (cfg);
11729                         ins->type = STACK_R8;
11730                         MONO_ADD_INS (cfg->cbb, ins);
11731
11732                         *sp++ = mono_decompose_opcode (cfg, ins);
11733
11734                         ++ip;
11735                         break;
11736                 }
11737                 case CEE_REFANYVAL: {
11738                         MonoInst *src_var, *src;
11739
11740                         int klass_reg = alloc_preg (cfg);
11741                         int dreg = alloc_preg (cfg);
11742
11743                         GSHAREDVT_FAILURE (*ip);
11744
11745                         CHECK_STACK (1);
11746                         MONO_INST_NEW (cfg, ins, *ip);
11747                         --sp;
11748                         CHECK_OPSIZE (5);
11749                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11750                         CHECK_TYPELOAD (klass);
11751
11752                         context_used = mini_class_check_context_used (cfg, klass);
11753
11754                         // FIXME:
11755                         src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
11756                         if (!src_var)
11757                                 src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
11758                         EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
11759                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass));
11760
11761                         if (context_used) {
11762                                 MonoInst *klass_ins;
11763
11764                                 klass_ins = emit_get_rgctx_klass (cfg, context_used,
11765                                                 klass, MONO_RGCTX_INFO_KLASS);
11766
11767                                 // FIXME:
11768                                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_ins->dreg);
11769                                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
11770                         } else {
11771                                 mini_emit_class_check (cfg, klass_reg, klass);
11772                         }
11773                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value));
11774                         ins->type = STACK_MP;
11775                         ins->klass = klass;
11776                         *sp++ = ins;
11777                         ip += 5;
11778                         break;
11779                 }
11780                 case CEE_MKREFANY: {
11781                         MonoInst *loc, *addr;
11782
11783                         GSHAREDVT_FAILURE (*ip);
11784
11785                         CHECK_STACK (1);
11786                         MONO_INST_NEW (cfg, ins, *ip);
11787                         --sp;
11788                         CHECK_OPSIZE (5);
11789                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11790                         CHECK_TYPELOAD (klass);
11791
11792                         context_used = mini_class_check_context_used (cfg, klass);
11793
11794                         loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
11795                         EMIT_NEW_TEMPLOADA (cfg, addr, loc->inst_c0);
11796
11797                         if (context_used) {
11798                                 MonoInst *const_ins;
11799                                 int type_reg = alloc_preg (cfg);
11800
11801                                 const_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
11802                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_ins->dreg);
11803                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_ins->dreg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
11804                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
11805                         } else if (cfg->compile_aot) {
11806                                 int const_reg = alloc_preg (cfg);
11807                                 int type_reg = alloc_preg (cfg);
11808
11809                                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
11810                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_reg);
11811                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_reg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
11812                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
11813                         } else {
11814                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), &klass->byval_arg);
11815                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), klass);
11816                         }
11817                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value), sp [0]->dreg);
11818
11819                         EMIT_NEW_TEMPLOAD (cfg, ins, loc->inst_c0);
11820                         ins->type = STACK_VTYPE;
11821                         ins->klass = mono_defaults.typed_reference_class;
11822                         *sp++ = ins;
11823                         ip += 5;
11824                         break;
11825                 }
11826                 case CEE_LDTOKEN: {
11827                         gpointer handle;
11828                         MonoClass *handle_class;
11829
11830                         CHECK_STACK_OVF (1);
11831
11832                         CHECK_OPSIZE (5);
11833                         n = read32 (ip + 1);
11834
11835                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD ||
11836                                         method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
11837                                 handle = mono_method_get_wrapper_data (method, n);
11838                                 handle_class = mono_method_get_wrapper_data (method, n + 1);
11839                                 if (handle_class == mono_defaults.typehandle_class)
11840                                         handle = &((MonoClass*)handle)->byval_arg;
11841                         }
11842                         else {
11843                                 handle = mono_ldtoken_checked (image, n, &handle_class, generic_context, &cfg->error);
11844                                 CHECK_CFG_ERROR;
11845                         }
11846                         if (!handle)
11847                                 LOAD_ERROR;
11848                         mono_class_init (handle_class);
11849                         if (cfg->gshared) {
11850                                 if (mono_metadata_token_table (n) == MONO_TABLE_TYPEDEF ||
11851                                                 mono_metadata_token_table (n) == MONO_TABLE_TYPEREF) {
11852                                         /* This case handles ldtoken
11853                                            of an open type, like for
11854                                            typeof(Gen<>). */
11855                                         context_used = 0;
11856                                 } else if (handle_class == mono_defaults.typehandle_class) {
11857                                         context_used = mini_class_check_context_used (cfg, mono_class_from_mono_type (handle));
11858                                 } else if (handle_class == mono_defaults.fieldhandle_class)
11859                                         context_used = mini_class_check_context_used (cfg, ((MonoClassField*)handle)->parent);
11860                                 else if (handle_class == mono_defaults.methodhandle_class)
11861                                         context_used = mini_method_check_context_used (cfg, handle);
11862                                 else
11863                                         g_assert_not_reached ();
11864                         }
11865
11866                         if ((cfg->opt & MONO_OPT_SHARED) &&
11867                                         method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD &&
11868                                         method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED) {
11869                                 MonoInst *addr, *vtvar, *iargs [3];
11870                                 int method_context_used;
11871
11872                                 method_context_used = mini_method_check_context_used (cfg, method);
11873
11874                                 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL); 
11875
11876                                 EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
11877                                 EMIT_NEW_ICONST (cfg, iargs [1], n);
11878                                 if (method_context_used) {
11879                                         iargs [2] = emit_get_rgctx_method (cfg, method_context_used,
11880                                                 method, MONO_RGCTX_INFO_METHOD);
11881                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper_generic_shared, iargs);
11882                                 } else {
11883                                         EMIT_NEW_PCONST (cfg, iargs [2], generic_context);
11884                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper, iargs);
11885                                 }
11886                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
11887
11888                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
11889
11890                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
11891                         } else {
11892                                 if ((ip + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 5) && 
11893                                         ((ip [5] == CEE_CALL) || (ip [5] == CEE_CALLVIRT)) && 
11894                                         (cmethod = mini_get_method (cfg, method, read32 (ip + 6), NULL, generic_context)) &&
11895                                         (cmethod->klass == mono_defaults.systemtype_class) &&
11896                                         (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
11897                                         MonoClass *tclass = mono_class_from_mono_type (handle);
11898
11899                                         mono_class_init (tclass);
11900                                         if (context_used) {
11901                                                 ins = emit_get_rgctx_klass (cfg, context_used,
11902                                                         tclass, MONO_RGCTX_INFO_REFLECTION_TYPE);
11903                                         } else if (cfg->compile_aot) {
11904                                                 if (method->wrapper_type) {
11905                                                         mono_error_init (&error); //got to do it since there are multiple conditionals below
11906                                                         if (mono_class_get_checked (tclass->image, tclass->type_token, &error) == tclass && !generic_context) {
11907                                                                 /* Special case for static synchronized wrappers */
11908                                                                 EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, tclass->image, tclass->type_token, generic_context);
11909                                                         } else {
11910                                                                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
11911                                                                 /* FIXME: n is not a normal token */
11912                                                                 DISABLE_AOT (cfg);
11913                                                                 EMIT_NEW_PCONST (cfg, ins, NULL);
11914                                                         }
11915                                                 } else {
11916                                                         EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n, generic_context);
11917                                                 }
11918                                         } else {
11919                                                 EMIT_NEW_PCONST (cfg, ins, mono_type_get_object (cfg->domain, handle));
11920                                         }
11921                                         ins->type = STACK_OBJ;
11922                                         ins->klass = cmethod->klass;
11923                                         ip += 5;
11924                                 } else {
11925                                         MonoInst *addr, *vtvar;
11926
11927                                         vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
11928
11929                                         if (context_used) {
11930                                                 if (handle_class == mono_defaults.typehandle_class) {
11931                                                         ins = emit_get_rgctx_klass (cfg, context_used,
11932                                                                         mono_class_from_mono_type (handle),
11933                                                                         MONO_RGCTX_INFO_TYPE);
11934                                                 } else if (handle_class == mono_defaults.methodhandle_class) {
11935                                                         ins = emit_get_rgctx_method (cfg, context_used,
11936                                                                         handle, MONO_RGCTX_INFO_METHOD);
11937                                                 } else if (handle_class == mono_defaults.fieldhandle_class) {
11938                                                         ins = emit_get_rgctx_field (cfg, context_used,
11939                                                                         handle, MONO_RGCTX_INFO_CLASS_FIELD);
11940                                                 } else {
11941                                                         g_assert_not_reached ();
11942                                                 }
11943                                         } else if (cfg->compile_aot) {
11944                                                 EMIT_NEW_LDTOKENCONST (cfg, ins, image, n, generic_context);
11945                                         } else {
11946                                                 EMIT_NEW_PCONST (cfg, ins, handle);
11947                                         }
11948                                         EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
11949                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
11950                                         EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
11951                                 }
11952                         }
11953
11954                         *sp++ = ins;
11955                         ip += 5;
11956                         break;
11957                 }
11958                 case CEE_THROW:
11959                         CHECK_STACK (1);
11960                         MONO_INST_NEW (cfg, ins, OP_THROW);
11961                         --sp;
11962                         ins->sreg1 = sp [0]->dreg;
11963                         ip++;
11964                         cfg->cbb->out_of_line = TRUE;
11965                         MONO_ADD_INS (cfg->cbb, ins);
11966                         MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
11967                         MONO_ADD_INS (cfg->cbb, ins);
11968                         sp = stack_start;
11969                         
11970                         link_bblock (cfg, cfg->cbb, end_bblock);
11971                         start_new_bblock = 1;
11972                         break;
11973                 case CEE_ENDFINALLY:
11974                         /* mono_save_seq_point_info () depends on this */
11975                         if (sp != stack_start)
11976                                 emit_seq_point (cfg, method, ip, FALSE, FALSE);
11977                         MONO_INST_NEW (cfg, ins, OP_ENDFINALLY);
11978                         MONO_ADD_INS (cfg->cbb, ins);
11979                         ip++;
11980                         start_new_bblock = 1;
11981
11982                         /*
11983                          * Control will leave the method so empty the stack, otherwise
11984                          * the next basic block will start with a nonempty stack.
11985                          */
11986                         while (sp != stack_start) {
11987                                 sp--;
11988                         }
11989                         break;
11990                 case CEE_LEAVE:
11991                 case CEE_LEAVE_S: {
11992                         GList *handlers;
11993
11994                         if (*ip == CEE_LEAVE) {
11995                                 CHECK_OPSIZE (5);
11996                                 target = ip + 5 + (gint32)read32(ip + 1);
11997                         } else {
11998                                 CHECK_OPSIZE (2);
11999                                 target = ip + 2 + (signed char)(ip [1]);
12000                         }
12001
12002                         /* empty the stack */
12003                         while (sp != stack_start) {
12004                                 sp--;
12005                         }
12006
12007                         /* 
12008                          * If this leave statement is in a catch block, check for a
12009                          * pending exception, and rethrow it if necessary.
12010                          * We avoid doing this in runtime invoke wrappers, since those are called
12011                          * by native code which excepts the wrapper to catch all exceptions.
12012                          */
12013                         for (i = 0; i < header->num_clauses; ++i) {
12014                                 MonoExceptionClause *clause = &header->clauses [i];
12015
12016                                 /* 
12017                                  * Use <= in the final comparison to handle clauses with multiple
12018                                  * leave statements, like in bug #78024.
12019                                  * The ordering of the exception clauses guarantees that we find the
12020                                  * innermost clause.
12021                                  */
12022                                 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) {
12023                                         MonoInst *exc_ins;
12024                                         MonoBasicBlock *dont_throw;
12025
12026                                         /*
12027                                           MonoInst *load;
12028
12029                                           NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, clause->handler_offset)->inst_c0);
12030                                         */
12031
12032                                         exc_ins = mono_emit_jit_icall (cfg, mono_thread_get_undeniable_exception, NULL);
12033
12034                                         NEW_BBLOCK (cfg, dont_throw);
12035
12036                                         /*
12037                                          * Currently, we always rethrow the abort exception, despite the 
12038                                          * fact that this is not correct. See thread6.cs for an example. 
12039                                          * But propagating the abort exception is more important than 
12040                                          * getting the sematics right.
12041                                          */
12042                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, exc_ins->dreg, 0);
12043                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, dont_throw);
12044                                         MONO_EMIT_NEW_UNALU (cfg, OP_THROW, -1, exc_ins->dreg);
12045
12046                                         MONO_START_BB (cfg, dont_throw);
12047                                 }
12048                         }
12049
12050                         cfg->cbb->try_end = (intptr_t)(ip - header->code);
12051
12052                         if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
12053                                 GList *tmp;
12054                                 MonoExceptionClause *clause;
12055
12056                                 for (tmp = handlers; tmp; tmp = tmp->next) {
12057                                         clause = tmp->data;
12058                                         tblock = cfg->cil_offset_to_bb [clause->handler_offset];
12059                                         g_assert (tblock);
12060                                         link_bblock (cfg, cfg->cbb, tblock);
12061                                         MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
12062                                         ins->inst_target_bb = tblock;
12063                                         ins->inst_eh_block = clause;
12064                                         MONO_ADD_INS (cfg->cbb, ins);
12065                                         cfg->cbb->has_call_handler = 1;
12066                                         if (COMPILE_LLVM (cfg)) {
12067                                                 MonoBasicBlock *target_bb;
12068
12069                                                 /* 
12070                                                  * Link the finally bblock with the target, since it will
12071                                                  * conceptually branch there.
12072                                                  * FIXME: Have to link the bblock containing the endfinally.
12073                                                  */
12074                                                 GET_BBLOCK (cfg, target_bb, target);
12075                                                 link_bblock (cfg, tblock, target_bb);
12076                                         }
12077                                 }
12078                                 g_list_free (handlers);
12079                         } 
12080
12081                         MONO_INST_NEW (cfg, ins, OP_BR);
12082                         MONO_ADD_INS (cfg->cbb, ins);
12083                         GET_BBLOCK (cfg, tblock, target);
12084                         link_bblock (cfg, cfg->cbb, tblock);
12085                         ins->inst_target_bb = tblock;
12086
12087                         start_new_bblock = 1;
12088
12089                         if (*ip == CEE_LEAVE)
12090                                 ip += 5;
12091                         else
12092                                 ip += 2;
12093
12094                         break;
12095                 }
12096
12097                         /*
12098                          * Mono specific opcodes
12099                          */
12100                 case MONO_CUSTOM_PREFIX: {
12101
12102                         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
12103
12104                         CHECK_OPSIZE (2);
12105                         switch (ip [1]) {
12106                         case CEE_MONO_ICALL: {
12107                                 gpointer func;
12108                                 MonoJitICallInfo *info;
12109
12110                                 token = read32 (ip + 2);
12111                                 func = mono_method_get_wrapper_data (method, token);
12112                                 info = mono_find_jit_icall_by_addr (func);
12113                                 if (!info)
12114                                         g_error ("Could not find icall address in wrapper %s", mono_method_full_name (method, 1));
12115                                 g_assert (info);
12116
12117                                 CHECK_STACK (info->sig->param_count);
12118                                 sp -= info->sig->param_count;
12119
12120                                 ins = mono_emit_jit_icall (cfg, info->func, sp);
12121                                 if (!MONO_TYPE_IS_VOID (info->sig->ret))
12122                                         *sp++ = ins;
12123
12124                                 ip += 6;
12125                                 inline_costs += 10 * num_calls++;
12126
12127                                 break;
12128                         }
12129                         case CEE_MONO_LDPTR_CARD_TABLE: {
12130                                 int shift_bits;
12131                                 gpointer card_mask;
12132                                 CHECK_STACK_OVF (1);
12133
12134                                 if (cfg->compile_aot)
12135                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR, NULL);
12136                                 else
12137                                         EMIT_NEW_PCONST (cfg, ins, mono_gc_get_card_table (&shift_bits, &card_mask));
12138
12139                                 *sp++ = ins;
12140                                 ip += 2;
12141                                 inline_costs += 10 * num_calls++;
12142                                 break;
12143                         }
12144                         case CEE_MONO_LDPTR_NURSERY_START: {
12145                                 int shift_bits;
12146                                 size_t size;
12147                                 CHECK_STACK_OVF (1);
12148
12149                                 if (cfg->compile_aot)
12150                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_GC_NURSERY_START, NULL);
12151                                 else
12152                                         EMIT_NEW_PCONST (cfg, ins, mono_gc_get_nursery (&shift_bits, &size));
12153
12154                                 *sp++ = ins;
12155                                 ip += 2;
12156                                 inline_costs += 10 * num_calls++;
12157                                 break;
12158                         }
12159                         case CEE_MONO_LDPTR_INT_REQ_FLAG: {
12160                                 CHECK_STACK_OVF (1);
12161
12162                                 if (cfg->compile_aot)
12163                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG, NULL);
12164                                 else
12165                                         EMIT_NEW_PCONST (cfg, ins, mono_thread_interruption_request_flag ());
12166
12167                                 *sp++ = ins;
12168                                 ip += 2;
12169                                 inline_costs += 10 * num_calls++;
12170                                 break;
12171                         }
12172                         case CEE_MONO_LDPTR: {
12173                                 gpointer ptr;
12174
12175                                 CHECK_STACK_OVF (1);
12176                                 CHECK_OPSIZE (6);
12177                                 token = read32 (ip + 2);
12178
12179                                 ptr = mono_method_get_wrapper_data (method, token);
12180                                 EMIT_NEW_PCONST (cfg, ins, ptr);
12181                                 *sp++ = ins;
12182                                 ip += 6;
12183                                 inline_costs += 10 * num_calls++;
12184                                 /* Can't embed random pointers into AOT code */
12185                                 DISABLE_AOT (cfg);
12186                                 break;
12187                         }
12188                         case CEE_MONO_JIT_ICALL_ADDR: {
12189                                 MonoJitICallInfo *callinfo;
12190                                 gpointer ptr;
12191
12192                                 CHECK_STACK_OVF (1);
12193                                 CHECK_OPSIZE (6);
12194                                 token = read32 (ip + 2);
12195
12196                                 ptr = mono_method_get_wrapper_data (method, token);
12197                                 callinfo = mono_find_jit_icall_by_addr (ptr);
12198                                 g_assert (callinfo);
12199                                 EMIT_NEW_JIT_ICALL_ADDRCONST (cfg, ins, (char*)callinfo->name);
12200                                 *sp++ = ins;
12201                                 ip += 6;
12202                                 inline_costs += 10 * num_calls++;
12203                                 break;
12204                         }
12205                         case CEE_MONO_ICALL_ADDR: {
12206                                 MonoMethod *cmethod;
12207                                 gpointer ptr;
12208
12209                                 CHECK_STACK_OVF (1);
12210                                 CHECK_OPSIZE (6);
12211                                 token = read32 (ip + 2);
12212
12213                                 cmethod = mono_method_get_wrapper_data (method, token);
12214
12215                                 if (cfg->compile_aot) {
12216                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, cmethod);
12217                                 } else {
12218                                         ptr = mono_lookup_internal_call (cmethod);
12219                                         g_assert (ptr);
12220                                         EMIT_NEW_PCONST (cfg, ins, ptr);
12221                                 }
12222                                 *sp++ = ins;
12223                                 ip += 6;
12224                                 break;
12225                         }
12226                         case CEE_MONO_VTADDR: {
12227                                 MonoInst *src_var, *src;
12228
12229                                 CHECK_STACK (1);
12230                                 --sp;
12231
12232                                 // FIXME:
12233                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
12234                                 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
12235                                 *sp++ = src;
12236                                 ip += 2;
12237                                 break;
12238                         }
12239                         case CEE_MONO_NEWOBJ: {
12240                                 MonoInst *iargs [2];
12241
12242                                 CHECK_STACK_OVF (1);
12243                                 CHECK_OPSIZE (6);
12244                                 token = read32 (ip + 2);
12245                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12246                                 mono_class_init (klass);
12247                                 NEW_DOMAINCONST (cfg, iargs [0]);
12248                                 MONO_ADD_INS (cfg->cbb, iargs [0]);
12249                                 NEW_CLASSCONST (cfg, iargs [1], klass);
12250                                 MONO_ADD_INS (cfg->cbb, iargs [1]);
12251                                 *sp++ = mono_emit_jit_icall (cfg, mono_object_new, iargs);
12252                                 ip += 6;
12253                                 inline_costs += 10 * num_calls++;
12254                                 break;
12255                         }
12256                         case CEE_MONO_OBJADDR:
12257                                 CHECK_STACK (1);
12258                                 --sp;
12259                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
12260                                 ins->dreg = alloc_ireg_mp (cfg);
12261                                 ins->sreg1 = sp [0]->dreg;
12262                                 ins->type = STACK_MP;
12263                                 MONO_ADD_INS (cfg->cbb, ins);
12264                                 *sp++ = ins;
12265                                 ip += 2;
12266                                 break;
12267                         case CEE_MONO_LDNATIVEOBJ:
12268                                 /*
12269                                  * Similar to LDOBJ, but instead load the unmanaged 
12270                                  * representation of the vtype to the stack.
12271                                  */
12272                                 CHECK_STACK (1);
12273                                 CHECK_OPSIZE (6);
12274                                 --sp;
12275                                 token = read32 (ip + 2);
12276                                 klass = mono_method_get_wrapper_data (method, token);
12277                                 g_assert (klass->valuetype);
12278                                 mono_class_init (klass);
12279
12280                                 {
12281                                         MonoInst *src, *dest, *temp;
12282
12283                                         src = sp [0];
12284                                         temp = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
12285                                         temp->backend.is_pinvoke = 1;
12286                                         EMIT_NEW_TEMPLOADA (cfg, dest, temp->inst_c0);
12287                                         mini_emit_stobj (cfg, dest, src, klass, TRUE);
12288
12289                                         EMIT_NEW_TEMPLOAD (cfg, dest, temp->inst_c0);
12290                                         dest->type = STACK_VTYPE;
12291                                         dest->klass = klass;
12292
12293                                         *sp ++ = dest;
12294                                         ip += 6;
12295                                 }
12296                                 break;
12297                         case CEE_MONO_RETOBJ: {
12298                                 /*
12299                                  * Same as RET, but return the native representation of a vtype
12300                                  * to the caller.
12301                                  */
12302                                 g_assert (cfg->ret);
12303                                 g_assert (mono_method_signature (method)->pinvoke); 
12304                                 CHECK_STACK (1);
12305                                 --sp;
12306                                 
12307                                 CHECK_OPSIZE (6);
12308                                 token = read32 (ip + 2);    
12309                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12310
12311                                 if (!cfg->vret_addr) {
12312                                         g_assert (cfg->ret_var_is_local);
12313
12314                                         EMIT_NEW_VARLOADA (cfg, ins, cfg->ret, cfg->ret->inst_vtype);
12315                                 } else {
12316                                         EMIT_NEW_RETLOADA (cfg, ins);
12317                                 }
12318                                 mini_emit_stobj (cfg, ins, sp [0], klass, TRUE);
12319                                 
12320                                 if (sp != stack_start)
12321                                         UNVERIFIED;
12322                                 
12323                                 MONO_INST_NEW (cfg, ins, OP_BR);
12324                                 ins->inst_target_bb = end_bblock;
12325                                 MONO_ADD_INS (cfg->cbb, ins);
12326                                 link_bblock (cfg, cfg->cbb, end_bblock);
12327                                 start_new_bblock = 1;
12328                                 ip += 6;
12329                                 break;
12330                         }
12331                         case CEE_MONO_CISINST:
12332                         case CEE_MONO_CCASTCLASS: {
12333                                 int token;
12334                                 CHECK_STACK (1);
12335                                 --sp;
12336                                 CHECK_OPSIZE (6);
12337                                 token = read32 (ip + 2);
12338                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12339                                 if (ip [1] == CEE_MONO_CISINST)
12340                                         ins = handle_cisinst (cfg, klass, sp [0]);
12341                                 else
12342                                         ins = handle_ccastclass (cfg, klass, sp [0]);
12343                                 *sp++ = ins;
12344                                 ip += 6;
12345                                 break;
12346                         }
12347                         case CEE_MONO_SAVE_LMF:
12348                         case CEE_MONO_RESTORE_LMF:
12349                                 ip += 2;
12350                                 break;
12351                         case CEE_MONO_CLASSCONST:
12352                                 CHECK_STACK_OVF (1);
12353                                 CHECK_OPSIZE (6);
12354                                 token = read32 (ip + 2);
12355                                 EMIT_NEW_CLASSCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
12356                                 *sp++ = ins;
12357                                 ip += 6;
12358                                 inline_costs += 10 * num_calls++;
12359                                 break;
12360                         case CEE_MONO_NOT_TAKEN:
12361                                 cfg->cbb->out_of_line = TRUE;
12362                                 ip += 2;
12363                                 break;
12364                         case CEE_MONO_TLS: {
12365                                 int key;
12366
12367                                 CHECK_STACK_OVF (1);
12368                                 CHECK_OPSIZE (6);
12369                                 key = (gint32)read32 (ip + 2);
12370                                 g_assert (key < TLS_KEY_NUM);
12371
12372                                 ins = mono_create_tls_get (cfg, key);
12373                                 if (!ins) {
12374                                         if (cfg->compile_aot) {
12375                                                 DISABLE_AOT (cfg);
12376                                                 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
12377                                                 ins->dreg = alloc_preg (cfg);
12378                                                 ins->type = STACK_PTR;
12379                                         } else {
12380                                                 g_assert_not_reached ();
12381                                         }
12382                                 }
12383                                 ins->type = STACK_PTR;
12384                                 MONO_ADD_INS (cfg->cbb, ins);
12385                                 *sp++ = ins;
12386                                 ip += 6;
12387                                 break;
12388                         }
12389                         case CEE_MONO_DYN_CALL: {
12390                                 MonoCallInst *call;
12391
12392                                 /* It would be easier to call a trampoline, but that would put an
12393                                  * extra frame on the stack, confusing exception handling. So
12394                                  * implement it inline using an opcode for now.
12395                                  */
12396
12397                                 if (!cfg->dyn_call_var) {
12398                                         cfg->dyn_call_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12399                                         /* prevent it from being register allocated */
12400                                         cfg->dyn_call_var->flags |= MONO_INST_VOLATILE;
12401                                 }
12402
12403                                 /* Has to use a call inst since it local regalloc expects it */
12404                                 MONO_INST_NEW_CALL (cfg, call, OP_DYN_CALL);
12405                                 ins = (MonoInst*)call;
12406                                 sp -= 2;
12407                                 ins->sreg1 = sp [0]->dreg;
12408                                 ins->sreg2 = sp [1]->dreg;
12409                                 MONO_ADD_INS (cfg->cbb, ins);
12410
12411                                 cfg->param_area = MAX (cfg->param_area, MONO_ARCH_DYN_CALL_PARAM_AREA);
12412
12413                                 ip += 2;
12414                                 inline_costs += 10 * num_calls++;
12415
12416                                 break;
12417                         }
12418                         case CEE_MONO_MEMORY_BARRIER: {
12419                                 CHECK_OPSIZE (6);
12420                                 emit_memory_barrier (cfg, (int)read32 (ip + 2));
12421                                 ip += 6;
12422                                 break;
12423                         }
12424                         case CEE_MONO_JIT_ATTACH: {
12425                                 MonoInst *args [16], *domain_ins;
12426                                 MonoInst *ad_ins, *jit_tls_ins;
12427                                 MonoBasicBlock *next_bb = NULL, *call_bb = NULL;
12428
12429                                 cfg->orig_domain_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12430
12431                                 EMIT_NEW_PCONST (cfg, ins, NULL);
12432                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12433
12434                                 ad_ins = mono_get_domain_intrinsic (cfg);
12435                                 jit_tls_ins = mono_get_jit_tls_intrinsic (cfg);
12436
12437                                 if (MONO_ARCH_HAVE_TLS_GET && ad_ins && jit_tls_ins) {
12438                                         NEW_BBLOCK (cfg, next_bb);
12439                                         NEW_BBLOCK (cfg, call_bb);
12440
12441                                         if (cfg->compile_aot) {
12442                                                 /* AOT code is only used in the root domain */
12443                                                 EMIT_NEW_PCONST (cfg, domain_ins, NULL);
12444                                         } else {
12445                                                 EMIT_NEW_PCONST (cfg, domain_ins, cfg->domain);
12446                                         }
12447                                         MONO_ADD_INS (cfg->cbb, ad_ins);
12448                                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, ad_ins->dreg, domain_ins->dreg);
12449                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, call_bb);
12450
12451                                         MONO_ADD_INS (cfg->cbb, jit_tls_ins);
12452                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, jit_tls_ins->dreg, 0);
12453                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, call_bb);
12454
12455                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, next_bb);
12456                                         MONO_START_BB (cfg, call_bb);
12457                                 }
12458
12459                                 if (cfg->compile_aot) {
12460                                         /* AOT code is only used in the root domain */
12461                                         EMIT_NEW_PCONST (cfg, args [0], NULL);
12462                                 } else {
12463                                         EMIT_NEW_PCONST (cfg, args [0], cfg->domain);
12464                                 }
12465                                 ins = mono_emit_jit_icall (cfg, mono_jit_thread_attach, args);
12466                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12467
12468                                 if (next_bb)
12469                                         MONO_START_BB (cfg, next_bb);
12470                                 ip += 2;
12471                                 break;
12472                         }
12473                         case CEE_MONO_JIT_DETACH: {
12474                                 MonoInst *args [16];
12475
12476                                 /* Restore the original domain */
12477                                 dreg = alloc_ireg (cfg);
12478                                 EMIT_NEW_UNALU (cfg, args [0], OP_MOVE, dreg, cfg->orig_domain_var->dreg);
12479                                 mono_emit_jit_icall (cfg, mono_jit_set_domain, args);
12480                                 ip += 2;
12481                                 break;
12482                         }
12483                         default:
12484                                 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
12485                                 break;
12486                         }
12487                         break;
12488                 }
12489
12490                 case CEE_PREFIX1: {
12491                         CHECK_OPSIZE (2);
12492                         switch (ip [1]) {
12493                         case CEE_ARGLIST: {
12494                                 /* somewhat similar to LDTOKEN */
12495                                 MonoInst *addr, *vtvar;
12496                                 CHECK_STACK_OVF (1);
12497                                 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL); 
12498
12499                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
12500                                 EMIT_NEW_UNALU (cfg, ins, OP_ARGLIST, -1, addr->dreg);
12501
12502                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
12503                                 ins->type = STACK_VTYPE;
12504                                 ins->klass = mono_defaults.argumenthandle_class;
12505                                 *sp++ = ins;
12506                                 ip += 2;
12507                                 break;
12508                         }
12509                         case CEE_CEQ:
12510                         case CEE_CGT:
12511                         case CEE_CGT_UN:
12512                         case CEE_CLT:
12513                         case CEE_CLT_UN: {
12514                                 MonoInst *cmp, *arg1, *arg2;
12515
12516                                 CHECK_STACK (2);
12517                                 sp -= 2;
12518                                 arg1 = sp [0];
12519                                 arg2 = sp [1];
12520
12521                                 /*
12522                                  * The following transforms:
12523                                  *    CEE_CEQ    into OP_CEQ
12524                                  *    CEE_CGT    into OP_CGT
12525                                  *    CEE_CGT_UN into OP_CGT_UN
12526                                  *    CEE_CLT    into OP_CLT
12527                                  *    CEE_CLT_UN into OP_CLT_UN
12528                                  */
12529                                 MONO_INST_NEW (cfg, cmp, (OP_CEQ - CEE_CEQ) + ip [1]);
12530
12531                                 MONO_INST_NEW (cfg, ins, cmp->opcode);
12532                                 cmp->sreg1 = arg1->dreg;
12533                                 cmp->sreg2 = arg2->dreg;
12534                                 type_from_op (cfg, cmp, arg1, arg2);
12535                                 CHECK_TYPE (cmp);
12536                                 add_widen_op (cfg, cmp, &arg1, &arg2);
12537                                 if ((arg1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((arg1->type == STACK_PTR) || (arg1->type == STACK_OBJ) || (arg1->type == STACK_MP))))
12538                                         cmp->opcode = OP_LCOMPARE;
12539                                 else if (arg1->type == STACK_R4)
12540                                         cmp->opcode = OP_RCOMPARE;
12541                                 else if (arg1->type == STACK_R8)
12542                                         cmp->opcode = OP_FCOMPARE;
12543                                 else
12544                                         cmp->opcode = OP_ICOMPARE;
12545                                 MONO_ADD_INS (cfg->cbb, cmp);
12546                                 ins->type = STACK_I4;
12547                                 ins->dreg = alloc_dreg (cfg, ins->type);
12548                                 type_from_op (cfg, ins, arg1, arg2);
12549
12550                                 if (cmp->opcode == OP_FCOMPARE || cmp->opcode == OP_RCOMPARE) {
12551                                         /*
12552                                          * The backends expect the fceq opcodes to do the
12553                                          * comparison too.
12554                                          */
12555                                         ins->sreg1 = cmp->sreg1;
12556                                         ins->sreg2 = cmp->sreg2;
12557                                         NULLIFY_INS (cmp);
12558                                 }
12559                                 MONO_ADD_INS (cfg->cbb, ins);
12560                                 *sp++ = ins;
12561                                 ip += 2;
12562                                 break;
12563                         }
12564                         case CEE_LDFTN: {
12565                                 MonoInst *argconst;
12566                                 MonoMethod *cil_method;
12567
12568                                 CHECK_STACK_OVF (1);
12569                                 CHECK_OPSIZE (6);
12570                                 n = read32 (ip + 2);
12571                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
12572                                 if (!cmethod || mono_loader_get_last_error ())
12573                                         LOAD_ERROR;
12574                                 mono_class_init (cmethod->klass);
12575
12576                                 mono_save_token_info (cfg, image, n, cmethod);
12577
12578                                 context_used = mini_method_check_context_used (cfg, cmethod);
12579
12580                                 cil_method = cmethod;
12581                                 if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
12582                                         METHOD_ACCESS_FAILURE (method, cil_method);
12583
12584                                 if (mono_security_core_clr_enabled ())
12585                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
12586
12587                                 /* 
12588                                  * Optimize the common case of ldftn+delegate creation
12589                                  */
12590                                 if ((sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 6) && (ip [6] == CEE_NEWOBJ)) {
12591                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
12592                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
12593                                                 MonoInst *target_ins, *handle_ins;
12594                                                 MonoMethod *invoke;
12595                                                 int invoke_context_used;
12596
12597                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
12598                                                 if (!invoke || !mono_method_signature (invoke))
12599                                                         LOAD_ERROR;
12600
12601                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
12602
12603                                                 target_ins = sp [-1];
12604
12605                                                 if (mono_security_core_clr_enabled ())
12606                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
12607
12608                                                 if (!(cmethod->flags & METHOD_ATTRIBUTE_STATIC)) {
12609                                                         /*LAME IMPL: We must not add a null check for virtual invoke delegates.*/
12610                                                         if (mono_method_signature (invoke)->param_count == mono_method_signature (cmethod)->param_count) {
12611                                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, target_ins->dreg, 0);
12612                                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "ArgumentException");
12613                                                         }
12614                                                 }
12615
12616                                                 /* FIXME: SGEN support */
12617                                                 if (invoke_context_used == 0) {
12618                                                         ip += 6;
12619                                                         if (cfg->verbose_level > 3)
12620                                                                 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));
12621                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, FALSE))) {
12622                                                                 sp --;
12623                                                                 *sp = handle_ins;
12624                                                                 CHECK_CFG_EXCEPTION;
12625                                                                 ip += 5;
12626                                                                 sp ++;
12627                                                                 break;
12628                                                         }
12629                                                         ip -= 6;
12630                                                 }
12631                                         }
12632                                 }
12633
12634                                 argconst = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD);
12635                                 ins = mono_emit_jit_icall (cfg, mono_ldftn, &argconst);
12636                                 *sp++ = ins;
12637                                 
12638                                 ip += 6;
12639                                 inline_costs += 10 * num_calls++;
12640                                 break;
12641                         }
12642                         case CEE_LDVIRTFTN: {
12643                                 MonoInst *args [2];
12644
12645                                 CHECK_STACK (1);
12646                                 CHECK_OPSIZE (6);
12647                                 n = read32 (ip + 2);
12648                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
12649                                 if (!cmethod || mono_loader_get_last_error ())
12650                                         LOAD_ERROR;
12651                                 mono_class_init (cmethod->klass);
12652  
12653                                 context_used = mini_method_check_context_used (cfg, cmethod);
12654
12655                                 if (mono_security_core_clr_enabled ())
12656                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
12657
12658                                 /*
12659                                  * Optimize the common case of ldvirtftn+delegate creation
12660                                  */
12661                                 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)) {
12662                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
12663                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
12664                                                 MonoInst *target_ins, *handle_ins;
12665                                                 MonoMethod *invoke;
12666                                                 int invoke_context_used;
12667                                                 gboolean is_virtual = cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL;
12668
12669                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
12670                                                 if (!invoke || !mono_method_signature (invoke))
12671                                                         LOAD_ERROR;
12672
12673                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
12674
12675                                                 target_ins = sp [-1];
12676
12677                                                 if (mono_security_core_clr_enabled ())
12678                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
12679
12680                                                 /* FIXME: SGEN support */
12681                                                 if (invoke_context_used == 0 || cfg->llvm_only) {
12682                                                         ip += 6;
12683                                                         if (cfg->verbose_level > 3)
12684                                                                 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));
12685                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, is_virtual))) {
12686                                                                 sp -= 2;
12687                                                                 *sp = handle_ins;
12688                                                                 CHECK_CFG_EXCEPTION;
12689                                                                 ip += 5;
12690                                                                 sp ++;
12691                                                                 break;
12692                                                         }
12693                                                         ip -= 6;
12694                                                 }
12695                                         }
12696                                 }
12697
12698                                 --sp;
12699                                 args [0] = *sp;
12700
12701                                 args [1] = emit_get_rgctx_method (cfg, context_used,
12702                                                                                                   cmethod, MONO_RGCTX_INFO_METHOD);
12703
12704                                 if (context_used)
12705                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn_gshared, args);
12706                                 else
12707                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn, args);
12708
12709                                 ip += 6;
12710                                 inline_costs += 10 * num_calls++;
12711                                 break;
12712                         }
12713                         case CEE_LDARG:
12714                                 CHECK_STACK_OVF (1);
12715                                 CHECK_OPSIZE (4);
12716                                 n = read16 (ip + 2);
12717                                 CHECK_ARG (n);
12718                                 EMIT_NEW_ARGLOAD (cfg, ins, n);
12719                                 *sp++ = ins;
12720                                 ip += 4;
12721                                 break;
12722                         case CEE_LDARGA:
12723                                 CHECK_STACK_OVF (1);
12724                                 CHECK_OPSIZE (4);
12725                                 n = read16 (ip + 2);
12726                                 CHECK_ARG (n);
12727                                 NEW_ARGLOADA (cfg, ins, n);
12728                                 MONO_ADD_INS (cfg->cbb, ins);
12729                                 *sp++ = ins;
12730                                 ip += 4;
12731                                 break;
12732                         case CEE_STARG:
12733                                 CHECK_STACK (1);
12734                                 --sp;
12735                                 CHECK_OPSIZE (4);
12736                                 n = read16 (ip + 2);
12737                                 CHECK_ARG (n);
12738                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
12739                                         UNVERIFIED;
12740                                 EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
12741                                 ip += 4;
12742                                 break;
12743                         case CEE_LDLOC:
12744                                 CHECK_STACK_OVF (1);
12745                                 CHECK_OPSIZE (4);
12746                                 n = read16 (ip + 2);
12747                                 CHECK_LOCAL (n);
12748                                 EMIT_NEW_LOCLOAD (cfg, ins, n);
12749                                 *sp++ = ins;
12750                                 ip += 4;
12751                                 break;
12752                         case CEE_LDLOCA: {
12753                                 unsigned char *tmp_ip;
12754                                 CHECK_STACK_OVF (1);
12755                                 CHECK_OPSIZE (4);
12756                                 n = read16 (ip + 2);
12757                                 CHECK_LOCAL (n);
12758
12759                                 if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 2))) {
12760                                         ip = tmp_ip;
12761                                         inline_costs += 1;
12762                                         break;
12763                                 }                       
12764                                 
12765                                 EMIT_NEW_LOCLOADA (cfg, ins, n);
12766                                 *sp++ = ins;
12767                                 ip += 4;
12768                                 break;
12769                         }
12770                         case CEE_STLOC:
12771                                 CHECK_STACK (1);
12772                                 --sp;
12773                                 CHECK_OPSIZE (4);
12774                                 n = read16 (ip + 2);
12775                                 CHECK_LOCAL (n);
12776                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
12777                                         UNVERIFIED;
12778                                 emit_stloc_ir (cfg, sp, header, n);
12779                                 ip += 4;
12780                                 inline_costs += 1;
12781                                 break;
12782                         case CEE_LOCALLOC:
12783                                 CHECK_STACK (1);
12784                                 --sp;
12785                                 if (sp != stack_start) 
12786                                         UNVERIFIED;
12787                                 if (cfg->method != method) 
12788                                         /* 
12789                                          * Inlining this into a loop in a parent could lead to 
12790                                          * stack overflows which is different behavior than the
12791                                          * non-inlined case, thus disable inlining in this case.
12792                                          */
12793                                         INLINE_FAILURE("localloc");
12794
12795                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
12796                                 ins->dreg = alloc_preg (cfg);
12797                                 ins->sreg1 = sp [0]->dreg;
12798                                 ins->type = STACK_PTR;
12799                                 MONO_ADD_INS (cfg->cbb, ins);
12800
12801                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12802                                 if (init_locals)
12803                                         ins->flags |= MONO_INST_INIT;
12804
12805                                 *sp++ = ins;
12806                                 ip += 2;
12807                                 break;
12808                         case CEE_ENDFILTER: {
12809                                 MonoExceptionClause *clause, *nearest;
12810                                 int cc;
12811
12812                                 CHECK_STACK (1);
12813                                 --sp;
12814                                 if ((sp != stack_start) || (sp [0]->type != STACK_I4)) 
12815                                         UNVERIFIED;
12816                                 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
12817                                 ins->sreg1 = (*sp)->dreg;
12818                                 MONO_ADD_INS (cfg->cbb, ins);
12819                                 start_new_bblock = 1;
12820                                 ip += 2;
12821
12822                                 nearest = NULL;
12823                                 for (cc = 0; cc < header->num_clauses; ++cc) {
12824                                         clause = &header->clauses [cc];
12825                                         if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
12826                                                 ((ip - header->code) > clause->data.filter_offset && (ip - header->code) <= clause->handler_offset) &&
12827                                             (!nearest || (clause->data.filter_offset < nearest->data.filter_offset)))
12828                                                 nearest = clause;
12829                                 }
12830                                 g_assert (nearest);
12831                                 if ((ip - header->code) != nearest->handler_offset)
12832                                         UNVERIFIED;
12833
12834                                 break;
12835                         }
12836                         case CEE_UNALIGNED_:
12837                                 ins_flag |= MONO_INST_UNALIGNED;
12838                                 /* FIXME: record alignment? we can assume 1 for now */
12839                                 CHECK_OPSIZE (3);
12840                                 ip += 3;
12841                                 break;
12842                         case CEE_VOLATILE_:
12843                                 ins_flag |= MONO_INST_VOLATILE;
12844                                 ip += 2;
12845                                 break;
12846                         case CEE_TAIL_:
12847                                 ins_flag   |= MONO_INST_TAILCALL;
12848                                 cfg->flags |= MONO_CFG_HAS_TAIL;
12849                                 /* Can't inline tail calls at this time */
12850                                 inline_costs += 100000;
12851                                 ip += 2;
12852                                 break;
12853                         case CEE_INITOBJ:
12854                                 CHECK_STACK (1);
12855                                 --sp;
12856                                 CHECK_OPSIZE (6);
12857                                 token = read32 (ip + 2);
12858                                 klass = mini_get_class (method, token, generic_context);
12859                                 CHECK_TYPELOAD (klass);
12860                                 if (generic_class_is_reference_type (cfg, klass))
12861                                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, sp [0]->dreg, 0, 0);
12862                                 else
12863                                         mini_emit_initobj (cfg, *sp, NULL, klass);
12864                                 ip += 6;
12865                                 inline_costs += 1;
12866                                 break;
12867                         case CEE_CONSTRAINED_:
12868                                 CHECK_OPSIZE (6);
12869                                 token = read32 (ip + 2);
12870                                 constrained_class = mini_get_class (method, token, generic_context);
12871                                 CHECK_TYPELOAD (constrained_class);
12872                                 ip += 6;
12873                                 break;
12874                         case CEE_CPBLK:
12875                         case CEE_INITBLK: {
12876                                 MonoInst *iargs [3];
12877                                 CHECK_STACK (3);
12878                                 sp -= 3;
12879
12880                                 /* Skip optimized paths for volatile operations. */
12881                                 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)) {
12882                                         mini_emit_memcpy (cfg, sp [0]->dreg, 0, sp [1]->dreg, 0, sp [2]->inst_c0, 0);
12883                                 } 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)) {
12884                                         /* emit_memset only works when val == 0 */
12885                                         mini_emit_memset (cfg, sp [0]->dreg, 0, sp [2]->inst_c0, sp [1]->inst_c0, 0);
12886                                 } else {
12887                                         MonoInst *call;
12888                                         iargs [0] = sp [0];
12889                                         iargs [1] = sp [1];
12890                                         iargs [2] = sp [2];
12891                                         if (ip [1] == CEE_CPBLK) {
12892                                                 /*
12893                                                  * FIXME: It's unclear whether we should be emitting both the acquire
12894                                                  * and release barriers for cpblk. It is technically both a load and
12895                                                  * store operation, so it seems like that's the sensible thing to do.
12896                                                  *
12897                                                  * FIXME: We emit full barriers on both sides of the operation for
12898                                                  * simplicity. We should have a separate atomic memcpy method instead.
12899                                                  */
12900                                                 MonoMethod *memcpy_method = get_memcpy_method ();
12901
12902                                                 if (ins_flag & MONO_INST_VOLATILE)
12903                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
12904
12905                                                 call = mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
12906                                                 call->flags |= ins_flag;
12907
12908                                                 if (ins_flag & MONO_INST_VOLATILE)
12909                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
12910                                         } else {
12911                                                 MonoMethod *memset_method = get_memset_method ();
12912                                                 if (ins_flag & MONO_INST_VOLATILE) {
12913                                                         /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
12914                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
12915                                                 }
12916                                                 call = mono_emit_method_call (cfg, memset_method, iargs, NULL);
12917                                                 call->flags |= ins_flag;
12918                                         }
12919                                 }
12920                                 ip += 2;
12921                                 ins_flag = 0;
12922                                 inline_costs += 1;
12923                                 break;
12924                         }
12925                         case CEE_NO_:
12926                                 CHECK_OPSIZE (3);
12927                                 if (ip [2] & 0x1)
12928                                         ins_flag |= MONO_INST_NOTYPECHECK;
12929                                 if (ip [2] & 0x2)
12930                                         ins_flag |= MONO_INST_NORANGECHECK;
12931                                 /* we ignore the no-nullcheck for now since we
12932                                  * really do it explicitly only when doing callvirt->call
12933                                  */
12934                                 ip += 3;
12935                                 break;
12936                         case CEE_RETHROW: {
12937                                 MonoInst *load;
12938                                 int handler_offset = -1;
12939
12940                                 for (i = 0; i < header->num_clauses; ++i) {
12941                                         MonoExceptionClause *clause = &header->clauses [i];
12942                                         if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
12943                                                 handler_offset = clause->handler_offset;
12944                                                 break;
12945                                         }
12946                                 }
12947
12948                                 cfg->cbb->flags |= BB_EXCEPTION_UNSAFE;
12949
12950                                 if (handler_offset == -1)
12951                                         UNVERIFIED;
12952
12953                                 EMIT_NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
12954                                 MONO_INST_NEW (cfg, ins, OP_RETHROW);
12955                                 ins->sreg1 = load->dreg;
12956                                 MONO_ADD_INS (cfg->cbb, ins);
12957
12958                                 MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
12959                                 MONO_ADD_INS (cfg->cbb, ins);
12960
12961                                 sp = stack_start;
12962                                 link_bblock (cfg, cfg->cbb, end_bblock);
12963                                 start_new_bblock = 1;
12964                                 ip += 2;
12965                                 break;
12966                         }
12967                         case CEE_SIZEOF: {
12968                                 guint32 val;
12969                                 int ialign;
12970
12971                                 CHECK_STACK_OVF (1);
12972                                 CHECK_OPSIZE (6);
12973                                 token = read32 (ip + 2);
12974                                 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC && !image_is_dynamic (method->klass->image) && !generic_context) {
12975                                         MonoType *type = mono_type_create_from_typespec_checked (image, token, &cfg->error);
12976                                         CHECK_CFG_ERROR;
12977
12978                                         val = mono_type_size (type, &ialign);
12979                                 } else {
12980                                         MonoClass *klass = mini_get_class (method, token, generic_context);
12981                                         CHECK_TYPELOAD (klass);
12982
12983                                         val = mono_type_size (&klass->byval_arg, &ialign);
12984
12985                                         if (mini_is_gsharedvt_klass (klass))
12986                                                 GSHAREDVT_FAILURE (*ip);
12987                                 }
12988                                 EMIT_NEW_ICONST (cfg, ins, val);
12989                                 *sp++= ins;
12990                                 ip += 6;
12991                                 break;
12992                         }
12993                         case CEE_REFANYTYPE: {
12994                                 MonoInst *src_var, *src;
12995
12996                                 GSHAREDVT_FAILURE (*ip);
12997
12998                                 CHECK_STACK (1);
12999                                 --sp;
13000
13001                                 // FIXME:
13002                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
13003                                 if (!src_var)
13004                                         src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
13005                                 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
13006                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &mono_defaults.typehandle_class->byval_arg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type));
13007                                 *sp++ = ins;
13008                                 ip += 2;
13009                                 break;
13010                         }
13011                         case CEE_READONLY_:
13012                                 readonly = TRUE;
13013                                 ip += 2;
13014                                 break;
13015
13016                         case CEE_UNUSED56:
13017                         case CEE_UNUSED57:
13018                         case CEE_UNUSED70:
13019                         case CEE_UNUSED:
13020                         case CEE_UNUSED99:
13021                                 UNVERIFIED;
13022                                 
13023                         default:
13024                                 g_warning ("opcode 0xfe 0x%02x not handled", ip [1]);
13025                                 UNVERIFIED;
13026                         }
13027                         break;
13028                 }
13029                 case CEE_UNUSED58:
13030                 case CEE_UNUSED1:
13031                         UNVERIFIED;
13032
13033                 default:
13034                         g_warning ("opcode 0x%02x not handled", *ip);
13035                         UNVERIFIED;
13036                 }
13037         }
13038         if (start_new_bblock != 1)
13039                 UNVERIFIED;
13040
13041         cfg->cbb->cil_length = ip - cfg->cbb->cil_code;
13042         if (cfg->cbb->next_bb) {
13043                 /* This could already be set because of inlining, #693905 */
13044                 MonoBasicBlock *bb = cfg->cbb;
13045
13046                 while (bb->next_bb)
13047                         bb = bb->next_bb;
13048                 bb->next_bb = end_bblock;
13049         } else {
13050                 cfg->cbb->next_bb = end_bblock;
13051         }
13052
13053         if (cfg->method == method && cfg->domainvar) {
13054                 MonoInst *store;
13055                 MonoInst *get_domain;
13056
13057                 cfg->cbb = init_localsbb;
13058
13059                 if ((get_domain = mono_get_domain_intrinsic (cfg))) {
13060                         MONO_ADD_INS (cfg->cbb, get_domain);
13061                 } else {
13062                         get_domain = mono_emit_jit_icall (cfg, mono_domain_get, NULL);
13063                 }
13064                 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, get_domain);
13065                 MONO_ADD_INS (cfg->cbb, store);
13066         }
13067
13068 #if defined(TARGET_POWERPC) || defined(TARGET_X86)
13069         if (cfg->compile_aot)
13070                 /* FIXME: The plt slots require a GOT var even if the method doesn't use it */
13071                 mono_get_got_var (cfg);
13072 #endif
13073
13074         if (cfg->method == method && cfg->got_var)
13075                 mono_emit_load_got_addr (cfg);
13076
13077         if (init_localsbb) {
13078                 cfg->cbb = init_localsbb;
13079                 cfg->ip = NULL;
13080                 for (i = 0; i < header->num_locals; ++i) {
13081                         emit_init_local (cfg, i, header->locals [i], init_locals);
13082                 }
13083         }
13084
13085         if (cfg->init_ref_vars && cfg->method == method) {
13086                 /* Emit initialization for ref vars */
13087                 // FIXME: Avoid duplication initialization for IL locals.
13088                 for (i = 0; i < cfg->num_varinfo; ++i) {
13089                         MonoInst *ins = cfg->varinfo [i];
13090
13091                         if (ins->opcode == OP_LOCAL && ins->type == STACK_OBJ)
13092                                 MONO_EMIT_NEW_PCONST (cfg, ins->dreg, NULL);
13093                 }
13094         }
13095
13096         if (cfg->lmf_var && cfg->method == method && !cfg->llvm_only) {
13097                 cfg->cbb = init_localsbb;
13098                 emit_push_lmf (cfg);
13099         }
13100
13101         cfg->cbb = init_localsbb;
13102         emit_instrumentation_call (cfg, mono_profiler_method_enter);
13103
13104         if (seq_points) {
13105                 MonoBasicBlock *bb;
13106
13107                 /*
13108                  * Make seq points at backward branch targets interruptable.
13109                  */
13110                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
13111                         if (bb->code && bb->in_count > 1 && bb->code->opcode == OP_SEQ_POINT)
13112                                 bb->code->flags |= MONO_INST_SINGLE_STEP_LOC;
13113         }
13114
13115         /* Add a sequence point for method entry/exit events */
13116         if (seq_points && cfg->gen_sdb_seq_points) {
13117                 NEW_SEQ_POINT (cfg, ins, METHOD_ENTRY_IL_OFFSET, FALSE);
13118                 MONO_ADD_INS (init_localsbb, ins);
13119                 NEW_SEQ_POINT (cfg, ins, METHOD_EXIT_IL_OFFSET, FALSE);
13120                 MONO_ADD_INS (cfg->bb_exit, ins);
13121         }
13122
13123         /*
13124          * Add seq points for IL offsets which have line number info, but wasn't generated a seq point during JITting because
13125          * the code they refer to was dead (#11880).
13126          */
13127         if (sym_seq_points) {
13128                 for (i = 0; i < header->code_size; ++i) {
13129                         if (mono_bitset_test_fast (seq_point_locs, i) && !mono_bitset_test_fast (seq_point_set_locs, i)) {
13130                                 MonoInst *ins;
13131
13132                                 NEW_SEQ_POINT (cfg, ins, i, FALSE);
13133                                 mono_add_seq_point (cfg, NULL, ins, SEQ_POINT_NATIVE_OFFSET_DEAD_CODE);
13134                         }
13135                 }
13136         }
13137
13138         cfg->ip = NULL;
13139
13140         if (cfg->method == method) {
13141                 MonoBasicBlock *bb;
13142                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13143                         bb->region = mono_find_block_region (cfg, bb->real_offset);
13144                         if (cfg->spvars)
13145                                 mono_create_spvar_for_region (cfg, bb->region);
13146                         if (cfg->verbose_level > 2)
13147                                 printf ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
13148                 }
13149         }
13150
13151         if (inline_costs < 0) {
13152                 char *mname;
13153
13154                 /* Method is too large */
13155                 mname = mono_method_full_name (method, TRUE);
13156                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
13157                 cfg->exception_message = g_strdup_printf ("Method %s is too complex.", mname);
13158                 g_free (mname);
13159         }
13160
13161         if ((cfg->verbose_level > 2) && (cfg->method == method)) 
13162                 mono_print_code (cfg, "AFTER METHOD-TO-IR");
13163
13164         goto cleanup;
13165
13166 mono_error_exit:
13167         g_assert (!mono_error_ok (&cfg->error));
13168         goto cleanup;
13169  
13170  exception_exit:
13171         g_assert (cfg->exception_type != MONO_EXCEPTION_NONE);
13172         goto cleanup;
13173
13174  unverified:
13175         set_exception_type_from_invalid_il (cfg, method, ip);
13176         goto cleanup;
13177
13178  cleanup:
13179         g_slist_free (class_inits);
13180         mono_basic_block_free (original_bb);
13181         cfg->dont_inline = g_list_remove (cfg->dont_inline, method);
13182         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
13183         if (cfg->exception_type)
13184                 return -1;
13185         else
13186                 return inline_costs;
13187 }
13188
13189 static int
13190 store_membase_reg_to_store_membase_imm (int opcode)
13191 {
13192         switch (opcode) {
13193         case OP_STORE_MEMBASE_REG:
13194                 return OP_STORE_MEMBASE_IMM;
13195         case OP_STOREI1_MEMBASE_REG:
13196                 return OP_STOREI1_MEMBASE_IMM;
13197         case OP_STOREI2_MEMBASE_REG:
13198                 return OP_STOREI2_MEMBASE_IMM;
13199         case OP_STOREI4_MEMBASE_REG:
13200                 return OP_STOREI4_MEMBASE_IMM;
13201         case OP_STOREI8_MEMBASE_REG:
13202                 return OP_STOREI8_MEMBASE_IMM;
13203         default:
13204                 g_assert_not_reached ();
13205         }
13206
13207         return -1;
13208 }               
13209
13210 int
13211 mono_op_to_op_imm (int opcode)
13212 {
13213         switch (opcode) {
13214         case OP_IADD:
13215                 return OP_IADD_IMM;
13216         case OP_ISUB:
13217                 return OP_ISUB_IMM;
13218         case OP_IDIV:
13219                 return OP_IDIV_IMM;
13220         case OP_IDIV_UN:
13221                 return OP_IDIV_UN_IMM;
13222         case OP_IREM:
13223                 return OP_IREM_IMM;
13224         case OP_IREM_UN:
13225                 return OP_IREM_UN_IMM;
13226         case OP_IMUL:
13227                 return OP_IMUL_IMM;
13228         case OP_IAND:
13229                 return OP_IAND_IMM;
13230         case OP_IOR:
13231                 return OP_IOR_IMM;
13232         case OP_IXOR:
13233                 return OP_IXOR_IMM;
13234         case OP_ISHL:
13235                 return OP_ISHL_IMM;
13236         case OP_ISHR:
13237                 return OP_ISHR_IMM;
13238         case OP_ISHR_UN:
13239                 return OP_ISHR_UN_IMM;
13240
13241         case OP_LADD:
13242                 return OP_LADD_IMM;
13243         case OP_LSUB:
13244                 return OP_LSUB_IMM;
13245         case OP_LAND:
13246                 return OP_LAND_IMM;
13247         case OP_LOR:
13248                 return OP_LOR_IMM;
13249         case OP_LXOR:
13250                 return OP_LXOR_IMM;
13251         case OP_LSHL:
13252                 return OP_LSHL_IMM;
13253         case OP_LSHR:
13254                 return OP_LSHR_IMM;
13255         case OP_LSHR_UN:
13256                 return OP_LSHR_UN_IMM;
13257 #if SIZEOF_REGISTER == 8
13258         case OP_LREM:
13259                 return OP_LREM_IMM;
13260 #endif
13261
13262         case OP_COMPARE:
13263                 return OP_COMPARE_IMM;
13264         case OP_ICOMPARE:
13265                 return OP_ICOMPARE_IMM;
13266         case OP_LCOMPARE:
13267                 return OP_LCOMPARE_IMM;
13268
13269         case OP_STORE_MEMBASE_REG:
13270                 return OP_STORE_MEMBASE_IMM;
13271         case OP_STOREI1_MEMBASE_REG:
13272                 return OP_STOREI1_MEMBASE_IMM;
13273         case OP_STOREI2_MEMBASE_REG:
13274                 return OP_STOREI2_MEMBASE_IMM;
13275         case OP_STOREI4_MEMBASE_REG:
13276                 return OP_STOREI4_MEMBASE_IMM;
13277
13278 #if defined(TARGET_X86) || defined (TARGET_AMD64)
13279         case OP_X86_PUSH:
13280                 return OP_X86_PUSH_IMM;
13281         case OP_X86_COMPARE_MEMBASE_REG:
13282                 return OP_X86_COMPARE_MEMBASE_IMM;
13283 #endif
13284 #if defined(TARGET_AMD64)
13285         case OP_AMD64_ICOMPARE_MEMBASE_REG:
13286                 return OP_AMD64_ICOMPARE_MEMBASE_IMM;
13287 #endif
13288         case OP_VOIDCALL_REG:
13289                 return OP_VOIDCALL;
13290         case OP_CALL_REG:
13291                 return OP_CALL;
13292         case OP_LCALL_REG:
13293                 return OP_LCALL;
13294         case OP_FCALL_REG:
13295                 return OP_FCALL;
13296         case OP_LOCALLOC:
13297                 return OP_LOCALLOC_IMM;
13298         }
13299
13300         return -1;
13301 }
13302
13303 static int
13304 ldind_to_load_membase (int opcode)
13305 {
13306         switch (opcode) {
13307         case CEE_LDIND_I1:
13308                 return OP_LOADI1_MEMBASE;
13309         case CEE_LDIND_U1:
13310                 return OP_LOADU1_MEMBASE;
13311         case CEE_LDIND_I2:
13312                 return OP_LOADI2_MEMBASE;
13313         case CEE_LDIND_U2:
13314                 return OP_LOADU2_MEMBASE;
13315         case CEE_LDIND_I4:
13316                 return OP_LOADI4_MEMBASE;
13317         case CEE_LDIND_U4:
13318                 return OP_LOADU4_MEMBASE;
13319         case CEE_LDIND_I:
13320                 return OP_LOAD_MEMBASE;
13321         case CEE_LDIND_REF:
13322                 return OP_LOAD_MEMBASE;
13323         case CEE_LDIND_I8:
13324                 return OP_LOADI8_MEMBASE;
13325         case CEE_LDIND_R4:
13326                 return OP_LOADR4_MEMBASE;
13327         case CEE_LDIND_R8:
13328                 return OP_LOADR8_MEMBASE;
13329         default:
13330                 g_assert_not_reached ();
13331         }
13332
13333         return -1;
13334 }
13335
13336 static int
13337 stind_to_store_membase (int opcode)
13338 {
13339         switch (opcode) {
13340         case CEE_STIND_I1:
13341                 return OP_STOREI1_MEMBASE_REG;
13342         case CEE_STIND_I2:
13343                 return OP_STOREI2_MEMBASE_REG;
13344         case CEE_STIND_I4:
13345                 return OP_STOREI4_MEMBASE_REG;
13346         case CEE_STIND_I:
13347         case CEE_STIND_REF:
13348                 return OP_STORE_MEMBASE_REG;
13349         case CEE_STIND_I8:
13350                 return OP_STOREI8_MEMBASE_REG;
13351         case CEE_STIND_R4:
13352                 return OP_STORER4_MEMBASE_REG;
13353         case CEE_STIND_R8:
13354                 return OP_STORER8_MEMBASE_REG;
13355         default:
13356                 g_assert_not_reached ();
13357         }
13358
13359         return -1;
13360 }
13361
13362 int
13363 mono_load_membase_to_load_mem (int opcode)
13364 {
13365         // FIXME: Add a MONO_ARCH_HAVE_LOAD_MEM macro
13366 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13367         switch (opcode) {
13368         case OP_LOAD_MEMBASE:
13369                 return OP_LOAD_MEM;
13370         case OP_LOADU1_MEMBASE:
13371                 return OP_LOADU1_MEM;
13372         case OP_LOADU2_MEMBASE:
13373                 return OP_LOADU2_MEM;
13374         case OP_LOADI4_MEMBASE:
13375                 return OP_LOADI4_MEM;
13376         case OP_LOADU4_MEMBASE:
13377                 return OP_LOADU4_MEM;
13378 #if SIZEOF_REGISTER == 8
13379         case OP_LOADI8_MEMBASE:
13380                 return OP_LOADI8_MEM;
13381 #endif
13382         }
13383 #endif
13384
13385         return -1;
13386 }
13387
13388 static inline int
13389 op_to_op_dest_membase (int store_opcode, int opcode)
13390 {
13391 #if defined(TARGET_X86)
13392         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG)))
13393                 return -1;
13394
13395         switch (opcode) {
13396         case OP_IADD:
13397                 return OP_X86_ADD_MEMBASE_REG;
13398         case OP_ISUB:
13399                 return OP_X86_SUB_MEMBASE_REG;
13400         case OP_IAND:
13401                 return OP_X86_AND_MEMBASE_REG;
13402         case OP_IOR:
13403                 return OP_X86_OR_MEMBASE_REG;
13404         case OP_IXOR:
13405                 return OP_X86_XOR_MEMBASE_REG;
13406         case OP_ADD_IMM:
13407         case OP_IADD_IMM:
13408                 return OP_X86_ADD_MEMBASE_IMM;
13409         case OP_SUB_IMM:
13410         case OP_ISUB_IMM:
13411                 return OP_X86_SUB_MEMBASE_IMM;
13412         case OP_AND_IMM:
13413         case OP_IAND_IMM:
13414                 return OP_X86_AND_MEMBASE_IMM;
13415         case OP_OR_IMM:
13416         case OP_IOR_IMM:
13417                 return OP_X86_OR_MEMBASE_IMM;
13418         case OP_XOR_IMM:
13419         case OP_IXOR_IMM:
13420                 return OP_X86_XOR_MEMBASE_IMM;
13421         case OP_MOVE:
13422                 return OP_NOP;
13423         }
13424 #endif
13425
13426 #if defined(TARGET_AMD64)
13427         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG) || (store_opcode == OP_STOREI8_MEMBASE_REG)))
13428                 return -1;
13429
13430         switch (opcode) {
13431         case OP_IADD:
13432                 return OP_X86_ADD_MEMBASE_REG;
13433         case OP_ISUB:
13434                 return OP_X86_SUB_MEMBASE_REG;
13435         case OP_IAND:
13436                 return OP_X86_AND_MEMBASE_REG;
13437         case OP_IOR:
13438                 return OP_X86_OR_MEMBASE_REG;
13439         case OP_IXOR:
13440                 return OP_X86_XOR_MEMBASE_REG;
13441         case OP_IADD_IMM:
13442                 return OP_X86_ADD_MEMBASE_IMM;
13443         case OP_ISUB_IMM:
13444                 return OP_X86_SUB_MEMBASE_IMM;
13445         case OP_IAND_IMM:
13446                 return OP_X86_AND_MEMBASE_IMM;
13447         case OP_IOR_IMM:
13448                 return OP_X86_OR_MEMBASE_IMM;
13449         case OP_IXOR_IMM:
13450                 return OP_X86_XOR_MEMBASE_IMM;
13451         case OP_LADD:
13452                 return OP_AMD64_ADD_MEMBASE_REG;
13453         case OP_LSUB:
13454                 return OP_AMD64_SUB_MEMBASE_REG;
13455         case OP_LAND:
13456                 return OP_AMD64_AND_MEMBASE_REG;
13457         case OP_LOR:
13458                 return OP_AMD64_OR_MEMBASE_REG;
13459         case OP_LXOR:
13460                 return OP_AMD64_XOR_MEMBASE_REG;
13461         case OP_ADD_IMM:
13462         case OP_LADD_IMM:
13463                 return OP_AMD64_ADD_MEMBASE_IMM;
13464         case OP_SUB_IMM:
13465         case OP_LSUB_IMM:
13466                 return OP_AMD64_SUB_MEMBASE_IMM;
13467         case OP_AND_IMM:
13468         case OP_LAND_IMM:
13469                 return OP_AMD64_AND_MEMBASE_IMM;
13470         case OP_OR_IMM:
13471         case OP_LOR_IMM:
13472                 return OP_AMD64_OR_MEMBASE_IMM;
13473         case OP_XOR_IMM:
13474         case OP_LXOR_IMM:
13475                 return OP_AMD64_XOR_MEMBASE_IMM;
13476         case OP_MOVE:
13477                 return OP_NOP;
13478         }
13479 #endif
13480
13481         return -1;
13482 }
13483
13484 static inline int
13485 op_to_op_store_membase (int store_opcode, int opcode)
13486 {
13487 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13488         switch (opcode) {
13489         case OP_ICEQ:
13490                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13491                         return OP_X86_SETEQ_MEMBASE;
13492         case OP_CNE:
13493                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13494                         return OP_X86_SETNE_MEMBASE;
13495         }
13496 #endif
13497
13498         return -1;
13499 }
13500
13501 static inline int
13502 op_to_op_src1_membase (int load_opcode, int opcode)
13503 {
13504 #ifdef TARGET_X86
13505         /* FIXME: This has sign extension issues */
13506         /*
13507         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
13508                 return OP_X86_COMPARE_MEMBASE8_IMM;
13509         */
13510
13511         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
13512                 return -1;
13513
13514         switch (opcode) {
13515         case OP_X86_PUSH:
13516                 return OP_X86_PUSH_MEMBASE;
13517         case OP_COMPARE_IMM:
13518         case OP_ICOMPARE_IMM:
13519                 return OP_X86_COMPARE_MEMBASE_IMM;
13520         case OP_COMPARE:
13521         case OP_ICOMPARE:
13522                 return OP_X86_COMPARE_MEMBASE_REG;
13523         }
13524 #endif
13525
13526 #ifdef TARGET_AMD64
13527         /* FIXME: This has sign extension issues */
13528         /*
13529         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
13530                 return OP_X86_COMPARE_MEMBASE8_IMM;
13531         */
13532
13533         switch (opcode) {
13534         case OP_X86_PUSH:
13535 #ifdef __mono_ilp32__
13536                 if (load_opcode == OP_LOADI8_MEMBASE)
13537 #else
13538                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
13539 #endif
13540                         return OP_X86_PUSH_MEMBASE;
13541                 break;
13542                 /* FIXME: This only works for 32 bit immediates
13543         case OP_COMPARE_IMM:
13544         case OP_LCOMPARE_IMM:
13545                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
13546                         return OP_AMD64_COMPARE_MEMBASE_IMM;
13547                 */
13548         case OP_ICOMPARE_IMM:
13549                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
13550                         return OP_AMD64_ICOMPARE_MEMBASE_IMM;
13551                 break;
13552         case OP_COMPARE:
13553         case OP_LCOMPARE:
13554 #ifdef __mono_ilp32__
13555                 if (load_opcode == OP_LOAD_MEMBASE)
13556                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
13557                 if (load_opcode == OP_LOADI8_MEMBASE)
13558 #else
13559                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
13560 #endif
13561                         return OP_AMD64_COMPARE_MEMBASE_REG;
13562                 break;
13563         case OP_ICOMPARE:
13564                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
13565                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
13566                 break;
13567         }
13568 #endif
13569
13570         return -1;
13571 }
13572
13573 static inline int
13574 op_to_op_src2_membase (int load_opcode, int opcode)
13575 {
13576 #ifdef TARGET_X86
13577         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
13578                 return -1;
13579         
13580         switch (opcode) {
13581         case OP_COMPARE:
13582         case OP_ICOMPARE:
13583                 return OP_X86_COMPARE_REG_MEMBASE;
13584         case OP_IADD:
13585                 return OP_X86_ADD_REG_MEMBASE;
13586         case OP_ISUB:
13587                 return OP_X86_SUB_REG_MEMBASE;
13588         case OP_IAND:
13589                 return OP_X86_AND_REG_MEMBASE;
13590         case OP_IOR:
13591                 return OP_X86_OR_REG_MEMBASE;
13592         case OP_IXOR:
13593                 return OP_X86_XOR_REG_MEMBASE;
13594         }
13595 #endif
13596
13597 #ifdef TARGET_AMD64
13598 #ifdef __mono_ilp32__
13599         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE) ) {
13600 #else
13601         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)) {
13602 #endif
13603                 switch (opcode) {
13604                 case OP_ICOMPARE:
13605                         return OP_AMD64_ICOMPARE_REG_MEMBASE;
13606                 case OP_IADD:
13607                         return OP_X86_ADD_REG_MEMBASE;
13608                 case OP_ISUB:
13609                         return OP_X86_SUB_REG_MEMBASE;
13610                 case OP_IAND:
13611                         return OP_X86_AND_REG_MEMBASE;
13612                 case OP_IOR:
13613                         return OP_X86_OR_REG_MEMBASE;
13614                 case OP_IXOR:
13615                         return OP_X86_XOR_REG_MEMBASE;
13616                 }
13617 #ifdef __mono_ilp32__
13618         } else if (load_opcode == OP_LOADI8_MEMBASE) {
13619 #else
13620         } else if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE)) {
13621 #endif
13622                 switch (opcode) {
13623                 case OP_COMPARE:
13624                 case OP_LCOMPARE:
13625                         return OP_AMD64_COMPARE_REG_MEMBASE;
13626                 case OP_LADD:
13627                         return OP_AMD64_ADD_REG_MEMBASE;
13628                 case OP_LSUB:
13629                         return OP_AMD64_SUB_REG_MEMBASE;
13630                 case OP_LAND:
13631                         return OP_AMD64_AND_REG_MEMBASE;
13632                 case OP_LOR:
13633                         return OP_AMD64_OR_REG_MEMBASE;
13634                 case OP_LXOR:
13635                         return OP_AMD64_XOR_REG_MEMBASE;
13636                 }
13637         }
13638 #endif
13639
13640         return -1;
13641 }
13642
13643 int
13644 mono_op_to_op_imm_noemul (int opcode)
13645 {
13646         switch (opcode) {
13647 #if SIZEOF_REGISTER == 4 && !defined(MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS)
13648         case OP_LSHR:
13649         case OP_LSHL:
13650         case OP_LSHR_UN:
13651                 return -1;
13652 #endif
13653 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
13654         case OP_IDIV:
13655         case OP_IDIV_UN:
13656         case OP_IREM:
13657         case OP_IREM_UN:
13658                 return -1;
13659 #endif
13660 #if defined(MONO_ARCH_EMULATE_MUL_DIV)
13661         case OP_IMUL:
13662                 return -1;
13663 #endif
13664         default:
13665                 return mono_op_to_op_imm (opcode);
13666         }
13667 }
13668
13669 /**
13670  * mono_handle_global_vregs:
13671  *
13672  *   Make vregs used in more than one bblock 'global', i.e. allocate a variable
13673  * for them.
13674  */
13675 void
13676 mono_handle_global_vregs (MonoCompile *cfg)
13677 {
13678         gint32 *vreg_to_bb;
13679         MonoBasicBlock *bb;
13680         int i, pos;
13681
13682         vreg_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (gint32*) * cfg->next_vreg + 1);
13683
13684 #ifdef MONO_ARCH_SIMD_INTRINSICS
13685         if (cfg->uses_simd_intrinsics)
13686                 mono_simd_simplify_indirection (cfg);
13687 #endif
13688
13689         /* Find local vregs used in more than one bb */
13690         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13691                 MonoInst *ins = bb->code;       
13692                 int block_num = bb->block_num;
13693
13694                 if (cfg->verbose_level > 2)
13695                         printf ("\nHANDLE-GLOBAL-VREGS BLOCK %d:\n", bb->block_num);
13696
13697                 cfg->cbb = bb;
13698                 for (; ins; ins = ins->next) {
13699                         const char *spec = INS_INFO (ins->opcode);
13700                         int regtype = 0, regindex;
13701                         gint32 prev_bb;
13702
13703                         if (G_UNLIKELY (cfg->verbose_level > 2))
13704                                 mono_print_ins (ins);
13705
13706                         g_assert (ins->opcode >= MONO_CEE_LAST);
13707
13708                         for (regindex = 0; regindex < 4; regindex ++) {
13709                                 int vreg = 0;
13710
13711                                 if (regindex == 0) {
13712                                         regtype = spec [MONO_INST_DEST];
13713                                         if (regtype == ' ')
13714                                                 continue;
13715                                         vreg = ins->dreg;
13716                                 } else if (regindex == 1) {
13717                                         regtype = spec [MONO_INST_SRC1];
13718                                         if (regtype == ' ')
13719                                                 continue;
13720                                         vreg = ins->sreg1;
13721                                 } else if (regindex == 2) {
13722                                         regtype = spec [MONO_INST_SRC2];
13723                                         if (regtype == ' ')
13724                                                 continue;
13725                                         vreg = ins->sreg2;
13726                                 } else if (regindex == 3) {
13727                                         regtype = spec [MONO_INST_SRC3];
13728                                         if (regtype == ' ')
13729                                                 continue;
13730                                         vreg = ins->sreg3;
13731                                 }
13732
13733 #if SIZEOF_REGISTER == 4
13734                                 /* In the LLVM case, the long opcodes are not decomposed */
13735                                 if (regtype == 'l' && !COMPILE_LLVM (cfg)) {
13736                                         /*
13737                                          * Since some instructions reference the original long vreg,
13738                                          * and some reference the two component vregs, it is quite hard
13739                                          * to determine when it needs to be global. So be conservative.
13740                                          */
13741                                         if (!get_vreg_to_inst (cfg, vreg)) {
13742                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
13743
13744                                                 if (cfg->verbose_level > 2)
13745                                                         printf ("LONG VREG R%d made global.\n", vreg);
13746                                         }
13747
13748                                         /*
13749                                          * Make the component vregs volatile since the optimizations can
13750                                          * get confused otherwise.
13751                                          */
13752                                         get_vreg_to_inst (cfg, vreg + 1)->flags |= MONO_INST_VOLATILE;
13753                                         get_vreg_to_inst (cfg, vreg + 2)->flags |= MONO_INST_VOLATILE;
13754                                 }
13755 #endif
13756
13757                                 g_assert (vreg != -1);
13758
13759                                 prev_bb = vreg_to_bb [vreg];
13760                                 if (prev_bb == 0) {
13761                                         /* 0 is a valid block num */
13762                                         vreg_to_bb [vreg] = block_num + 1;
13763                                 } else if ((prev_bb != block_num + 1) && (prev_bb != -1)) {
13764                                         if (((regtype == 'i' && (vreg < MONO_MAX_IREGS))) || (regtype == 'f' && (vreg < MONO_MAX_FREGS)))
13765                                                 continue;
13766
13767                                         if (!get_vreg_to_inst (cfg, vreg)) {
13768                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
13769                                                         printf ("VREG R%d used in BB%d and BB%d made global.\n", vreg, vreg_to_bb [vreg], block_num);
13770
13771                                                 switch (regtype) {
13772                                                 case 'i':
13773                                                         if (vreg_is_ref (cfg, vreg))
13774                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL, vreg);
13775                                                         else
13776                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL, vreg);
13777                                                         break;
13778                                                 case 'l':
13779                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
13780                                                         break;
13781                                                 case 'f':
13782                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL, vreg);
13783                                                         break;
13784                                                 case 'v':
13785                                                         mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, vreg);
13786                                                         break;
13787                                                 default:
13788                                                         g_assert_not_reached ();
13789                                                 }
13790                                         }
13791
13792                                         /* Flag as having been used in more than one bb */
13793                                         vreg_to_bb [vreg] = -1;
13794                                 }
13795                         }
13796                 }
13797         }
13798
13799         /* If a variable is used in only one bblock, convert it into a local vreg */
13800         for (i = 0; i < cfg->num_varinfo; i++) {
13801                 MonoInst *var = cfg->varinfo [i];
13802                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
13803
13804                 switch (var->type) {
13805                 case STACK_I4:
13806                 case STACK_OBJ:
13807                 case STACK_PTR:
13808                 case STACK_MP:
13809                 case STACK_VTYPE:
13810 #if SIZEOF_REGISTER == 8
13811                 case STACK_I8:
13812 #endif
13813 #if !defined(TARGET_X86)
13814                 /* Enabling this screws up the fp stack on x86 */
13815                 case STACK_R8:
13816 #endif
13817                         if (mono_arch_is_soft_float ())
13818                                 break;
13819
13820                         /* Arguments are implicitly global */
13821                         /* Putting R4 vars into registers doesn't work currently */
13822                         /* The gsharedvt vars are implicitly referenced by ldaddr opcodes, but those opcodes are only generated later */
13823                         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) {
13824                                 /* 
13825                                  * Make that the variable's liveness interval doesn't contain a call, since
13826                                  * that would cause the lvreg to be spilled, making the whole optimization
13827                                  * useless.
13828                                  */
13829                                 /* This is too slow for JIT compilation */
13830 #if 0
13831                                 if (cfg->compile_aot && vreg_to_bb [var->dreg]) {
13832                                         MonoInst *ins;
13833                                         int def_index, call_index, ins_index;
13834                                         gboolean spilled = FALSE;
13835
13836                                         def_index = -1;
13837                                         call_index = -1;
13838                                         ins_index = 0;
13839                                         for (ins = vreg_to_bb [var->dreg]->code; ins; ins = ins->next) {
13840                                                 const char *spec = INS_INFO (ins->opcode);
13841
13842                                                 if ((spec [MONO_INST_DEST] != ' ') && (ins->dreg == var->dreg))
13843                                                         def_index = ins_index;
13844
13845                                                 if (((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg)) ||
13846                                                         ((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg))) {
13847                                                         if (call_index > def_index) {
13848                                                                 spilled = TRUE;
13849                                                                 break;
13850                                                         }
13851                                                 }
13852
13853                                                 if (MONO_IS_CALL (ins))
13854                                                         call_index = ins_index;
13855
13856                                                 ins_index ++;
13857                                         }
13858
13859                                         if (spilled)
13860                                                 break;
13861                                 }
13862 #endif
13863
13864                                 if (G_UNLIKELY (cfg->verbose_level > 2))
13865                                         printf ("CONVERTED R%d(%d) TO VREG.\n", var->dreg, vmv->idx);
13866                                 var->flags |= MONO_INST_IS_DEAD;
13867                                 cfg->vreg_to_inst [var->dreg] = NULL;
13868                         }
13869                         break;
13870                 }
13871         }
13872
13873         /* 
13874          * Compress the varinfo and vars tables so the liveness computation is faster and
13875          * takes up less space.
13876          */
13877         pos = 0;
13878         for (i = 0; i < cfg->num_varinfo; ++i) {
13879                 MonoInst *var = cfg->varinfo [i];
13880                 if (pos < i && cfg->locals_start == i)
13881                         cfg->locals_start = pos;
13882                 if (!(var->flags & MONO_INST_IS_DEAD)) {
13883                         if (pos < i) {
13884                                 cfg->varinfo [pos] = cfg->varinfo [i];
13885                                 cfg->varinfo [pos]->inst_c0 = pos;
13886                                 memcpy (&cfg->vars [pos], &cfg->vars [i], sizeof (MonoMethodVar));
13887                                 cfg->vars [pos].idx = pos;
13888 #if SIZEOF_REGISTER == 4
13889                                 if (cfg->varinfo [pos]->type == STACK_I8) {
13890                                         /* Modify the two component vars too */
13891                                         MonoInst *var1;
13892
13893                                         var1 = get_vreg_to_inst (cfg, cfg->varinfo [pos]->dreg + 1);
13894                                         var1->inst_c0 = pos;
13895                                         var1 = get_vreg_to_inst (cfg, cfg->varinfo [pos]->dreg + 2);
13896                                         var1->inst_c0 = pos;
13897                                 }
13898 #endif
13899                         }
13900                         pos ++;
13901                 }
13902         }
13903         cfg->num_varinfo = pos;
13904         if (cfg->locals_start > cfg->num_varinfo)
13905                 cfg->locals_start = cfg->num_varinfo;
13906 }
13907
13908 /**
13909  * mono_spill_global_vars:
13910  *
13911  *   Generate spill code for variables which are not allocated to registers, 
13912  * and replace vregs with their allocated hregs. *need_local_opts is set to TRUE if
13913  * code is generated which could be optimized by the local optimization passes.
13914  */
13915 void
13916 mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
13917 {
13918         MonoBasicBlock *bb;
13919         char spec2 [16];
13920         int orig_next_vreg;
13921         guint32 *vreg_to_lvreg;
13922         guint32 *lvregs;
13923         guint32 i, lvregs_len;
13924         gboolean dest_has_lvreg = FALSE;
13925         guint32 stacktypes [128];
13926         MonoInst **live_range_start, **live_range_end;
13927         MonoBasicBlock **live_range_start_bb, **live_range_end_bb;
13928         int *gsharedvt_vreg_to_idx = NULL;
13929
13930         *need_local_opts = FALSE;
13931
13932         memset (spec2, 0, sizeof (spec2));
13933
13934         /* FIXME: Move this function to mini.c */
13935         stacktypes ['i'] = STACK_PTR;
13936         stacktypes ['l'] = STACK_I8;
13937         stacktypes ['f'] = STACK_R8;
13938 #ifdef MONO_ARCH_SIMD_INTRINSICS
13939         stacktypes ['x'] = STACK_VTYPE;
13940 #endif
13941
13942 #if SIZEOF_REGISTER == 4
13943         /* Create MonoInsts for longs */
13944         for (i = 0; i < cfg->num_varinfo; i++) {
13945                 MonoInst *ins = cfg->varinfo [i];
13946
13947                 if ((ins->opcode != OP_REGVAR) && !(ins->flags & MONO_INST_IS_DEAD)) {
13948                         switch (ins->type) {
13949                         case STACK_R8:
13950                         case STACK_I8: {
13951                                 MonoInst *tree;
13952
13953                                 if (ins->type == STACK_R8 && !COMPILE_SOFT_FLOAT (cfg))
13954                                         break;
13955
13956                                 g_assert (ins->opcode == OP_REGOFFSET);
13957
13958                                 tree = get_vreg_to_inst (cfg, ins->dreg + 1);
13959                                 g_assert (tree);
13960                                 tree->opcode = OP_REGOFFSET;
13961                                 tree->inst_basereg = ins->inst_basereg;
13962                                 tree->inst_offset = ins->inst_offset + MINI_LS_WORD_OFFSET;
13963
13964                                 tree = get_vreg_to_inst (cfg, ins->dreg + 2);
13965                                 g_assert (tree);
13966                                 tree->opcode = OP_REGOFFSET;
13967                                 tree->inst_basereg = ins->inst_basereg;
13968                                 tree->inst_offset = ins->inst_offset + MINI_MS_WORD_OFFSET;
13969                                 break;
13970                         }
13971                         default:
13972                                 break;
13973                         }
13974                 }
13975         }
13976 #endif
13977
13978         if (cfg->compute_gc_maps) {
13979                 /* registers need liveness info even for !non refs */
13980                 for (i = 0; i < cfg->num_varinfo; i++) {
13981                         MonoInst *ins = cfg->varinfo [i];
13982
13983                         if (ins->opcode == OP_REGVAR)
13984                                 ins->flags |= MONO_INST_GC_TRACK;
13985                 }
13986         }
13987
13988         if (cfg->gsharedvt) {
13989                 gsharedvt_vreg_to_idx = mono_mempool_alloc0 (cfg->mempool, sizeof (int) * cfg->next_vreg);
13990
13991                 for (i = 0; i < cfg->num_varinfo; ++i) {
13992                         MonoInst *ins = cfg->varinfo [i];
13993                         int idx;
13994
13995                         if (mini_is_gsharedvt_variable_type (ins->inst_vtype)) {
13996                                 if (i >= cfg->locals_start) {
13997                                         /* Local */
13998                                         idx = get_gsharedvt_info_slot (cfg, ins->inst_vtype, MONO_RGCTX_INFO_LOCAL_OFFSET);
13999                                         gsharedvt_vreg_to_idx [ins->dreg] = idx + 1;
14000                                         ins->opcode = OP_GSHAREDVT_LOCAL;
14001                                         ins->inst_imm = idx;
14002                                 } else {
14003                                         /* Arg */
14004                                         gsharedvt_vreg_to_idx [ins->dreg] = -1;
14005                                         ins->opcode = OP_GSHAREDVT_ARG_REGOFFSET;
14006                                 }
14007                         }
14008                 }
14009         }
14010                 
14011         /* FIXME: widening and truncation */
14012
14013         /*
14014          * As an optimization, when a variable allocated to the stack is first loaded into 
14015          * an lvreg, we will remember the lvreg and use it the next time instead of loading
14016          * the variable again.
14017          */
14018         orig_next_vreg = cfg->next_vreg;
14019         vreg_to_lvreg = mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * cfg->next_vreg);
14020         lvregs = mono_mempool_alloc (cfg->mempool, sizeof (guint32) * 1024);
14021         lvregs_len = 0;
14022
14023         /* 
14024          * These arrays contain the first and last instructions accessing a given
14025          * variable.
14026          * Since we emit bblocks in the same order we process them here, and we
14027          * don't split live ranges, these will precisely describe the live range of
14028          * the variable, i.e. the instruction range where a valid value can be found
14029          * in the variables location.
14030          * The live range is computed using the liveness info computed by the liveness pass.
14031          * We can't use vmv->range, since that is an abstract live range, and we need
14032          * one which is instruction precise.
14033          * FIXME: Variables used in out-of-line bblocks have a hole in their live range.
14034          */
14035         /* FIXME: Only do this if debugging info is requested */
14036         live_range_start = g_new0 (MonoInst*, cfg->next_vreg);
14037         live_range_end = g_new0 (MonoInst*, cfg->next_vreg);
14038         live_range_start_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
14039         live_range_end_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
14040         
14041         /* Add spill loads/stores */
14042         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
14043                 MonoInst *ins;
14044
14045                 if (cfg->verbose_level > 2)
14046                         printf ("\nSPILL BLOCK %d:\n", bb->block_num);
14047
14048                 /* Clear vreg_to_lvreg array */
14049                 for (i = 0; i < lvregs_len; i++)
14050                         vreg_to_lvreg [lvregs [i]] = 0;
14051                 lvregs_len = 0;
14052
14053                 cfg->cbb = bb;
14054                 MONO_BB_FOR_EACH_INS (bb, ins) {
14055                         const char *spec = INS_INFO (ins->opcode);
14056                         int regtype, srcindex, sreg, tmp_reg, prev_dreg, num_sregs;
14057                         gboolean store, no_lvreg;
14058                         int sregs [MONO_MAX_SRC_REGS];
14059
14060                         if (G_UNLIKELY (cfg->verbose_level > 2))
14061                                 mono_print_ins (ins);
14062
14063                         if (ins->opcode == OP_NOP)
14064                                 continue;
14065
14066                         /* 
14067                          * We handle LDADDR here as well, since it can only be decomposed
14068                          * when variable addresses are known.
14069                          */
14070                         if (ins->opcode == OP_LDADDR) {
14071                                 MonoInst *var = ins->inst_p0;
14072
14073                                 if (var->opcode == OP_VTARG_ADDR) {
14074                                         /* Happens on SPARC/S390 where vtypes are passed by reference */
14075                                         MonoInst *vtaddr = var->inst_left;
14076                                         if (vtaddr->opcode == OP_REGVAR) {
14077                                                 ins->opcode = OP_MOVE;
14078                                                 ins->sreg1 = vtaddr->dreg;
14079                                         }
14080                                         else if (var->inst_left->opcode == OP_REGOFFSET) {
14081                                                 ins->opcode = OP_LOAD_MEMBASE;
14082                                                 ins->inst_basereg = vtaddr->inst_basereg;
14083                                                 ins->inst_offset = vtaddr->inst_offset;
14084                                         } else
14085                                                 NOT_IMPLEMENTED;
14086                                 } else if (cfg->gsharedvt && gsharedvt_vreg_to_idx [var->dreg] < 0) {
14087                                         /* gsharedvt arg passed by ref */
14088                                         g_assert (var->opcode == OP_GSHAREDVT_ARG_REGOFFSET);
14089
14090                                         ins->opcode = OP_LOAD_MEMBASE;
14091                                         ins->inst_basereg = var->inst_basereg;
14092                                         ins->inst_offset = var->inst_offset;
14093                                 } else if (cfg->gsharedvt && gsharedvt_vreg_to_idx [var->dreg]) {
14094                                         MonoInst *load, *load2, *load3;
14095                                         int idx = gsharedvt_vreg_to_idx [var->dreg] - 1;
14096                                         int reg1, reg2, reg3;
14097                                         MonoInst *info_var = cfg->gsharedvt_info_var;
14098                                         MonoInst *locals_var = cfg->gsharedvt_locals_var;
14099
14100                                         /*
14101                                          * gsharedvt local.
14102                                          * Compute the address of the local as gsharedvt_locals_var + gsharedvt_info_var->locals_offsets [idx].
14103                                          */
14104
14105                                         g_assert (var->opcode == OP_GSHAREDVT_LOCAL);
14106
14107                                         g_assert (info_var);
14108                                         g_assert (locals_var);
14109
14110                                         /* Mark the instruction used to compute the locals var as used */
14111                                         cfg->gsharedvt_locals_var_ins = NULL;
14112
14113                                         /* Load the offset */
14114                                         if (info_var->opcode == OP_REGOFFSET) {
14115                                                 reg1 = alloc_ireg (cfg);
14116                                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, reg1, info_var->inst_basereg, info_var->inst_offset);
14117                                         } else if (info_var->opcode == OP_REGVAR) {
14118                                                 load = NULL;
14119                                                 reg1 = info_var->dreg;
14120                                         } else {
14121                                                 g_assert_not_reached ();
14122                                         }
14123                                         reg2 = alloc_ireg (cfg);
14124                                         NEW_LOAD_MEMBASE (cfg, load2, OP_LOADI4_MEMBASE, reg2, reg1, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
14125                                         /* Load the locals area address */
14126                                         reg3 = alloc_ireg (cfg);
14127                                         if (locals_var->opcode == OP_REGOFFSET) {
14128                                                 NEW_LOAD_MEMBASE (cfg, load3, OP_LOAD_MEMBASE, reg3, locals_var->inst_basereg, locals_var->inst_offset);
14129                                         } else if (locals_var->opcode == OP_REGVAR) {
14130                                                 NEW_UNALU (cfg, load3, OP_MOVE, reg3, locals_var->dreg);
14131                                         } else {
14132                                                 g_assert_not_reached ();
14133                                         }
14134                                         /* Compute the address */
14135                                         ins->opcode = OP_PADD;
14136                                         ins->sreg1 = reg3;
14137                                         ins->sreg2 = reg2;
14138
14139                                         mono_bblock_insert_before_ins (bb, ins, load3);
14140                                         mono_bblock_insert_before_ins (bb, load3, load2);
14141                                         if (load)
14142                                                 mono_bblock_insert_before_ins (bb, load2, load);
14143                                 } else {
14144                                         g_assert (var->opcode == OP_REGOFFSET);
14145
14146                                         ins->opcode = OP_ADD_IMM;
14147                                         ins->sreg1 = var->inst_basereg;
14148                                         ins->inst_imm = var->inst_offset;
14149                                 }
14150
14151                                 *need_local_opts = TRUE;
14152                                 spec = INS_INFO (ins->opcode);
14153                         }
14154
14155                         if (ins->opcode < MONO_CEE_LAST) {
14156                                 mono_print_ins (ins);
14157                                 g_assert_not_reached ();
14158                         }
14159
14160                         /*
14161                          * Store opcodes have destbasereg in the dreg, but in reality, it is an
14162                          * src register.
14163                          * FIXME:
14164                          */
14165                         if (MONO_IS_STORE_MEMBASE (ins)) {
14166                                 tmp_reg = ins->dreg;
14167                                 ins->dreg = ins->sreg2;
14168                                 ins->sreg2 = tmp_reg;
14169                                 store = TRUE;
14170
14171                                 spec2 [MONO_INST_DEST] = ' ';
14172                                 spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14173                                 spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14174                                 spec2 [MONO_INST_SRC3] = ' ';
14175                                 spec = spec2;
14176                         } else if (MONO_IS_STORE_MEMINDEX (ins))
14177                                 g_assert_not_reached ();
14178                         else
14179                                 store = FALSE;
14180                         no_lvreg = FALSE;
14181
14182                         if (G_UNLIKELY (cfg->verbose_level > 2)) {
14183                                 printf ("\t %.3s %d", spec, ins->dreg);
14184                                 num_sregs = mono_inst_get_src_registers (ins, sregs);
14185                                 for (srcindex = 0; srcindex < num_sregs; ++srcindex)
14186                                         printf (" %d", sregs [srcindex]);
14187                                 printf ("\n");
14188                         }
14189
14190                         /***************/
14191                         /*    DREG     */
14192                         /***************/
14193                         regtype = spec [MONO_INST_DEST];
14194                         g_assert (((ins->dreg == -1) && (regtype == ' ')) || ((ins->dreg != -1) && (regtype != ' ')));
14195                         prev_dreg = -1;
14196
14197                         if ((ins->dreg != -1) && get_vreg_to_inst (cfg, ins->dreg)) {
14198                                 MonoInst *var = get_vreg_to_inst (cfg, ins->dreg);
14199                                 MonoInst *store_ins;
14200                                 int store_opcode;
14201                                 MonoInst *def_ins = ins;
14202                                 int dreg = ins->dreg; /* The original vreg */
14203
14204                                 store_opcode = mono_type_to_store_membase (cfg, var->inst_vtype);
14205
14206                                 if (var->opcode == OP_REGVAR) {
14207                                         ins->dreg = var->dreg;
14208                                 } 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)) {
14209                                         /* 
14210                                          * Instead of emitting a load+store, use a _membase opcode.
14211                                          */
14212                                         g_assert (var->opcode == OP_REGOFFSET);
14213                                         if (ins->opcode == OP_MOVE) {
14214                                                 NULLIFY_INS (ins);
14215                                                 def_ins = NULL;
14216                                         } else {
14217                                                 ins->opcode = op_to_op_dest_membase (store_opcode, ins->opcode);
14218                                                 ins->inst_basereg = var->inst_basereg;
14219                                                 ins->inst_offset = var->inst_offset;
14220                                                 ins->dreg = -1;
14221                                         }
14222                                         spec = INS_INFO (ins->opcode);
14223                                 } else {
14224                                         guint32 lvreg;
14225
14226                                         g_assert (var->opcode == OP_REGOFFSET);
14227
14228                                         prev_dreg = ins->dreg;
14229
14230                                         /* Invalidate any previous lvreg for this vreg */
14231                                         vreg_to_lvreg [ins->dreg] = 0;
14232
14233                                         lvreg = 0;
14234
14235                                         if (COMPILE_SOFT_FLOAT (cfg) && store_opcode == OP_STORER8_MEMBASE_REG) {
14236                                                 regtype = 'l';
14237                                                 store_opcode = OP_STOREI8_MEMBASE_REG;
14238                                         }
14239
14240                                         ins->dreg = alloc_dreg (cfg, stacktypes [regtype]);
14241
14242 #if SIZEOF_REGISTER != 8
14243                                         if (regtype == 'l') {
14244                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET, ins->dreg + 1);
14245                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14246                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET, ins->dreg + 2);
14247                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14248                                                 def_ins = store_ins;
14249                                         }
14250                                         else
14251 #endif
14252                                         {
14253                                                 g_assert (store_opcode != OP_STOREV_MEMBASE);
14254
14255                                                 /* Try to fuse the store into the instruction itself */
14256                                                 /* FIXME: Add more instructions */
14257                                                 if (!lvreg && ((ins->opcode == OP_ICONST) || ((ins->opcode == OP_I8CONST) && (ins->inst_c0 == 0)))) {
14258                                                         ins->opcode = store_membase_reg_to_store_membase_imm (store_opcode);
14259                                                         ins->inst_imm = ins->inst_c0;
14260                                                         ins->inst_destbasereg = var->inst_basereg;
14261                                                         ins->inst_offset = var->inst_offset;
14262                                                         spec = INS_INFO (ins->opcode);
14263                                                 } else if (!lvreg && ((ins->opcode == OP_MOVE) || (ins->opcode == OP_FMOVE) || (ins->opcode == OP_LMOVE) || (ins->opcode == OP_RMOVE))) {
14264                                                         ins->opcode = store_opcode;
14265                                                         ins->inst_destbasereg = var->inst_basereg;
14266                                                         ins->inst_offset = var->inst_offset;
14267
14268                                                         no_lvreg = TRUE;
14269
14270                                                         tmp_reg = ins->dreg;
14271                                                         ins->dreg = ins->sreg2;
14272                                                         ins->sreg2 = tmp_reg;
14273                                                         store = TRUE;
14274
14275                                                         spec2 [MONO_INST_DEST] = ' ';
14276                                                         spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14277                                                         spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14278                                                         spec2 [MONO_INST_SRC3] = ' ';
14279                                                         spec = spec2;
14280                                                 } else if (!lvreg && (op_to_op_store_membase (store_opcode, ins->opcode) != -1)) {
14281                                                         // FIXME: The backends expect the base reg to be in inst_basereg
14282                                                         ins->opcode = op_to_op_store_membase (store_opcode, ins->opcode);
14283                                                         ins->dreg = -1;
14284                                                         ins->inst_basereg = var->inst_basereg;
14285                                                         ins->inst_offset = var->inst_offset;
14286                                                         spec = INS_INFO (ins->opcode);
14287                                                 } else {
14288                                                         /* printf ("INS: "); mono_print_ins (ins); */
14289                                                         /* Create a store instruction */
14290                                                         NEW_STORE_MEMBASE (cfg, store_ins, store_opcode, var->inst_basereg, var->inst_offset, ins->dreg);
14291
14292                                                         /* Insert it after the instruction */
14293                                                         mono_bblock_insert_after_ins (bb, ins, store_ins);
14294
14295                                                         def_ins = store_ins;
14296
14297                                                         /* 
14298                                                          * We can't assign ins->dreg to var->dreg here, since the
14299                                                          * sregs could use it. So set a flag, and do it after
14300                                                          * the sregs.
14301                                                          */
14302                                                         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)))
14303                                                                 dest_has_lvreg = TRUE;
14304                                                 }
14305                                         }
14306                                 }
14307
14308                                 if (def_ins && !live_range_start [dreg]) {
14309                                         live_range_start [dreg] = def_ins;
14310                                         live_range_start_bb [dreg] = bb;
14311                                 }
14312
14313                                 if (cfg->compute_gc_maps && def_ins && (var->flags & MONO_INST_GC_TRACK)) {
14314                                         MonoInst *tmp;
14315
14316                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
14317                                         tmp->inst_c1 = dreg;
14318                                         mono_bblock_insert_after_ins (bb, def_ins, tmp);
14319                                 }
14320                         }
14321
14322                         /************/
14323                         /*  SREGS   */
14324                         /************/
14325                         num_sregs = mono_inst_get_src_registers (ins, sregs);
14326                         for (srcindex = 0; srcindex < 3; ++srcindex) {
14327                                 regtype = spec [MONO_INST_SRC1 + srcindex];
14328                                 sreg = sregs [srcindex];
14329
14330                                 g_assert (((sreg == -1) && (regtype == ' ')) || ((sreg != -1) && (regtype != ' ')));
14331                                 if ((sreg != -1) && get_vreg_to_inst (cfg, sreg)) {
14332                                         MonoInst *var = get_vreg_to_inst (cfg, sreg);
14333                                         MonoInst *use_ins = ins;
14334                                         MonoInst *load_ins;
14335                                         guint32 load_opcode;
14336
14337                                         if (var->opcode == OP_REGVAR) {
14338                                                 sregs [srcindex] = var->dreg;
14339                                                 //mono_inst_set_src_registers (ins, sregs);
14340                                                 live_range_end [sreg] = use_ins;
14341                                                 live_range_end_bb [sreg] = bb;
14342
14343                                                 if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14344                                                         MonoInst *tmp;
14345
14346                                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14347                                                         /* var->dreg is a hreg */
14348                                                         tmp->inst_c1 = sreg;
14349                                                         mono_bblock_insert_after_ins (bb, ins, tmp);
14350                                                 }
14351
14352                                                 continue;
14353                                         }
14354
14355                                         g_assert (var->opcode == OP_REGOFFSET);
14356                                                 
14357                                         load_opcode = mono_type_to_load_membase (cfg, var->inst_vtype);
14358
14359                                         g_assert (load_opcode != OP_LOADV_MEMBASE);
14360
14361                                         if (vreg_to_lvreg [sreg]) {
14362                                                 g_assert (vreg_to_lvreg [sreg] != -1);
14363
14364                                                 /* The variable is already loaded to an lvreg */
14365                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
14366                                                         printf ("\t\tUse lvreg R%d for R%d.\n", vreg_to_lvreg [sreg], sreg);
14367                                                 sregs [srcindex] = vreg_to_lvreg [sreg];
14368                                                 //mono_inst_set_src_registers (ins, sregs);
14369                                                 continue;
14370                                         }
14371
14372                                         /* Try to fuse the load into the instruction */
14373                                         if ((srcindex == 0) && (op_to_op_src1_membase (load_opcode, ins->opcode) != -1)) {
14374                                                 ins->opcode = op_to_op_src1_membase (load_opcode, ins->opcode);
14375                                                 sregs [0] = var->inst_basereg;
14376                                                 //mono_inst_set_src_registers (ins, sregs);
14377                                                 ins->inst_offset = var->inst_offset;
14378                                         } else if ((srcindex == 1) && (op_to_op_src2_membase (load_opcode, ins->opcode) != -1)) {
14379                                                 ins->opcode = op_to_op_src2_membase (load_opcode, ins->opcode);
14380                                                 sregs [1] = var->inst_basereg;
14381                                                 //mono_inst_set_src_registers (ins, sregs);
14382                                                 ins->inst_offset = var->inst_offset;
14383                                         } else {
14384                                                 if (MONO_IS_REAL_MOVE (ins)) {
14385                                                         ins->opcode = OP_NOP;
14386                                                         sreg = ins->dreg;
14387                                                 } else {
14388                                                         //printf ("%d ", srcindex); mono_print_ins (ins);
14389
14390                                                         sreg = alloc_dreg (cfg, stacktypes [regtype]);
14391
14392                                                         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) {
14393                                                                 if (var->dreg == prev_dreg) {
14394                                                                         /*
14395                                                                          * sreg refers to the value loaded by the load
14396                                                                          * emitted below, but we need to use ins->dreg
14397                                                                          * since it refers to the store emitted earlier.
14398                                                                          */
14399                                                                         sreg = ins->dreg;
14400                                                                 }
14401                                                                 g_assert (sreg != -1);
14402                                                                 vreg_to_lvreg [var->dreg] = sreg;
14403                                                                 g_assert (lvregs_len < 1024);
14404                                                                 lvregs [lvregs_len ++] = var->dreg;
14405                                                         }
14406                                                 }
14407
14408                                                 sregs [srcindex] = sreg;
14409                                                 //mono_inst_set_src_registers (ins, sregs);
14410
14411 #if SIZEOF_REGISTER != 8
14412                                                 if (regtype == 'l') {
14413                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 2, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET);
14414                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14415                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 1, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET);
14416                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14417                                                         use_ins = load_ins;
14418                                                 }
14419                                                 else
14420 #endif
14421                                                 {
14422 #if SIZEOF_REGISTER == 4
14423                                                         g_assert (load_opcode != OP_LOADI8_MEMBASE);
14424 #endif
14425                                                         NEW_LOAD_MEMBASE (cfg, load_ins, load_opcode, sreg, var->inst_basereg, var->inst_offset);
14426                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14427                                                         use_ins = load_ins;
14428                                                 }
14429                                         }
14430
14431                                         if (var->dreg < orig_next_vreg) {
14432                                                 live_range_end [var->dreg] = use_ins;
14433                                                 live_range_end_bb [var->dreg] = bb;
14434                                         }
14435
14436                                         if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14437                                                 MonoInst *tmp;
14438
14439                                                 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14440                                                 tmp->inst_c1 = var->dreg;
14441                                                 mono_bblock_insert_after_ins (bb, ins, tmp);
14442                                         }
14443                                 }
14444                         }
14445                         mono_inst_set_src_registers (ins, sregs);
14446
14447                         if (dest_has_lvreg) {
14448                                 g_assert (ins->dreg != -1);
14449                                 vreg_to_lvreg [prev_dreg] = ins->dreg;
14450                                 g_assert (lvregs_len < 1024);
14451                                 lvregs [lvregs_len ++] = prev_dreg;
14452                                 dest_has_lvreg = FALSE;
14453                         }
14454
14455                         if (store) {
14456                                 tmp_reg = ins->dreg;
14457                                 ins->dreg = ins->sreg2;
14458                                 ins->sreg2 = tmp_reg;
14459                         }
14460
14461                         if (MONO_IS_CALL (ins)) {
14462                                 /* Clear vreg_to_lvreg array */
14463                                 for (i = 0; i < lvregs_len; i++)
14464                                         vreg_to_lvreg [lvregs [i]] = 0;
14465                                 lvregs_len = 0;
14466                         } else if (ins->opcode == OP_NOP) {
14467                                 ins->dreg = -1;
14468                                 MONO_INST_NULLIFY_SREGS (ins);
14469                         }
14470
14471                         if (cfg->verbose_level > 2)
14472                                 mono_print_ins_index (1, ins);
14473                 }
14474
14475                 /* Extend the live range based on the liveness info */
14476                 if (cfg->compute_precise_live_ranges && bb->live_out_set && bb->code) {
14477                         for (i = 0; i < cfg->num_varinfo; i ++) {
14478                                 MonoMethodVar *vi = MONO_VARINFO (cfg, i);
14479
14480                                 if (vreg_is_volatile (cfg, vi->vreg))
14481                                         /* The liveness info is incomplete */
14482                                         continue;
14483
14484                                 if (mono_bitset_test_fast (bb->live_in_set, i) && !live_range_start [vi->vreg]) {
14485                                         /* Live from at least the first ins of this bb */
14486                                         live_range_start [vi->vreg] = bb->code;
14487                                         live_range_start_bb [vi->vreg] = bb;
14488                                 }
14489
14490                                 if (mono_bitset_test_fast (bb->live_out_set, i)) {
14491                                         /* Live at least until the last ins of this bb */
14492                                         live_range_end [vi->vreg] = bb->last_ins;
14493                                         live_range_end_bb [vi->vreg] = bb;
14494                                 }
14495                         }
14496                 }
14497         }
14498         
14499 #ifdef MONO_ARCH_HAVE_LIVERANGE_OPS
14500         /*
14501          * Emit LIVERANGE_START/LIVERANGE_END opcodes, the backend will implement them
14502          * by storing the current native offset into MonoMethodVar->live_range_start/end.
14503          */
14504         if (cfg->compute_precise_live_ranges && cfg->comp_done & MONO_COMP_LIVENESS) {
14505                 for (i = 0; i < cfg->num_varinfo; ++i) {
14506                         int vreg = MONO_VARINFO (cfg, i)->vreg;
14507                         MonoInst *ins;
14508
14509                         if (live_range_start [vreg]) {
14510                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_START);
14511                                 ins->inst_c0 = i;
14512                                 ins->inst_c1 = vreg;
14513                                 mono_bblock_insert_after_ins (live_range_start_bb [vreg], live_range_start [vreg], ins);
14514                         }
14515                         if (live_range_end [vreg]) {
14516                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_END);
14517                                 ins->inst_c0 = i;
14518                                 ins->inst_c1 = vreg;
14519                                 if (live_range_end [vreg] == live_range_end_bb [vreg]->last_ins)
14520                                         mono_add_ins_to_end (live_range_end_bb [vreg], ins);
14521                                 else
14522                                         mono_bblock_insert_after_ins (live_range_end_bb [vreg], live_range_end [vreg], ins);
14523                         }
14524                 }
14525         }
14526 #endif
14527
14528         if (cfg->gsharedvt_locals_var_ins) {
14529                 /* Nullify if unused */
14530                 cfg->gsharedvt_locals_var_ins->opcode = OP_PCONST;
14531                 cfg->gsharedvt_locals_var_ins->inst_imm = 0;
14532         }
14533
14534         g_free (live_range_start);
14535         g_free (live_range_end);
14536         g_free (live_range_start_bb);
14537         g_free (live_range_end_bb);
14538 }
14539
14540 /**
14541  * FIXME:
14542  * - use 'iadd' instead of 'int_add'
14543  * - handling ovf opcodes: decompose in method_to_ir.
14544  * - unify iregs/fregs
14545  *   -> partly done, the missing parts are:
14546  *   - a more complete unification would involve unifying the hregs as well, so
14547  *     code wouldn't need if (fp) all over the place. but that would mean the hregs
14548  *     would no longer map to the machine hregs, so the code generators would need to
14549  *     be modified. Also, on ia64 for example, niregs + nfregs > 256 -> bitmasks
14550  *     wouldn't work any more. Duplicating the code in mono_local_regalloc () into
14551  *     fp/non-fp branches speeds it up by about 15%.
14552  * - use sext/zext opcodes instead of shifts
14553  * - add OP_ICALL
14554  * - get rid of TEMPLOADs if possible and use vregs instead
14555  * - clean up usage of OP_P/OP_ opcodes
14556  * - cleanup usage of DUMMY_USE
14557  * - cleanup the setting of ins->type for MonoInst's which are pushed on the 
14558  *   stack
14559  * - set the stack type and allocate a dreg in the EMIT_NEW macros
14560  * - get rid of all the <foo>2 stuff when the new JIT is ready.
14561  * - make sure handle_stack_args () is called before the branch is emitted
14562  * - when the new IR is done, get rid of all unused stuff
14563  * - COMPARE/BEQ as separate instructions or unify them ?
14564  *   - keeping them separate allows specialized compare instructions like
14565  *     compare_imm, compare_membase
14566  *   - most back ends unify fp compare+branch, fp compare+ceq
14567  * - integrate mono_save_args into inline_method
14568  * - get rid of the empty bblocks created by MONO_EMIT_NEW_BRACH_BLOCK2
14569  * - handle long shift opts on 32 bit platforms somehow: they require 
14570  *   3 sregs (2 for arg1 and 1 for arg2)
14571  * - make byref a 'normal' type.
14572  * - use vregs for bb->out_stacks if possible, handle_global_vreg will make them a
14573  *   variable if needed.
14574  * - do not start a new IL level bblock when cfg->cbb is changed by a function call
14575  *   like inline_method.
14576  * - remove inlining restrictions
14577  * - fix LNEG and enable cfold of INEG
14578  * - generalize x86 optimizations like ldelema as a peephole optimization
14579  * - add store_mem_imm for amd64
14580  * - optimize the loading of the interruption flag in the managed->native wrappers
14581  * - avoid special handling of OP_NOP in passes
14582  * - move code inserting instructions into one function/macro.
14583  * - try a coalescing phase after liveness analysis
14584  * - add float -> vreg conversion + local optimizations on !x86
14585  * - figure out how to handle decomposed branches during optimizations, ie.
14586  *   compare+branch, op_jump_table+op_br etc.
14587  * - promote RuntimeXHandles to vregs
14588  * - vtype cleanups:
14589  *   - add a NEW_VARLOADA_VREG macro
14590  * - the vtype optimizations are blocked by the LDADDR opcodes generated for 
14591  *   accessing vtype fields.
14592  * - get rid of I8CONST on 64 bit platforms
14593  * - dealing with the increase in code size due to branches created during opcode
14594  *   decomposition:
14595  *   - use extended basic blocks
14596  *     - all parts of the JIT
14597  *     - handle_global_vregs () && local regalloc
14598  *   - avoid introducing global vregs during decomposition, like 'vtable' in isinst
14599  * - sources of increase in code size:
14600  *   - vtypes
14601  *   - long compares
14602  *   - isinst and castclass
14603  *   - lvregs not allocated to global registers even if used multiple times
14604  * - call cctors outside the JIT, to make -v output more readable and JIT timings more
14605  *   meaningful.
14606  * - check for fp stack leakage in other opcodes too. (-> 'exceptions' optimization)
14607  * - add all micro optimizations from the old JIT
14608  * - put tree optimizations into the deadce pass
14609  * - decompose op_start_handler/op_endfilter/op_endfinally earlier using an arch
14610  *   specific function.
14611  * - unify the float comparison opcodes with the other comparison opcodes, i.e.
14612  *   fcompare + branchCC.
14613  * - create a helper function for allocating a stack slot, taking into account 
14614  *   MONO_CFG_HAS_SPILLUP.
14615  * - merge r68207.
14616  * - merge the ia64 switch changes.
14617  * - optimize mono_regstate2_alloc_int/float.
14618  * - fix the pessimistic handling of variables accessed in exception handler blocks.
14619  * - need to write a tree optimization pass, but the creation of trees is difficult, i.e.
14620  *   parts of the tree could be separated by other instructions, killing the tree
14621  *   arguments, or stores killing loads etc. Also, should we fold loads into other
14622  *   instructions if the result of the load is used multiple times ?
14623  * - make the REM_IMM optimization in mini-x86.c arch-independent.
14624  * - LAST MERGE: 108395.
14625  * - when returning vtypes in registers, generate IR and append it to the end of the
14626  *   last bb instead of doing it in the epilog.
14627  * - change the store opcodes so they use sreg1 instead of dreg to store the base register.
14628  */
14629
14630 /*
14631
14632 NOTES
14633 -----
14634
14635 - When to decompose opcodes:
14636   - earlier: this makes some optimizations hard to implement, since the low level IR
14637   no longer contains the neccessary information. But it is easier to do.
14638   - later: harder to implement, enables more optimizations.
14639 - Branches inside bblocks:
14640   - created when decomposing complex opcodes. 
14641     - branches to another bblock: harmless, but not tracked by the branch 
14642       optimizations, so need to branch to a label at the start of the bblock.
14643     - branches to inside the same bblock: very problematic, trips up the local
14644       reg allocator. Can be fixed by spitting the current bblock, but that is a
14645       complex operation, since some local vregs can become global vregs etc.
14646 - Local/global vregs:
14647   - local vregs: temporary vregs used inside one bblock. Assigned to hregs by the
14648     local register allocator.
14649   - global vregs: used in more than one bblock. Have an associated MonoMethodVar
14650     structure, created by mono_create_var (). Assigned to hregs or the stack by
14651     the global register allocator.
14652 - When to do optimizations like alu->alu_imm:
14653   - earlier -> saves work later on since the IR will be smaller/simpler
14654   - later -> can work on more instructions
14655 - Handling of valuetypes:
14656   - When a vtype is pushed on the stack, a new temporary is created, an 
14657     instruction computing its address (LDADDR) is emitted and pushed on
14658     the stack. Need to optimize cases when the vtype is used immediately as in
14659     argument passing, stloc etc.
14660 - Instead of the to_end stuff in the old JIT, simply call the function handling
14661   the values on the stack before emitting the last instruction of the bb.
14662 */
14663
14664 #endif /* DISABLE_JIT */