Fix a merge problem.
[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                         try_bb->real_offset = clause->try_offset;
7940                         try_bb->try_start = TRUE;
7941                         try_bb->region = ((i + 1) << 8) | clause->flags;
7942                         GET_BBLOCK (cfg, tblock, ip + clause->handler_offset);
7943                         tblock->real_offset = clause->handler_offset;
7944                         tblock->flags |= BB_EXCEPTION_HANDLER;
7945
7946                         /*
7947                          * Linking the try block with the EH block hinders inlining as we won't be able to 
7948                          * merge the bblocks from inlining and produce an artificial hole for no good reason.
7949                          */
7950                         if (COMPILE_LLVM (cfg))
7951                                 link_bblock (cfg, try_bb, tblock);
7952
7953                         if (*(ip + clause->handler_offset) == CEE_POP)
7954                                 tblock->flags |= BB_EXCEPTION_DEAD_OBJ;
7955
7956                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
7957                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER ||
7958                             clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
7959                                 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
7960                                 MONO_ADD_INS (tblock, ins);
7961
7962                                 if (seq_points && clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY && clause->flags != MONO_EXCEPTION_CLAUSE_FILTER) {
7963                                         /* finally clauses already have a seq point */
7964                                         /* seq points for filter clauses are emitted below */
7965                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
7966                                         MONO_ADD_INS (tblock, ins);
7967                                 }
7968
7969                                 /* todo: is a fault block unsafe to optimize? */
7970                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
7971                                         tblock->flags |= BB_EXCEPTION_UNSAFE;
7972                         }
7973
7974                         /*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);
7975                           while (p < end) {
7976                           printf ("%s", mono_disasm_code_one (NULL, method, p, &p));
7977                           }*/
7978                         /* catch and filter blocks get the exception object on the stack */
7979                         if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
7980                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
7981
7982                                 /* mostly like handle_stack_args (), but just sets the input args */
7983                                 /* printf ("handling clause at IL_%04x\n", clause->handler_offset); */
7984                                 tblock->in_scount = 1;
7985                                 tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
7986                                 tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
7987
7988                                 cfg->cbb = tblock;
7989
7990 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
7991                                 /* The EH code passes in the exception in a register to both JITted and LLVM compiled code */
7992                                 if (!cfg->compile_llvm) {
7993                                         MONO_INST_NEW (cfg, ins, OP_GET_EX_OBJ);
7994                                         ins->dreg = tblock->in_stack [0]->dreg;
7995                                         MONO_ADD_INS (tblock, ins);
7996                                 }
7997 #else
7998                                 MonoInst *dummy_use;
7999
8000                                 /* 
8001                                  * Add a dummy use for the exvar so its liveness info will be
8002                                  * correct.
8003                                  */
8004                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, tblock->in_stack [0]);
8005 #endif
8006
8007                                 if (seq_points && clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
8008                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
8009                                         MONO_ADD_INS (tblock, ins);
8010                                 }
8011                                 
8012                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
8013                                         GET_BBLOCK (cfg, tblock, ip + clause->data.filter_offset);
8014                                         tblock->flags |= BB_EXCEPTION_HANDLER;
8015                                         tblock->real_offset = clause->data.filter_offset;
8016                                         tblock->in_scount = 1;
8017                                         tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
8018                                         /* The filter block shares the exvar with the handler block */
8019                                         tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
8020                                         MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
8021                                         MONO_ADD_INS (tblock, ins);
8022                                 }
8023                         }
8024
8025                         if (clause->flags != MONO_EXCEPTION_CLAUSE_FILTER &&
8026                                         clause->data.catch_class &&
8027                                         cfg->gshared &&
8028                                         mono_class_check_context_used (clause->data.catch_class)) {
8029                                 /*
8030                                  * In shared generic code with catch
8031                                  * clauses containing type variables
8032                                  * the exception handling code has to
8033                                  * be able to get to the rgctx.
8034                                  * Therefore we have to make sure that
8035                                  * the vtable/mrgctx argument (for
8036                                  * static or generic methods) or the
8037                                  * "this" argument (for non-static
8038                                  * methods) are live.
8039                                  */
8040                                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
8041                                                 mini_method_get_context (method)->method_inst ||
8042                                                 method->klass->valuetype) {
8043                                         mono_get_vtable_var (cfg);
8044                                 } else {
8045                                         MonoInst *dummy_use;
8046
8047                                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, arg_array [0]);
8048                                 }
8049                         }
8050                 }
8051         } else {
8052                 arg_array = (MonoInst **) alloca (sizeof (MonoInst *) * num_args);
8053                 cfg->cbb = start_bblock;
8054                 cfg->args = arg_array;
8055                 mono_save_args (cfg, sig, inline_args);
8056         }
8057
8058         /* FIRST CODE BLOCK */
8059         NEW_BBLOCK (cfg, tblock);
8060         tblock->cil_code = ip;
8061         cfg->cbb = tblock;
8062         cfg->ip = ip;
8063
8064         ADD_BBLOCK (cfg, tblock);
8065
8066         if (cfg->method == method) {
8067                 breakpoint_id = mono_debugger_method_has_breakpoint (method);
8068                 if (breakpoint_id) {
8069                         MONO_INST_NEW (cfg, ins, OP_BREAK);
8070                         MONO_ADD_INS (cfg->cbb, ins);
8071                 }
8072         }
8073
8074         /* we use a separate basic block for the initialization code */
8075         NEW_BBLOCK (cfg, init_localsbb);
8076         cfg->bb_init = init_localsbb;
8077         init_localsbb->real_offset = cfg->real_offset;
8078         start_bblock->next_bb = init_localsbb;
8079         init_localsbb->next_bb = cfg->cbb;
8080         link_bblock (cfg, start_bblock, init_localsbb);
8081         link_bblock (cfg, init_localsbb, cfg->cbb);
8082                 
8083         cfg->cbb = init_localsbb;
8084
8085         if (cfg->gsharedvt && cfg->method == method) {
8086                 MonoGSharedVtMethodInfo *info;
8087                 MonoInst *var, *locals_var;
8088                 int dreg;
8089
8090                 info = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoGSharedVtMethodInfo));
8091                 info->method = cfg->method;
8092                 info->count_entries = 16;
8093                 info->entries = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
8094                 cfg->gsharedvt_info = info;
8095
8096                 var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8097                 /* prevent it from being register allocated */
8098                 //var->flags |= MONO_INST_VOLATILE;
8099                 cfg->gsharedvt_info_var = var;
8100
8101                 ins = emit_get_rgctx_gsharedvt_method (cfg, mini_method_check_context_used (cfg, method), method, info);
8102                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, var->dreg, ins->dreg);
8103
8104                 /* Allocate locals */
8105                 locals_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8106                 /* prevent it from being register allocated */
8107                 //locals_var->flags |= MONO_INST_VOLATILE;
8108                 cfg->gsharedvt_locals_var = locals_var;
8109
8110                 dreg = alloc_ireg (cfg);
8111                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, dreg, var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, locals_size));
8112
8113                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
8114                 ins->dreg = locals_var->dreg;
8115                 ins->sreg1 = dreg;
8116                 MONO_ADD_INS (cfg->cbb, ins);
8117                 cfg->gsharedvt_locals_var_ins = ins;
8118                 
8119                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
8120                 /*
8121                 if (init_locals)
8122                         ins->flags |= MONO_INST_INIT;
8123                 */
8124         }
8125
8126         if (mono_security_core_clr_enabled ()) {
8127                 /* check if this is native code, e.g. an icall or a p/invoke */
8128                 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
8129                         MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
8130                         if (wrapped) {
8131                                 gboolean pinvk = (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL);
8132                                 gboolean icall = (wrapped->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL);
8133
8134                                 /* if this ia a native call then it can only be JITted from platform code */
8135                                 if ((icall || pinvk) && method->klass && method->klass->image) {
8136                                         if (!mono_security_core_clr_is_platform_image (method->klass->image)) {
8137                                                 MonoException *ex = icall ? mono_get_exception_security () : 
8138                                                         mono_get_exception_method_access ();
8139                                                 emit_throw_exception (cfg, ex);
8140                                         }
8141                                 }
8142                         }
8143                 }
8144         }
8145
8146         CHECK_CFG_EXCEPTION;
8147
8148         if (header->code_size == 0)
8149                 UNVERIFIED;
8150
8151         if (get_basic_blocks (cfg, header, cfg->real_offset, ip, end, &err_pos)) {
8152                 ip = err_pos;
8153                 UNVERIFIED;
8154         }
8155
8156         if (cfg->method == method)
8157                 mono_debug_init_method (cfg, cfg->cbb, breakpoint_id);
8158
8159         for (n = 0; n < header->num_locals; ++n) {
8160                 if (header->locals [n]->type == MONO_TYPE_VOID && !header->locals [n]->byref)
8161                         UNVERIFIED;
8162         }
8163         class_inits = NULL;
8164
8165         /* We force the vtable variable here for all shared methods
8166            for the possibility that they might show up in a stack
8167            trace where their exact instantiation is needed. */
8168         if (cfg->gshared && method == cfg->method) {
8169                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
8170                                 mini_method_get_context (method)->method_inst ||
8171                                 method->klass->valuetype) {
8172                         mono_get_vtable_var (cfg);
8173                 } else {
8174                         /* FIXME: Is there a better way to do this?
8175                            We need the variable live for the duration
8176                            of the whole method. */
8177                         cfg->args [0]->flags |= MONO_INST_VOLATILE;
8178                 }
8179         }
8180
8181         /* add a check for this != NULL to inlined methods */
8182         if (is_virtual_call) {
8183                 MonoInst *arg_ins;
8184
8185                 NEW_ARGLOAD (cfg, arg_ins, 0);
8186                 MONO_ADD_INS (cfg->cbb, arg_ins);
8187                 MONO_EMIT_NEW_CHECK_THIS (cfg, arg_ins->dreg);
8188         }
8189
8190         skip_dead_blocks = !dont_verify;
8191         if (skip_dead_blocks) {
8192                 original_bb = bb = mono_basic_block_split (method, &cfg->error);
8193                 CHECK_CFG_ERROR;
8194                 g_assert (bb);
8195         }
8196
8197         /* we use a spare stack slot in SWITCH and NEWOBJ and others */
8198         stack_start = sp = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
8199
8200         ins_flag = 0;
8201         start_new_bblock = 0;
8202         while (ip < end) {
8203                 if (cfg->method == method)
8204                         cfg->real_offset = ip - header->code;
8205                 else
8206                         cfg->real_offset = inline_offset;
8207                 cfg->ip = ip;
8208
8209                 context_used = 0;
8210
8211                 if (start_new_bblock) {
8212                         cfg->cbb->cil_length = ip - cfg->cbb->cil_code;
8213                         if (start_new_bblock == 2) {
8214                                 g_assert (ip == tblock->cil_code);
8215                         } else {
8216                                 GET_BBLOCK (cfg, tblock, ip);
8217                         }
8218                         cfg->cbb->next_bb = tblock;
8219                         cfg->cbb = tblock;
8220                         start_new_bblock = 0;
8221                         for (i = 0; i < cfg->cbb->in_scount; ++i) {
8222                                 if (cfg->verbose_level > 3)
8223                                         printf ("loading %d from temp %d\n", i, (int)cfg->cbb->in_stack [i]->inst_c0);
8224                                 EMIT_NEW_TEMPLOAD (cfg, ins, cfg->cbb->in_stack [i]->inst_c0);
8225                                 *sp++ = ins;
8226                         }
8227                         if (class_inits)
8228                                 g_slist_free (class_inits);
8229                         class_inits = NULL;
8230                 } else {
8231                         if ((tblock = cfg->cil_offset_to_bb [ip - cfg->cil_start]) && (tblock != cfg->cbb)) {
8232                                 link_bblock (cfg, cfg->cbb, tblock);
8233                                 if (sp != stack_start) {
8234                                         handle_stack_args (cfg, stack_start, sp - stack_start);
8235                                         sp = stack_start;
8236                                         CHECK_UNVERIFIABLE (cfg);
8237                                 }
8238                                 cfg->cbb->next_bb = tblock;
8239                                 cfg->cbb = tblock;
8240                                 for (i = 0; i < cfg->cbb->in_scount; ++i) {
8241                                         if (cfg->verbose_level > 3)
8242                                                 printf ("loading %d from temp %d\n", i, (int)cfg->cbb->in_stack [i]->inst_c0);
8243                                         EMIT_NEW_TEMPLOAD (cfg, ins, cfg->cbb->in_stack [i]->inst_c0);
8244                                         *sp++ = ins;
8245                                 }
8246                                 g_slist_free (class_inits);
8247                                 class_inits = NULL;
8248                         }
8249                 }
8250
8251                 if (skip_dead_blocks) {
8252                         int ip_offset = ip - header->code;
8253
8254                         if (ip_offset == bb->end)
8255                                 bb = bb->next;
8256
8257                         if (bb->dead) {
8258                                 int op_size = mono_opcode_size (ip, end);
8259                                 g_assert (op_size > 0); /*The BB formation pass must catch all bad ops*/
8260
8261                                 if (cfg->verbose_level > 3) printf ("SKIPPING DEAD OP at %x\n", ip_offset);
8262
8263                                 if (ip_offset + op_size == bb->end) {
8264                                         MONO_INST_NEW (cfg, ins, OP_NOP);
8265                                         MONO_ADD_INS (cfg->cbb, ins);
8266                                         start_new_bblock = 1;
8267                                 }
8268
8269                                 ip += op_size;
8270                                 continue;
8271                         }
8272                 }
8273                 /*
8274                  * Sequence points are points where the debugger can place a breakpoint.
8275                  * Currently, we generate these automatically at points where the IL
8276                  * stack is empty.
8277                  */
8278                 if (seq_points && ((!sym_seq_points && (sp == stack_start)) || (sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code)))) {
8279                         /*
8280                          * Make methods interruptable at the beginning, and at the targets of
8281                          * backward branches.
8282                          * Also, do this at the start of every bblock in methods with clauses too,
8283                          * to be able to handle instructions with inprecise control flow like
8284                          * throw/endfinally.
8285                          * Backward branches are handled at the end of method-to-ir ().
8286                          */
8287                         gboolean intr_loc = ip == header->code || (!cfg->cbb->last_ins && cfg->header->num_clauses);
8288                         gboolean sym_seq_point = sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code);
8289
8290                         /* Avoid sequence points on empty IL like .volatile */
8291                         // FIXME: Enable this
8292                         //if (!(cfg->cbb->last_ins && cfg->cbb->last_ins->opcode == OP_SEQ_POINT)) {
8293                         NEW_SEQ_POINT (cfg, ins, ip - header->code, intr_loc);
8294                         if ((sp != stack_start) && !sym_seq_point)
8295                                 ins->flags |= MONO_INST_NONEMPTY_STACK;
8296                         MONO_ADD_INS (cfg->cbb, ins);
8297
8298                         if (sym_seq_points)
8299                                 mono_bitset_set_fast (seq_point_set_locs, ip - header->code);
8300                 }
8301
8302                 cfg->cbb->real_offset = cfg->real_offset;
8303
8304                 if ((cfg->method == method) && cfg->coverage_info) {
8305                         guint32 cil_offset = ip - header->code;
8306                         cfg->coverage_info->data [cil_offset].cil_code = ip;
8307
8308                         /* TODO: Use an increment here */
8309 #if defined(TARGET_X86)
8310                         MONO_INST_NEW (cfg, ins, OP_STORE_MEM_IMM);
8311                         ins->inst_p0 = &(cfg->coverage_info->data [cil_offset].count);
8312                         ins->inst_imm = 1;
8313                         MONO_ADD_INS (cfg->cbb, ins);
8314 #else
8315                         EMIT_NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
8316                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, ins->dreg, 0, 1);
8317 #endif
8318                 }
8319
8320                 if (cfg->verbose_level > 3)
8321                         printf ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
8322
8323                 switch (*ip) {
8324                 case CEE_NOP:
8325                         if (seq_points && !sym_seq_points && sp != stack_start) {
8326                                 /*
8327                                  * The C# compiler uses these nops to notify the JIT that it should
8328                                  * insert seq points.
8329                                  */
8330                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, FALSE);
8331                                 MONO_ADD_INS (cfg->cbb, ins);
8332                         }
8333                         if (cfg->keep_cil_nops)
8334                                 MONO_INST_NEW (cfg, ins, OP_HARD_NOP);
8335                         else
8336                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8337                         ip++;
8338                         MONO_ADD_INS (cfg->cbb, ins);
8339                         break;
8340                 case CEE_BREAK:
8341                         if (should_insert_brekpoint (cfg->method)) {
8342                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
8343                         } else {
8344                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8345                         }
8346                         ip++;
8347                         MONO_ADD_INS (cfg->cbb, ins);
8348                         break;
8349                 case CEE_LDARG_0:
8350                 case CEE_LDARG_1:
8351                 case CEE_LDARG_2:
8352                 case CEE_LDARG_3:
8353                         CHECK_STACK_OVF (1);
8354                         n = (*ip)-CEE_LDARG_0;
8355                         CHECK_ARG (n);
8356                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8357                         ip++;
8358                         *sp++ = ins;
8359                         break;
8360                 case CEE_LDLOC_0:
8361                 case CEE_LDLOC_1:
8362                 case CEE_LDLOC_2:
8363                 case CEE_LDLOC_3:
8364                         CHECK_STACK_OVF (1);
8365                         n = (*ip)-CEE_LDLOC_0;
8366                         CHECK_LOCAL (n);
8367                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8368                         ip++;
8369                         *sp++ = ins;
8370                         break;
8371                 case CEE_STLOC_0:
8372                 case CEE_STLOC_1:
8373                 case CEE_STLOC_2:
8374                 case CEE_STLOC_3: {
8375                         CHECK_STACK (1);
8376                         n = (*ip)-CEE_STLOC_0;
8377                         CHECK_LOCAL (n);
8378                         --sp;
8379                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
8380                                 UNVERIFIED;
8381                         emit_stloc_ir (cfg, sp, header, n);
8382                         ++ip;
8383                         inline_costs += 1;
8384                         break;
8385                         }
8386                 case CEE_LDARG_S:
8387                         CHECK_OPSIZE (2);
8388                         CHECK_STACK_OVF (1);
8389                         n = ip [1];
8390                         CHECK_ARG (n);
8391                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8392                         *sp++ = ins;
8393                         ip += 2;
8394                         break;
8395                 case CEE_LDARGA_S:
8396                         CHECK_OPSIZE (2);
8397                         CHECK_STACK_OVF (1);
8398                         n = ip [1];
8399                         CHECK_ARG (n);
8400                         NEW_ARGLOADA (cfg, ins, n);
8401                         MONO_ADD_INS (cfg->cbb, ins);
8402                         *sp++ = ins;
8403                         ip += 2;
8404                         break;
8405                 case CEE_STARG_S:
8406                         CHECK_OPSIZE (2);
8407                         CHECK_STACK (1);
8408                         --sp;
8409                         n = ip [1];
8410                         CHECK_ARG (n);
8411                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [ip [1]], *sp))
8412                                 UNVERIFIED;
8413                         EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
8414                         ip += 2;
8415                         break;
8416                 case CEE_LDLOC_S:
8417                         CHECK_OPSIZE (2);
8418                         CHECK_STACK_OVF (1);
8419                         n = ip [1];
8420                         CHECK_LOCAL (n);
8421                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8422                         *sp++ = ins;
8423                         ip += 2;
8424                         break;
8425                 case CEE_LDLOCA_S: {
8426                         unsigned char *tmp_ip;
8427                         CHECK_OPSIZE (2);
8428                         CHECK_STACK_OVF (1);
8429                         CHECK_LOCAL (ip [1]);
8430
8431                         if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 1))) {
8432                                 ip = tmp_ip;
8433                                 inline_costs += 1;
8434                                 break;
8435                         }
8436
8437                         EMIT_NEW_LOCLOADA (cfg, ins, ip [1]);
8438                         *sp++ = ins;
8439                         ip += 2;
8440                         break;
8441                 }
8442                 case CEE_STLOC_S:
8443                         CHECK_OPSIZE (2);
8444                         CHECK_STACK (1);
8445                         --sp;
8446                         CHECK_LOCAL (ip [1]);
8447                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [ip [1]], *sp))
8448                                 UNVERIFIED;
8449                         emit_stloc_ir (cfg, sp, header, ip [1]);
8450                         ip += 2;
8451                         inline_costs += 1;
8452                         break;
8453                 case CEE_LDNULL:
8454                         CHECK_STACK_OVF (1);
8455                         EMIT_NEW_PCONST (cfg, ins, NULL);
8456                         ins->type = STACK_OBJ;
8457                         ++ip;
8458                         *sp++ = ins;
8459                         break;
8460                 case CEE_LDC_I4_M1:
8461                         CHECK_STACK_OVF (1);
8462                         EMIT_NEW_ICONST (cfg, ins, -1);
8463                         ++ip;
8464                         *sp++ = ins;
8465                         break;
8466                 case CEE_LDC_I4_0:
8467                 case CEE_LDC_I4_1:
8468                 case CEE_LDC_I4_2:
8469                 case CEE_LDC_I4_3:
8470                 case CEE_LDC_I4_4:
8471                 case CEE_LDC_I4_5:
8472                 case CEE_LDC_I4_6:
8473                 case CEE_LDC_I4_7:
8474                 case CEE_LDC_I4_8:
8475                         CHECK_STACK_OVF (1);
8476                         EMIT_NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
8477                         ++ip;
8478                         *sp++ = ins;
8479                         break;
8480                 case CEE_LDC_I4_S:
8481                         CHECK_OPSIZE (2);
8482                         CHECK_STACK_OVF (1);
8483                         ++ip;
8484                         EMIT_NEW_ICONST (cfg, ins, *((signed char*)ip));
8485                         ++ip;
8486                         *sp++ = ins;
8487                         break;
8488                 case CEE_LDC_I4:
8489                         CHECK_OPSIZE (5);
8490                         CHECK_STACK_OVF (1);
8491                         EMIT_NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
8492                         ip += 5;
8493                         *sp++ = ins;
8494                         break;
8495                 case CEE_LDC_I8:
8496                         CHECK_OPSIZE (9);
8497                         CHECK_STACK_OVF (1);
8498                         MONO_INST_NEW (cfg, ins, OP_I8CONST);
8499                         ins->type = STACK_I8;
8500                         ins->dreg = alloc_dreg (cfg, STACK_I8);
8501                         ++ip;
8502                         ins->inst_l = (gint64)read64 (ip);
8503                         MONO_ADD_INS (cfg->cbb, ins);
8504                         ip += 8;
8505                         *sp++ = ins;
8506                         break;
8507                 case CEE_LDC_R4: {
8508                         float *f;
8509                         gboolean use_aotconst = FALSE;
8510
8511 #ifdef TARGET_POWERPC
8512                         /* FIXME: Clean this up */
8513                         if (cfg->compile_aot)
8514                                 use_aotconst = TRUE;
8515 #endif
8516
8517                         /* FIXME: we should really allocate this only late in the compilation process */
8518                         f = mono_domain_alloc (cfg->domain, sizeof (float));
8519                         CHECK_OPSIZE (5);
8520                         CHECK_STACK_OVF (1);
8521
8522                         if (use_aotconst) {
8523                                 MonoInst *cons;
8524                                 int dreg;
8525
8526                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R4, f);
8527
8528                                 dreg = alloc_freg (cfg);
8529                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR4_MEMBASE, dreg, cons->dreg, 0);
8530                                 ins->type = cfg->r4_stack_type;
8531                         } else {
8532                                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
8533                                 ins->type = cfg->r4_stack_type;
8534                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8535                                 ins->inst_p0 = f;
8536                                 MONO_ADD_INS (cfg->cbb, ins);
8537                         }
8538                         ++ip;
8539                         readr4 (ip, f);
8540                         ip += 4;
8541                         *sp++ = ins;                    
8542                         break;
8543                 }
8544                 case CEE_LDC_R8: {
8545                         double *d;
8546                         gboolean use_aotconst = FALSE;
8547
8548 #ifdef TARGET_POWERPC
8549                         /* FIXME: Clean this up */
8550                         if (cfg->compile_aot)
8551                                 use_aotconst = TRUE;
8552 #endif
8553
8554                         /* FIXME: we should really allocate this only late in the compilation process */
8555                         d = mono_domain_alloc (cfg->domain, sizeof (double));
8556                         CHECK_OPSIZE (9);
8557                         CHECK_STACK_OVF (1);
8558
8559                         if (use_aotconst) {
8560                                 MonoInst *cons;
8561                                 int dreg;
8562
8563                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R8, d);
8564
8565                                 dreg = alloc_freg (cfg);
8566                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR8_MEMBASE, dreg, cons->dreg, 0);
8567                                 ins->type = STACK_R8;
8568                         } else {
8569                                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
8570                                 ins->type = STACK_R8;
8571                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8572                                 ins->inst_p0 = d;
8573                                 MONO_ADD_INS (cfg->cbb, ins);
8574                         }
8575                         ++ip;
8576                         readr8 (ip, d);
8577                         ip += 8;
8578                         *sp++ = ins;
8579                         break;
8580                 }
8581                 case CEE_DUP: {
8582                         MonoInst *temp, *store;
8583                         CHECK_STACK (1);
8584                         CHECK_STACK_OVF (1);
8585                         sp--;
8586                         ins = *sp;
8587
8588                         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
8589                         EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
8590
8591                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8592                         *sp++ = ins;
8593
8594                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8595                         *sp++ = ins;
8596
8597                         ++ip;
8598                         inline_costs += 2;
8599                         break;
8600                 }
8601                 case CEE_POP:
8602                         CHECK_STACK (1);
8603                         ip++;
8604                         --sp;
8605
8606 #ifdef TARGET_X86
8607                         if (sp [0]->type == STACK_R8)
8608                                 /* we need to pop the value from the x86 FP stack */
8609                                 MONO_EMIT_NEW_UNALU (cfg, OP_X86_FPOP, -1, sp [0]->dreg);
8610 #endif
8611                         break;
8612                 case CEE_JMP: {
8613                         MonoCallInst *call;
8614
8615                         INLINE_FAILURE ("jmp");
8616                         GSHAREDVT_FAILURE (*ip);
8617
8618                         CHECK_OPSIZE (5);
8619                         if (stack_start != sp)
8620                                 UNVERIFIED;
8621                         token = read32 (ip + 1);
8622                         /* FIXME: check the signature matches */
8623                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
8624
8625                         if (!cmethod || mono_loader_get_last_error ())
8626                                 LOAD_ERROR;
8627  
8628                         if (cfg->gshared && mono_method_check_context_used (cmethod))
8629                                 GENERIC_SHARING_FAILURE (CEE_JMP);
8630
8631                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
8632
8633                         if (ARCH_HAVE_OP_TAIL_CALL) {
8634                                 MonoMethodSignature *fsig = mono_method_signature (cmethod);
8635                                 int i, n;
8636
8637                                 /* Handle tail calls similarly to calls */
8638                                 n = fsig->param_count + fsig->hasthis;
8639
8640                                 DISABLE_AOT (cfg);
8641
8642                                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
8643                                 call->method = cmethod;
8644                                 call->tail_call = TRUE;
8645                                 call->signature = mono_method_signature (cmethod);
8646                                 call->args = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
8647                                 call->inst.inst_p0 = cmethod;
8648                                 for (i = 0; i < n; ++i)
8649                                         EMIT_NEW_ARGLOAD (cfg, call->args [i], i);
8650
8651                                 mono_arch_emit_call (cfg, call);
8652                                 cfg->param_area = MAX(cfg->param_area, call->stack_usage);
8653                                 MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
8654                         } else {
8655                                 for (i = 0; i < num_args; ++i)
8656                                         /* Prevent arguments from being optimized away */
8657                                         arg_array [i]->flags |= MONO_INST_VOLATILE;
8658
8659                                 MONO_INST_NEW_CALL (cfg, call, OP_JMP);
8660                                 ins = (MonoInst*)call;
8661                                 ins->inst_p0 = cmethod;
8662                                 MONO_ADD_INS (cfg->cbb, ins);
8663                         }
8664
8665                         ip += 5;
8666                         start_new_bblock = 1;
8667                         break;
8668                 }
8669                 case CEE_CALLI: {
8670                         MonoInst *addr;
8671                         MonoMethodSignature *fsig;
8672
8673                         CHECK_OPSIZE (5);
8674                         token = read32 (ip + 1);
8675
8676                         ins = NULL;
8677
8678                         //GSHAREDVT_FAILURE (*ip);
8679                         cmethod = NULL;
8680                         CHECK_STACK (1);
8681                         --sp;
8682                         addr = *sp;
8683                         fsig = mini_get_signature (method, token, generic_context);
8684
8685                         if (method->dynamic && fsig->pinvoke) {
8686                                 MonoInst *args [3];
8687
8688                                 /*
8689                                  * This is a call through a function pointer using a pinvoke
8690                                  * signature. Have to create a wrapper and call that instead.
8691                                  * FIXME: This is very slow, need to create a wrapper at JIT time
8692                                  * instead based on the signature.
8693                                  */
8694                                 EMIT_NEW_IMAGECONST (cfg, args [0], method->klass->image);
8695                                 EMIT_NEW_PCONST (cfg, args [1], fsig);
8696                                 args [2] = addr;
8697                                 addr = mono_emit_jit_icall (cfg, mono_get_native_calli_wrapper, args);
8698                         }
8699
8700                         n = fsig->param_count + fsig->hasthis;
8701
8702                         CHECK_STACK (n);
8703
8704                         //g_assert (!virtual || fsig->hasthis);
8705
8706                         sp -= n;
8707
8708                         inline_costs += 10 * num_calls++;
8709
8710                         /*
8711                          * Making generic calls out of gsharedvt methods.
8712                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
8713                          * patching gshared method addresses into a gsharedvt method.
8714                          */
8715                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
8716                                 /*
8717                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
8718                                  */
8719                                 MonoInst *callee = addr;
8720
8721                                 if (method->wrapper_type != MONO_WRAPPER_DELEGATE_INVOKE)
8722                                         /* Not tested */
8723                                         GSHAREDVT_FAILURE (*ip);
8724
8725                                 addr = emit_get_rgctx_sig (cfg, context_used,
8726                                                                                           fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
8727                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
8728                                 goto calli_end;
8729                         }
8730
8731                         /* Prevent inlining of methods with indirect calls */
8732                         INLINE_FAILURE ("indirect call");
8733
8734                         if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST || addr->opcode == OP_GOT_ENTRY) {
8735                                 int info_type;
8736                                 gpointer info_data;
8737
8738                                 /*
8739                                  * Instead of emitting an indirect call, emit a direct call
8740                                  * with the contents of the aotconst as the patch info.
8741                                  */
8742                                 if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST) {
8743                                         info_type = addr->inst_c1;
8744                                         info_data = addr->inst_p0;
8745                                 } else {
8746                                         info_type = addr->inst_right->inst_c1;
8747                                         info_data = addr->inst_right->inst_left;
8748                                 }
8749
8750                                 if (info_type == MONO_PATCH_INFO_ICALL_ADDR || info_type == MONO_PATCH_INFO_JIT_ICALL_ADDR) {
8751                                         ins = (MonoInst*)mono_emit_abs_call (cfg, info_type, info_data, fsig, sp);
8752                                         NULLIFY_INS (addr);
8753                                         goto calli_end;
8754                                 }
8755                         }
8756                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8757
8758                         calli_end:
8759
8760                         /* End of call, INS should contain the result of the call, if any */
8761
8762                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8763                                 g_assert (ins);
8764                                 *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
8765                         }
8766
8767                         CHECK_CFG_EXCEPTION;
8768
8769                         ip += 5;
8770                         ins_flag = 0;
8771                         constrained_class = NULL;
8772                         break;
8773                 }
8774                 case CEE_CALL:
8775                 case CEE_CALLVIRT: {
8776                         MonoInst *addr = NULL;
8777                         MonoMethodSignature *fsig = NULL;
8778                         int array_rank = 0;
8779                         int virtual = *ip == CEE_CALLVIRT;
8780                         gboolean pass_imt_from_rgctx = FALSE;
8781                         MonoInst *imt_arg = NULL;
8782                         MonoInst *keep_this_alive = NULL;
8783                         gboolean pass_vtable = FALSE;
8784                         gboolean pass_mrgctx = FALSE;
8785                         MonoInst *vtable_arg = NULL;
8786                         gboolean check_this = FALSE;
8787                         gboolean supported_tail_call = FALSE;
8788                         gboolean tail_call = FALSE;
8789                         gboolean need_seq_point = FALSE;
8790                         guint32 call_opcode = *ip;
8791                         gboolean emit_widen = TRUE;
8792                         gboolean push_res = TRUE;
8793                         gboolean skip_ret = FALSE;
8794                         gboolean delegate_invoke = FALSE;
8795                         gboolean direct_icall = FALSE;
8796                         gboolean constrained_partial_call = FALSE;
8797                         MonoMethod *cil_method;
8798
8799                         CHECK_OPSIZE (5);
8800                         token = read32 (ip + 1);
8801
8802                         ins = NULL;
8803
8804                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
8805                         cil_method = cmethod;
8806                                 
8807                         if (constrained_class) {
8808                                 if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->gshared) {
8809                                         if (!mini_is_gsharedvt_klass (constrained_class)) {
8810                                                 g_assert (!cmethod->klass->valuetype);
8811                                                 if (!mini_type_is_reference (&constrained_class->byval_arg))
8812                                                         constrained_partial_call = TRUE;
8813                                         }
8814                                 }
8815
8816                                 if (method->wrapper_type != MONO_WRAPPER_NONE) {
8817                                         if (cfg->verbose_level > 2)
8818                                                 printf ("DM Constrained call to %s\n", mono_type_get_full_name (constrained_class));
8819                                         if (!((constrained_class->byval_arg.type == MONO_TYPE_VAR ||
8820                                                    constrained_class->byval_arg.type == MONO_TYPE_MVAR) &&
8821                                                   cfg->gshared)) {
8822                                                 cmethod = mono_get_method_constrained_with_method (image, cil_method, constrained_class, generic_context, &cfg->error);
8823                                                 CHECK_CFG_ERROR;
8824                                         }
8825                                 } else {
8826                                         if (cfg->verbose_level > 2)
8827                                                 printf ("Constrained call to %s\n", mono_type_get_full_name (constrained_class));
8828
8829                                         if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->gshared) {
8830                                                 /* 
8831                                                  * This is needed since get_method_constrained can't find 
8832                                                  * the method in klass representing a type var.
8833                                                  * The type var is guaranteed to be a reference type in this
8834                                                  * case.
8835                                                  */
8836                                                 if (!mini_is_gsharedvt_klass (constrained_class))
8837                                                         g_assert (!cmethod->klass->valuetype);
8838                                         } else {
8839                                                 cmethod = mono_get_method_constrained_checked (image, token, constrained_class, generic_context, &cil_method, &cfg->error);
8840                                                 CHECK_CFG_ERROR;
8841                                         }
8842                                 }
8843                         }
8844                                         
8845                         if (!cmethod || mono_loader_get_last_error ())
8846                                 LOAD_ERROR;
8847                         if (!dont_verify && !cfg->skip_visibility) {
8848                                 MonoMethod *target_method = cil_method;
8849                                 if (method->is_inflated) {
8850                                         target_method = mini_get_method_allow_open (method, token, NULL, &(mono_method_get_generic_container (method_definition)->context));
8851                                 }
8852                                 if (!mono_method_can_access_method (method_definition, target_method) &&
8853                                         !mono_method_can_access_method (method, cil_method))
8854                                         METHOD_ACCESS_FAILURE (method, cil_method);
8855                         }
8856
8857                         if (mono_security_core_clr_enabled ())
8858                                 ensure_method_is_allowed_to_call_method (cfg, method, cil_method);
8859
8860                         if (!virtual && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
8861                                 /* MS.NET seems to silently convert this to a callvirt */
8862                                 virtual = 1;
8863
8864                         {
8865                                 /*
8866                                  * MS.NET accepts non virtual calls to virtual final methods of transparent proxy classes and
8867                                  * converts to a callvirt.
8868                                  *
8869                                  * tests/bug-515884.il is an example of this behavior
8870                                  */
8871                                 const int test_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_STATIC;
8872                                 const int expected_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL;
8873                                 if (!virtual && mono_class_is_marshalbyref (cmethod->klass) && (cmethod->flags & test_flags) == expected_flags && cfg->method->wrapper_type == MONO_WRAPPER_NONE)
8874                                         virtual = 1;
8875                         }
8876
8877                         if (!cmethod->klass->inited)
8878                                 if (!mono_class_init (cmethod->klass))
8879                                         TYPE_LOAD_ERROR (cmethod->klass);
8880
8881                         fsig = mono_method_signature (cmethod);
8882                         if (!fsig)
8883                                 LOAD_ERROR;
8884                         if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
8885                                 mini_class_is_system_array (cmethod->klass)) {
8886                                 array_rank = cmethod->klass->rank;
8887                         } else if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && icall_is_direct_callable (cfg, cmethod)) {
8888                                 direct_icall = TRUE;
8889                         } else if (fsig->pinvoke) {
8890                                 MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
8891                                 fsig = mono_method_signature (wrapper);
8892                         } else if (constrained_class) {
8893                         } else {
8894                                 fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
8895                                 CHECK_CFG_ERROR;
8896                         }
8897
8898                         /* See code below */
8899                         if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
8900                                 MonoBasicBlock *tbb;
8901
8902                                 GET_BBLOCK (cfg, tbb, ip + 5);
8903                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
8904                                         /*
8905                                          * We want to extend the try block to cover the call, but we can't do it if the
8906                                          * call is made directly since its followed by an exception check.
8907                                          */
8908                                         direct_icall = FALSE;
8909                                 }
8910                         }
8911
8912                         mono_save_token_info (cfg, image, token, cil_method);
8913
8914                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip + 5 - header->code)))
8915                                 need_seq_point = TRUE;
8916
8917                         /* Don't support calls made using type arguments for now */
8918                         /*
8919                           if (cfg->gsharedvt) {
8920                           if (mini_is_gsharedvt_signature (fsig))
8921                           GSHAREDVT_FAILURE (*ip);
8922                           }
8923                         */
8924
8925                         if (cmethod->string_ctor && method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE)
8926                                 g_assert_not_reached ();
8927
8928                         n = fsig->param_count + fsig->hasthis;
8929
8930                         if (!cfg->gshared && cmethod->klass->generic_container)
8931                                 UNVERIFIED;
8932
8933                         if (!cfg->gshared)
8934                                 g_assert (!mono_method_check_context_used (cmethod));
8935
8936                         CHECK_STACK (n);
8937
8938                         //g_assert (!virtual || fsig->hasthis);
8939
8940                         sp -= n;
8941
8942                         if (constrained_class) {
8943                                 if (mini_is_gsharedvt_klass (constrained_class)) {
8944                                         if ((cmethod->klass != mono_defaults.object_class) && constrained_class->valuetype && cmethod->klass->valuetype) {
8945                                                 /* The 'Own method' case below */
8946                                         } else if (cmethod->klass->image != mono_defaults.corlib && !(cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !cmethod->klass->valuetype) {
8947                                                 /* 'The type parameter is instantiated as a reference type' case below. */
8948                                         } else {
8949                                                 ins = handle_constrained_gsharedvt_call (cfg, cmethod, fsig, sp, constrained_class, &emit_widen);
8950                                                 CHECK_CFG_EXCEPTION;
8951                                                 g_assert (ins);
8952                                                 goto call_end;
8953                                         }
8954                                 }
8955
8956                                 /*
8957                                  * We have the `constrained.' prefix opcode.
8958                                  */
8959                                 if (constrained_partial_call) {
8960                                         gboolean need_box = TRUE;
8961
8962                                         /*
8963                                          * The receiver is a valuetype, but the exact type is not known at compile time. This means the
8964                                          * called method is not known at compile time either. The called method could end up being
8965                                          * one of the methods on the parent classes (object/valuetype/enum), in which case we need
8966                                          * to box the receiver.
8967                                          * A simple solution would be to box always and make a normal virtual call, but that would
8968                                          * be bad performance wise.
8969                                          */
8970                                         if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE && cmethod->klass->generic_class) {
8971                                                 /*
8972                                                  * The parent classes implement no generic interfaces, so the called method will be a vtype method, so no boxing neccessary.
8973                                                  */
8974                                                 need_box = FALSE;
8975                                         }
8976
8977                                         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)) {
8978                                                 /* The called method is not virtual, i.e. Object:GetType (), the receiver is a vtype, has to box */
8979                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
8980                                                 ins->klass = constrained_class;
8981                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
8982                                                 CHECK_CFG_EXCEPTION;
8983                                         } else if (need_box) {
8984                                                 MonoInst *box_type;
8985                                                 MonoBasicBlock *is_ref_bb, *end_bb;
8986                                                 MonoInst *nonbox_call;
8987
8988                                                 /*
8989                                                  * Determine at runtime whenever the called method is defined on object/valuetype/enum, and emit a boxing call
8990                                                  * if needed.
8991                                                  * FIXME: It is possible to inline the called method in a lot of cases, i.e. for T_INT,
8992                                                  * the no-box case goes to a method in Int32, while the box case goes to a method in Enum.
8993                                                  */
8994                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
8995
8996                                                 NEW_BBLOCK (cfg, is_ref_bb);
8997                                                 NEW_BBLOCK (cfg, end_bb);
8998
8999                                                 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);
9000                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, box_type->dreg, 1);
9001                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
9002
9003                                                 /* Non-ref case */
9004                                                 nonbox_call = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9005
9006                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
9007
9008                                                 /* Ref case */
9009                                                 MONO_START_BB (cfg, is_ref_bb);
9010                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9011                                                 ins->klass = constrained_class;
9012                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9013                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9014
9015                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
9016
9017                                                 MONO_START_BB (cfg, end_bb);
9018                                                 cfg->cbb = end_bb;
9019
9020                                                 nonbox_call->dreg = ins->dreg;
9021                                                 goto call_end;
9022                                         } else {
9023                                                 g_assert (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE);
9024                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
9025                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9026                                                 goto call_end;
9027                                         }
9028                                 } else if (constrained_class->valuetype && (cmethod->klass == mono_defaults.object_class || cmethod->klass == mono_defaults.enum_class->parent || cmethod->klass == mono_defaults.enum_class)) {
9029                                         /*
9030                                          * The type parameter is instantiated as a valuetype,
9031                                          * but that type doesn't override the method we're
9032                                          * calling, so we need to box `this'.
9033                                          */
9034                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9035                                         ins->klass = constrained_class;
9036                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9037                                         CHECK_CFG_EXCEPTION;
9038                                 } else if (!constrained_class->valuetype) {
9039                                         int dreg = alloc_ireg_ref (cfg);
9040
9041                                         /*
9042                                          * The type parameter is instantiated as a reference
9043                                          * type.  We have a managed pointer on the stack, so
9044                                          * we need to dereference it here.
9045                                          */
9046                                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, sp [0]->dreg, 0);
9047                                         ins->type = STACK_OBJ;
9048                                         sp [0] = ins;
9049                                 } else {
9050                                         if (cmethod->klass->valuetype) {
9051                                                 /* Own method */
9052                                         } else {
9053                                                 /* Interface method */
9054                                                 int ioffset, slot;
9055
9056                                                 mono_class_setup_vtable (constrained_class);
9057                                                 CHECK_TYPELOAD (constrained_class);
9058                                                 ioffset = mono_class_interface_offset (constrained_class, cmethod->klass);
9059                                                 if (ioffset == -1)
9060                                                         TYPE_LOAD_ERROR (constrained_class);
9061                                                 slot = mono_method_get_vtable_slot (cmethod);
9062                                                 if (slot == -1)
9063                                                         TYPE_LOAD_ERROR (cmethod->klass);
9064                                                 cmethod = constrained_class->vtable [ioffset + slot];
9065
9066                                                 if (cmethod->klass == mono_defaults.enum_class) {
9067                                                         /* Enum implements some interfaces, so treat this as the first case */
9068                                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9069                                                         ins->klass = constrained_class;
9070                                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9071                                                         CHECK_CFG_EXCEPTION;
9072                                                 }
9073                                         }
9074                                         virtual = 0;
9075                                 }
9076                                 constrained_class = NULL;
9077                         }
9078
9079                         if (check_call_signature (cfg, fsig, sp))
9080                                 UNVERIFIED;
9081
9082                         if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (cmethod->name, "Invoke"))
9083                                 delegate_invoke = TRUE;
9084
9085                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_sharable_method (cfg, cmethod, fsig, sp))) {
9086                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9087                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
9088                                         emit_widen = FALSE;
9089                                 }
9090
9091                                 goto call_end;
9092                         }
9093
9094                         /* 
9095                          * If the callee is a shared method, then its static cctor
9096                          * might not get called after the call was patched.
9097                          */
9098                         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)) {
9099                                 emit_class_init (cfg, cmethod->klass);
9100                                 CHECK_TYPELOAD (cmethod->klass);
9101                         }
9102
9103                         check_method_sharing (cfg, cmethod, &pass_vtable, &pass_mrgctx);
9104
9105                         if (cfg->gshared) {
9106                                 MonoGenericContext *cmethod_context = mono_method_get_context (cmethod);
9107
9108                                 context_used = mini_method_check_context_used (cfg, cmethod);
9109
9110                                 if (context_used && (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
9111                                         /* Generic method interface
9112                                            calls are resolved via a
9113                                            helper function and don't
9114                                            need an imt. */
9115                                         if (!cmethod_context || !cmethod_context->method_inst)
9116                                                 pass_imt_from_rgctx = TRUE;
9117                                 }
9118
9119                                 /*
9120                                  * If a shared method calls another
9121                                  * shared method then the caller must
9122                                  * have a generic sharing context
9123                                  * because the magic trampoline
9124                                  * requires it.  FIXME: We shouldn't
9125                                  * have to force the vtable/mrgctx
9126                                  * variable here.  Instead there
9127                                  * should be a flag in the cfg to
9128                                  * request a generic sharing context.
9129                                  */
9130                                 if (context_used &&
9131                                                 ((method->flags & METHOD_ATTRIBUTE_STATIC) || method->klass->valuetype))
9132                                         mono_get_vtable_var (cfg);
9133                         }
9134
9135                         if (pass_vtable) {
9136                                 if (context_used) {
9137                                         vtable_arg = emit_get_rgctx_klass (cfg, context_used, cmethod->klass, MONO_RGCTX_INFO_VTABLE);
9138                                 } else {
9139                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
9140
9141                                         CHECK_TYPELOAD (cmethod->klass);
9142                                         EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
9143                                 }
9144                         }
9145
9146                         if (pass_mrgctx) {
9147                                 g_assert (!vtable_arg);
9148
9149                                 if (!cfg->compile_aot) {
9150                                         /* 
9151                                          * emit_get_rgctx_method () calls mono_class_vtable () so check 
9152                                          * for type load errors before.
9153                                          */
9154                                         mono_class_setup_vtable (cmethod->klass);
9155                                         CHECK_TYPELOAD (cmethod->klass);
9156                                 }
9157
9158                                 vtable_arg = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
9159
9160                                 /* !marshalbyref is needed to properly handle generic methods + remoting */
9161                                 if ((!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
9162                                          MONO_METHOD_IS_FINAL (cmethod)) &&
9163                                         !mono_class_is_marshalbyref (cmethod->klass)) {
9164                                         if (virtual)
9165                                                 check_this = TRUE;
9166                                         virtual = 0;
9167                                 }
9168                         }
9169
9170                         if (pass_imt_from_rgctx) {
9171                                 g_assert (!pass_vtable);
9172
9173                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9174                                         cmethod, MONO_RGCTX_INFO_METHOD);
9175                         }
9176
9177                         if (check_this)
9178                                 MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9179
9180                         /* Calling virtual generic methods */
9181                         if (virtual && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) && 
9182                             !(MONO_METHOD_IS_FINAL (cmethod) && 
9183                               cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) &&
9184                             fsig->generic_param_count && 
9185                                 !(cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) &&
9186                                 !cfg->llvm_only) {
9187                                 MonoInst *this_temp, *this_arg_temp, *store;
9188                                 MonoInst *iargs [4];
9189                                 gboolean use_imt = FALSE;
9190
9191                                 g_assert (fsig->is_inflated);
9192
9193                                 /* Prevent inlining of methods that contain indirect calls */
9194                                 INLINE_FAILURE ("virtual generic call");
9195
9196                                 if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))
9197                                         GSHAREDVT_FAILURE (*ip);
9198
9199 #if MONO_ARCH_HAVE_GENERALIZED_IMT_THUNK && defined(MONO_ARCH_GSHARED_SUPPORTED)
9200                                 if (cmethod->wrapper_type == MONO_WRAPPER_NONE)
9201                                         use_imt = TRUE;
9202 #endif
9203
9204                                 if (use_imt) {
9205                                         g_assert (!imt_arg);
9206                                         if (!context_used)
9207                                                 g_assert (cmethod->is_inflated);
9208                                         imt_arg = emit_get_rgctx_method (cfg, context_used,
9209                                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
9210                                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, sp [0], imt_arg, NULL);
9211                                 } else {
9212                                         this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
9213                                         NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
9214                                         MONO_ADD_INS (cfg->cbb, store);
9215
9216                                         /* FIXME: This should be a managed pointer */
9217                                         this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
9218
9219                                         EMIT_NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
9220                                         iargs [1] = emit_get_rgctx_method (cfg, context_used,
9221                                                                                                            cmethod, MONO_RGCTX_INFO_METHOD);
9222                                         EMIT_NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
9223                                         addr = mono_emit_jit_icall (cfg,
9224                                                                                                 mono_helper_compile_generic_method, iargs);
9225
9226                                         EMIT_NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
9227
9228                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9229                                 }
9230
9231                                 goto call_end;
9232                         }
9233
9234                         /*
9235                          * Implement a workaround for the inherent races involved in locking:
9236                          * Monitor.Enter ()
9237                          * try {
9238                          * } finally {
9239                          *    Monitor.Exit ()
9240                          * }
9241                          * If a thread abort happens between the call to Monitor.Enter () and the start of the
9242                          * try block, the Exit () won't be executed, see:
9243                          * http://www.bluebytesoftware.com/blog/2007/01/30/MonitorEnterThreadAbortsAndOrphanedLocks.aspx
9244                          * To work around this, we extend such try blocks to include the last x bytes
9245                          * of the Monitor.Enter () call.
9246                          */
9247                         if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
9248                                 MonoBasicBlock *tbb;
9249
9250                                 GET_BBLOCK (cfg, tbb, ip + 5);
9251                                 /* 
9252                                  * Only extend try blocks with a finally, to avoid catching exceptions thrown
9253                                  * from Monitor.Enter like ArgumentNullException.
9254                                  */
9255                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
9256                                         /* Mark this bblock as needing to be extended */
9257                                         tbb->extend_try_block = TRUE;
9258                                 }
9259                         }
9260
9261                         /* Conversion to a JIT intrinsic */
9262                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_method (cfg, cmethod, fsig, sp))) {
9263                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9264                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
9265                                         emit_widen = FALSE;
9266                                 }
9267                                 goto call_end;
9268                         }
9269
9270                         /* Inlining */
9271                         if ((cfg->opt & MONO_OPT_INLINE) &&
9272                                 (!virtual || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || MONO_METHOD_IS_FINAL (cmethod)) &&
9273                             mono_method_check_inlining (cfg, cmethod)) {
9274                                 int costs;
9275                                 gboolean always = FALSE;
9276
9277                                 if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
9278                                         (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
9279                                         /* Prevent inlining of methods that call wrappers */
9280                                         INLINE_FAILURE ("wrapper call");
9281                                         cmethod = mono_marshal_get_native_wrapper (cmethod, TRUE, FALSE);
9282                                         always = TRUE;
9283                                 }
9284
9285                                 costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, always);
9286                                 if (costs) {
9287                                         cfg->real_offset += 5;
9288
9289                                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9290                                                 /* *sp is already set by inline_method */
9291                                                 sp++;
9292                                                 push_res = FALSE;
9293                                         }
9294
9295                                         inline_costs += costs;
9296
9297                                         goto call_end;
9298                                 }
9299                         }
9300
9301                         /* Tail recursion elimination */
9302                         if ((cfg->opt & MONO_OPT_TAILC) && call_opcode == CEE_CALL && cmethod == method && ip [5] == CEE_RET && !vtable_arg) {
9303                                 gboolean has_vtargs = FALSE;
9304                                 int i;
9305
9306                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9307                                 INLINE_FAILURE ("tail call");
9308
9309                                 /* keep it simple */
9310                                 for (i =  fsig->param_count - 1; i >= 0; i--) {
9311                                         if (MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->params [i])) 
9312                                                 has_vtargs = TRUE;
9313                                 }
9314
9315                                 if (!has_vtargs) {
9316                                         for (i = 0; i < n; ++i)
9317                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9318                                         MONO_INST_NEW (cfg, ins, OP_BR);
9319                                         MONO_ADD_INS (cfg->cbb, ins);
9320                                         tblock = start_bblock->out_bb [0];
9321                                         link_bblock (cfg, cfg->cbb, tblock);
9322                                         ins->inst_target_bb = tblock;
9323                                         start_new_bblock = 1;
9324
9325                                         /* skip the CEE_RET, too */
9326                                         if (ip_in_bb (cfg, cfg->cbb, ip + 5))
9327                                                 skip_ret = TRUE;
9328                                         push_res = FALSE;
9329                                         goto call_end;
9330                                 }
9331                         }
9332
9333                         inline_costs += 10 * num_calls++;
9334
9335                         /*
9336                          * Making generic calls out of gsharedvt methods.
9337                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
9338                          * patching gshared method addresses into a gsharedvt method.
9339                          */
9340                         if (cfg->gsharedvt && (mini_is_gsharedvt_signature (fsig) || cmethod->is_inflated || cmethod->klass->generic_class) &&
9341                                 !(cmethod->klass->rank && cmethod->klass->byval_arg.type != MONO_TYPE_SZARRAY)) {
9342                                 MonoRgctxInfoType info_type;
9343
9344                                 if (virtual) {
9345                                         //if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
9346                                                 //GSHAREDVT_FAILURE (*ip);
9347                                         // disable for possible remoting calls
9348                                         if (fsig->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class))
9349                                                 GSHAREDVT_FAILURE (*ip);
9350                                         if (fsig->generic_param_count) {
9351                                                 /* virtual generic call */
9352                                                 g_assert (!imt_arg);
9353                                                 /* Same as the virtual generic case above */
9354                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9355                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9356                                                 /* This is not needed, as the trampoline code will pass one, and it might be passed in the same reg as the imt arg */
9357                                                 vtable_arg = NULL;
9358                                         } else if ((cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !imt_arg) {
9359                                                 /* This can happen when we call a fully instantiated iface method */
9360                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9361                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9362                                                 vtable_arg = NULL;
9363                                         }
9364                                 }
9365
9366                                 if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (cmethod->name, "Invoke")))
9367                                         keep_this_alive = sp [0];
9368
9369                                 if (virtual && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))
9370                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
9371                                 else
9372                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE;
9373                                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, info_type);
9374
9375                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9376                                 goto call_end;
9377                         }
9378
9379                         /* Generic sharing */
9380
9381                         /*
9382                          * Use this if the callee is gsharedvt sharable too, since
9383                          * at runtime we might find an instantiation so the call cannot
9384                          * be patched (the 'no_patch' code path in mini-trampolines.c).
9385                          */
9386                         if (context_used && !imt_arg && !array_rank && !delegate_invoke &&
9387                                 (!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
9388                                  !mono_class_generic_sharing_enabled (cmethod->klass)) &&
9389                                 (!virtual || MONO_METHOD_IS_FINAL (cmethod) ||
9390                                  !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))) {
9391                                 INLINE_FAILURE ("gshared");
9392
9393                                 g_assert (cfg->gshared && cmethod);
9394                                 g_assert (!addr);
9395
9396                                 /*
9397                                  * We are compiling a call to a
9398                                  * generic method from shared code,
9399                                  * which means that we have to look up
9400                                  * the method in the rgctx and do an
9401                                  * indirect call.
9402                                  */
9403                                 if (fsig->hasthis)
9404                                         MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9405
9406                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
9407                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9408                                 goto call_end;
9409                         }
9410
9411                         /* Direct calls to icalls */
9412                         if (direct_icall) {
9413                                 MonoMethod *wrapper;
9414                                 int costs;
9415
9416                                 /* Inline the wrapper */
9417                                 wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
9418
9419                                 costs = inline_method (cfg, wrapper, fsig, sp, ip, cfg->real_offset, TRUE);
9420                                 g_assert (costs > 0);
9421                                 cfg->real_offset += 5;
9422
9423                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9424                                         /* *sp is already set by inline_method */
9425                                         sp++;
9426                                         push_res = FALSE;
9427                                 }
9428
9429                                 inline_costs += costs;
9430
9431                                 goto call_end;
9432                         }
9433                                         
9434                         /* Array methods */
9435                         if (array_rank) {
9436                                 MonoInst *addr;
9437
9438                                 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ 
9439                                         MonoInst *val = sp [fsig->param_count];
9440
9441                                         if (val->type == STACK_OBJ) {
9442                                                 MonoInst *iargs [2];
9443
9444                                                 iargs [0] = sp [0];
9445                                                 iargs [1] = val;
9446                                                 
9447                                                 mono_emit_jit_icall (cfg, mono_helper_stelem_ref_check, iargs);
9448                                         }
9449                                         
9450                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, TRUE);
9451                                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, fsig->params [fsig->param_count - 1], addr->dreg, 0, val->dreg);
9452                                         if (cfg->gen_write_barriers && val->type == STACK_OBJ && !(val->opcode == OP_PCONST && val->inst_c0 == 0))
9453                                                 emit_write_barrier (cfg, addr, val);
9454                                         if (cfg->gen_write_barriers && mini_is_gsharedvt_klass (cmethod->klass))
9455                                                 GSHAREDVT_FAILURE (*ip);
9456                                 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
9457                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9458
9459                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, addr->dreg, 0);
9460                                 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
9461                                         if (!cmethod->klass->element_class->valuetype && !readonly)
9462                                                 mini_emit_check_array_type (cfg, sp [0], cmethod->klass);
9463                                         CHECK_TYPELOAD (cmethod->klass);
9464                                         
9465                                         readonly = FALSE;
9466                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9467                                         ins = addr;
9468                                 } else {
9469                                         g_assert_not_reached ();
9470                                 }
9471
9472                                 emit_widen = FALSE;
9473                                 goto call_end;
9474                         }
9475
9476                         ins = mini_redirect_call (cfg, cmethod, fsig, sp, virtual ? sp [0] : NULL);
9477                         if (ins)
9478                                 goto call_end;
9479
9480                         /* Tail prefix / tail call optimization */
9481
9482                         /* FIXME: Enabling TAILC breaks some inlining/stack trace/etc tests */
9483                         /* FIXME: runtime generic context pointer for jumps? */
9484                         /* FIXME: handle this for generic sharing eventually */
9485                         if ((ins_flag & MONO_INST_TAILCALL) &&
9486                                 !vtable_arg && !cfg->gshared && is_supported_tail_call (cfg, method, cmethod, fsig, call_opcode))
9487                                 supported_tail_call = TRUE;
9488
9489                         if (supported_tail_call) {
9490                                 MonoCallInst *call;
9491
9492                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9493                                 INLINE_FAILURE ("tail call");
9494
9495                                 //printf ("HIT: %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
9496
9497                                 if (ARCH_HAVE_OP_TAIL_CALL) {
9498                                         /* Handle tail calls similarly to normal calls */
9499                                         tail_call = TRUE;
9500                                 } else {
9501                                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
9502
9503                                         MONO_INST_NEW_CALL (cfg, call, OP_JMP);
9504                                         call->tail_call = TRUE;
9505                                         call->method = cmethod;
9506                                         call->signature = mono_method_signature (cmethod);
9507
9508                                         /*
9509                                          * We implement tail calls by storing the actual arguments into the 
9510                                          * argument variables, then emitting a CEE_JMP.
9511                                          */
9512                                         for (i = 0; i < n; ++i) {
9513                                                 /* Prevent argument from being register allocated */
9514                                                 arg_array [i]->flags |= MONO_INST_VOLATILE;
9515                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9516                                         }
9517                                         ins = (MonoInst*)call;
9518                                         ins->inst_p0 = cmethod;
9519                                         ins->inst_p1 = arg_array [0];
9520                                         MONO_ADD_INS (cfg->cbb, ins);
9521                                         link_bblock (cfg, cfg->cbb, end_bblock);
9522                                         start_new_bblock = 1;
9523
9524                                         // FIXME: Eliminate unreachable epilogs
9525
9526                                         /*
9527                                          * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9528                                          * only reachable from this call.
9529                                          */
9530                                         GET_BBLOCK (cfg, tblock, ip + 5);
9531                                         if (tblock == cfg->cbb || tblock->in_count == 0)
9532                                                 skip_ret = TRUE;
9533                                         push_res = FALSE;
9534
9535                                         goto call_end;
9536                                 }
9537                         }
9538
9539                         /* 
9540                          * Synchronized wrappers.
9541                          * Its hard to determine where to replace a method with its synchronized
9542                          * wrapper without causing an infinite recursion. The current solution is
9543                          * to add the synchronized wrapper in the trampolines, and to
9544                          * change the called method to a dummy wrapper, and resolve that wrapper
9545                          * to the real method in mono_jit_compile_method ().
9546                          */
9547                         if (cfg->method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
9548                                 MonoMethod *orig = mono_marshal_method_from_wrapper (cfg->method);
9549                                 if (cmethod == orig || (cmethod->is_inflated && mono_method_get_declaring_generic_method (cmethod) == orig))
9550                                         cmethod = mono_marshal_get_synchronized_inner_wrapper (cmethod);
9551                         }
9552
9553                         /*
9554                          * Interface calls in llvm-only mode are complicated becase the callee might need an rgctx arg,
9555                          * (i.e. its a vtype method), and there is no way to for the caller to know this at compile time.
9556                          * So we make resolve_iface_call return the rgctx, and do two calls with different signatures
9557                          * based on whenever there is an rgctx or not.
9558                          */
9559                         if (cfg->llvm_only && virtual && cmethod && (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
9560                                 MonoInst *args [16], *icall_args [16];
9561                                 MonoBasicBlock *rgctx_bb, *end_bb;
9562                                 MonoInst *call1, *call2, *call_target;
9563                                 MonoMethodSignature *rgctx_sig;
9564                                 int rgctx_reg, tmp_reg;
9565
9566                                 MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
9567
9568                                 NEW_BBLOCK (cfg, rgctx_bb);
9569                                 NEW_BBLOCK (cfg, end_bb);
9570
9571                                 // FIXME: Optimize this
9572
9573                                 guint32 imt_slot = mono_method_get_imt_slot (cmethod);
9574
9575                                 icall_args [0] = sp [0];
9576                                 EMIT_NEW_ICONST (cfg, icall_args [1], imt_slot);
9577                                 if (imt_arg) {
9578                                         icall_args [2] = imt_arg;
9579                                 } else {
9580                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_METHODCONST, cmethod);
9581                                         icall_args [2] = ins;
9582                                 }
9583
9584                                 rgctx_reg = alloc_preg (cfg);
9585                                 MONO_EMIT_NEW_PCONST (cfg, rgctx_reg, NULL);
9586                                 EMIT_NEW_VARLOADA_VREG (cfg, icall_args [3], rgctx_reg, &mono_defaults.int_class->byval_arg);
9587                                 //EMIT_NEW_PCONST (cfg, icall_args [3], NULL);
9588
9589                                 call_target = mono_emit_jit_icall (cfg, mono_resolve_iface_call, icall_args);
9590
9591                                 // FIXME: Only do this if needed (generic calls)
9592
9593                                 // Check whenever to pass an rgctx
9594                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rgctx_reg, 0);
9595                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, rgctx_bb);
9596                                 /* Non rgctx case */
9597                                 call1 = mono_emit_calli (cfg, fsig, sp, call_target, NULL, vtable_arg);
9598                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
9599                                 /* Rgctx case */
9600                                 MONO_START_BB (cfg, rgctx_bb);
9601                                 /* Make a call with an rgctx */
9602                                 g_assert (fsig->param_count + 2 < 16);
9603                                 args [0] = sp [0];
9604                                 for (i = 0; i < fsig->param_count; ++i)
9605                                         args [i + 1] = sp [i + 1];
9606                                 tmp_reg = alloc_preg (cfg);
9607                                 EMIT_NEW_UNALU (cfg, args [fsig->param_count + 1], OP_MOVE, tmp_reg, rgctx_reg);
9608                                 rgctx_sig = sig_to_rgctx_sig (fsig);
9609                                 call2 = mono_emit_calli (cfg, rgctx_sig, args, call_target, NULL, NULL);
9610                                 call2->dreg = call1->dreg;
9611                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
9612                                 /* End */
9613                                 MONO_START_BB (cfg, end_bb);
9614                                 ins = call1;
9615                                 goto call_end;
9616                         }
9617
9618                         /* Common call */
9619                         INLINE_FAILURE ("call");
9620                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, tail_call, sp, virtual ? sp [0] : NULL,
9621                                                                                           imt_arg, vtable_arg);
9622
9623                         if (tail_call) {
9624                                 link_bblock (cfg, cfg->cbb, end_bblock);
9625                                 start_new_bblock = 1;
9626
9627                                 // FIXME: Eliminate unreachable epilogs
9628
9629                                 /*
9630                                  * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9631                                  * only reachable from this call.
9632                                  */
9633                                 GET_BBLOCK (cfg, tblock, ip + 5);
9634                                 if (tblock == cfg->cbb || tblock->in_count == 0)
9635                                         skip_ret = TRUE;
9636                                 push_res = FALSE;
9637                         }
9638
9639                         call_end:
9640
9641                         /* End of call, INS should contain the result of the call, if any */
9642
9643                         if (push_res && !MONO_TYPE_IS_VOID (fsig->ret)) {
9644                                 g_assert (ins);
9645                                 if (emit_widen)
9646                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
9647                                 else
9648                                         *sp++ = ins;
9649                         }
9650
9651                         if (keep_this_alive) {
9652                                 MonoInst *dummy_use;
9653
9654                                 /* See mono_emit_method_call_full () */
9655                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, keep_this_alive);
9656                         }
9657
9658                         CHECK_CFG_EXCEPTION;
9659
9660                         ip += 5;
9661                         if (skip_ret) {
9662                                 g_assert (*ip == CEE_RET);
9663                                 ip += 1;
9664                         }
9665                         ins_flag = 0;
9666                         constrained_class = NULL;
9667                         if (need_seq_point)
9668                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
9669                         break;
9670                 }
9671                 case CEE_RET:
9672                         if (cfg->method != method) {
9673                                 /* return from inlined method */
9674                                 /* 
9675                                  * If in_count == 0, that means the ret is unreachable due to
9676                                  * being preceeded by a throw. In that case, inline_method () will
9677                                  * handle setting the return value 
9678                                  * (test case: test_0_inline_throw ()).
9679                                  */
9680                                 if (return_var && cfg->cbb->in_count) {
9681                                         MonoType *ret_type = mono_method_signature (method)->ret;
9682
9683                                         MonoInst *store;
9684                                         CHECK_STACK (1);
9685                                         --sp;
9686
9687                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
9688                                                 UNVERIFIED;
9689
9690                                         //g_assert (returnvar != -1);
9691                                         EMIT_NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
9692                                         cfg->ret_var_set = TRUE;
9693                                 } 
9694                         } else {
9695                                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
9696
9697                                 if (cfg->lmf_var && cfg->cbb->in_count && !REALLY_LLVMONLY)
9698                                         emit_pop_lmf (cfg);
9699
9700                                 if (cfg->ret) {
9701                                         MonoType *ret_type = mini_get_underlying_type (mono_method_signature (method)->ret);
9702
9703                                         if (seq_points && !sym_seq_points) {
9704                                                 /* 
9705                                                  * Place a seq point here too even through the IL stack is not
9706                                                  * empty, so a step over on
9707                                                  * call <FOO>
9708                                                  * ret
9709                                                  * will work correctly.
9710                                                  */
9711                                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, TRUE);
9712                                                 MONO_ADD_INS (cfg->cbb, ins);
9713                                         }
9714
9715                                         g_assert (!return_var);
9716                                         CHECK_STACK (1);
9717                                         --sp;
9718
9719                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
9720                                                 UNVERIFIED;
9721
9722                                         if (mini_type_to_stind (cfg, ret_type) == CEE_STOBJ) {
9723                                                 MonoInst *ret_addr;
9724
9725                                                 if (!cfg->vret_addr) {
9726                                                         MonoInst *ins;
9727
9728                                                         EMIT_NEW_VARSTORE (cfg, ins, cfg->ret, ret_type, (*sp));
9729                                                 } else {
9730                                                         EMIT_NEW_RETLOADA (cfg, ret_addr);
9731
9732                                                         EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STOREV_MEMBASE, ret_addr->dreg, 0, (*sp)->dreg);
9733                                                         ins->klass = mono_class_from_mono_type (ret_type);
9734                                                 }
9735                                         } else {
9736 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
9737                                                 if (COMPILE_SOFT_FLOAT (cfg) && !ret_type->byref && ret_type->type == MONO_TYPE_R4) {
9738                                                         MonoInst *iargs [1];
9739                                                         MonoInst *conv;
9740
9741                                                         iargs [0] = *sp;
9742                                                         conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
9743                                                         mono_arch_emit_setret (cfg, method, conv);
9744                                                 } else {
9745                                                         mono_arch_emit_setret (cfg, method, *sp);
9746                                                 }
9747 #else
9748                                                 mono_arch_emit_setret (cfg, method, *sp);
9749 #endif
9750                                         }
9751                                 }
9752                         }
9753                         if (sp != stack_start)
9754                                 UNVERIFIED;
9755                         MONO_INST_NEW (cfg, ins, OP_BR);
9756                         ip++;
9757                         ins->inst_target_bb = end_bblock;
9758                         MONO_ADD_INS (cfg->cbb, ins);
9759                         link_bblock (cfg, cfg->cbb, end_bblock);
9760                         start_new_bblock = 1;
9761                         break;
9762                 case CEE_BR_S:
9763                         CHECK_OPSIZE (2);
9764                         MONO_INST_NEW (cfg, ins, OP_BR);
9765                         ip++;
9766                         target = ip + 1 + (signed char)(*ip);
9767                         ++ip;
9768                         GET_BBLOCK (cfg, tblock, target);
9769                         link_bblock (cfg, cfg->cbb, tblock);
9770                         ins->inst_target_bb = tblock;
9771                         if (sp != stack_start) {
9772                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9773                                 sp = stack_start;
9774                                 CHECK_UNVERIFIABLE (cfg);
9775                         }
9776                         MONO_ADD_INS (cfg->cbb, ins);
9777                         start_new_bblock = 1;
9778                         inline_costs += BRANCH_COST;
9779                         break;
9780                 case CEE_BEQ_S:
9781                 case CEE_BGE_S:
9782                 case CEE_BGT_S:
9783                 case CEE_BLE_S:
9784                 case CEE_BLT_S:
9785                 case CEE_BNE_UN_S:
9786                 case CEE_BGE_UN_S:
9787                 case CEE_BGT_UN_S:
9788                 case CEE_BLE_UN_S:
9789                 case CEE_BLT_UN_S:
9790                         CHECK_OPSIZE (2);
9791                         CHECK_STACK (2);
9792                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
9793                         ip++;
9794                         target = ip + 1 + *(signed char*)ip;
9795                         ip++;
9796
9797                         ADD_BINCOND (NULL);
9798
9799                         sp = stack_start;
9800                         inline_costs += BRANCH_COST;
9801                         break;
9802                 case CEE_BR:
9803                         CHECK_OPSIZE (5);
9804                         MONO_INST_NEW (cfg, ins, OP_BR);
9805                         ip++;
9806
9807                         target = ip + 4 + (gint32)read32(ip);
9808                         ip += 4;
9809                         GET_BBLOCK (cfg, tblock, target);
9810                         link_bblock (cfg, cfg->cbb, tblock);
9811                         ins->inst_target_bb = tblock;
9812                         if (sp != stack_start) {
9813                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9814                                 sp = stack_start;
9815                                 CHECK_UNVERIFIABLE (cfg);
9816                         }
9817
9818                         MONO_ADD_INS (cfg->cbb, ins);
9819
9820                         start_new_bblock = 1;
9821                         inline_costs += BRANCH_COST;
9822                         break;
9823                 case CEE_BRFALSE_S:
9824                 case CEE_BRTRUE_S:
9825                 case CEE_BRFALSE:
9826                 case CEE_BRTRUE: {
9827                         MonoInst *cmp;
9828                         gboolean is_short = ((*ip) == CEE_BRFALSE_S) || ((*ip) == CEE_BRTRUE_S);
9829                         gboolean is_true = ((*ip) == CEE_BRTRUE_S) || ((*ip) == CEE_BRTRUE);
9830                         guint32 opsize = is_short ? 1 : 4;
9831
9832                         CHECK_OPSIZE (opsize);
9833                         CHECK_STACK (1);
9834                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
9835                                 UNVERIFIED;
9836                         ip ++;
9837                         target = ip + opsize + (is_short ? *(signed char*)ip : (gint32)read32(ip));
9838                         ip += opsize;
9839
9840                         sp--;
9841
9842                         GET_BBLOCK (cfg, tblock, target);
9843                         link_bblock (cfg, cfg->cbb, tblock);
9844                         GET_BBLOCK (cfg, tblock, ip);
9845                         link_bblock (cfg, cfg->cbb, tblock);
9846
9847                         if (sp != stack_start) {
9848                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9849                                 CHECK_UNVERIFIABLE (cfg);
9850                         }
9851
9852                         MONO_INST_NEW(cfg, cmp, OP_ICOMPARE_IMM);
9853                         cmp->sreg1 = sp [0]->dreg;
9854                         type_from_op (cfg, cmp, sp [0], NULL);
9855                         CHECK_TYPE (cmp);
9856
9857 #if SIZEOF_REGISTER == 4
9858                         if (cmp->opcode == OP_LCOMPARE_IMM) {
9859                                 /* Convert it to OP_LCOMPARE */
9860                                 MONO_INST_NEW (cfg, ins, OP_I8CONST);
9861                                 ins->type = STACK_I8;
9862                                 ins->dreg = alloc_dreg (cfg, STACK_I8);
9863                                 ins->inst_l = 0;
9864                                 MONO_ADD_INS (cfg->cbb, ins);
9865                                 cmp->opcode = OP_LCOMPARE;
9866                                 cmp->sreg2 = ins->dreg;
9867                         }
9868 #endif
9869                         MONO_ADD_INS (cfg->cbb, cmp);
9870
9871                         MONO_INST_NEW (cfg, ins, is_true ? CEE_BNE_UN : CEE_BEQ);
9872                         type_from_op (cfg, ins, sp [0], NULL);
9873                         MONO_ADD_INS (cfg->cbb, ins);
9874                         ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);
9875                         GET_BBLOCK (cfg, tblock, target);
9876                         ins->inst_true_bb = tblock;
9877                         GET_BBLOCK (cfg, tblock, ip);
9878                         ins->inst_false_bb = tblock;
9879                         start_new_bblock = 2;
9880
9881                         sp = stack_start;
9882                         inline_costs += BRANCH_COST;
9883                         break;
9884                 }
9885                 case CEE_BEQ:
9886                 case CEE_BGE:
9887                 case CEE_BGT:
9888                 case CEE_BLE:
9889                 case CEE_BLT:
9890                 case CEE_BNE_UN:
9891                 case CEE_BGE_UN:
9892                 case CEE_BGT_UN:
9893                 case CEE_BLE_UN:
9894                 case CEE_BLT_UN:
9895                         CHECK_OPSIZE (5);
9896                         CHECK_STACK (2);
9897                         MONO_INST_NEW (cfg, ins, *ip);
9898                         ip++;
9899                         target = ip + 4 + (gint32)read32(ip);
9900                         ip += 4;
9901
9902                         ADD_BINCOND (NULL);
9903
9904                         sp = stack_start;
9905                         inline_costs += BRANCH_COST;
9906                         break;
9907                 case CEE_SWITCH: {
9908                         MonoInst *src1;
9909                         MonoBasicBlock **targets;
9910                         MonoBasicBlock *default_bblock;
9911                         MonoJumpInfoBBTable *table;
9912                         int offset_reg = alloc_preg (cfg);
9913                         int target_reg = alloc_preg (cfg);
9914                         int table_reg = alloc_preg (cfg);
9915                         int sum_reg = alloc_preg (cfg);
9916                         gboolean use_op_switch;
9917
9918                         CHECK_OPSIZE (5);
9919                         CHECK_STACK (1);
9920                         n = read32 (ip + 1);
9921                         --sp;
9922                         src1 = sp [0];
9923                         if ((src1->type != STACK_I4) && (src1->type != STACK_PTR)) 
9924                                 UNVERIFIED;
9925
9926                         ip += 5;
9927                         CHECK_OPSIZE (n * sizeof (guint32));
9928                         target = ip + n * sizeof (guint32);
9929
9930                         GET_BBLOCK (cfg, default_bblock, target);
9931                         default_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
9932
9933                         targets = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * n);
9934                         for (i = 0; i < n; ++i) {
9935                                 GET_BBLOCK (cfg, tblock, target + (gint32)read32(ip));
9936                                 targets [i] = tblock;
9937                                 targets [i]->flags |= BB_INDIRECT_JUMP_TARGET;
9938                                 ip += 4;
9939                         }
9940
9941                         if (sp != stack_start) {
9942                                 /* 
9943                                  * Link the current bb with the targets as well, so handle_stack_args
9944                                  * will set their in_stack correctly.
9945                                  */
9946                                 link_bblock (cfg, cfg->cbb, default_bblock);
9947                                 for (i = 0; i < n; ++i)
9948                                         link_bblock (cfg, cfg->cbb, targets [i]);
9949
9950                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9951                                 sp = stack_start;
9952                                 CHECK_UNVERIFIABLE (cfg);
9953
9954                                 /* Undo the links */
9955                                 mono_unlink_bblock (cfg, cfg->cbb, default_bblock);
9956                                 for (i = 0; i < n; ++i)
9957                                         mono_unlink_bblock (cfg, cfg->cbb, targets [i]);
9958                         }
9959
9960                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, src1->dreg, n);
9961                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBGE_UN, default_bblock);
9962
9963                         for (i = 0; i < n; ++i)
9964                                 link_bblock (cfg, cfg->cbb, targets [i]);
9965
9966                         table = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
9967                         table->table = targets;
9968                         table->table_size = n;
9969
9970                         use_op_switch = FALSE;
9971 #ifdef TARGET_ARM
9972                         /* ARM implements SWITCH statements differently */
9973                         /* FIXME: Make it use the generic implementation */
9974                         if (!cfg->compile_aot)
9975                                 use_op_switch = TRUE;
9976 #endif
9977
9978                         if (COMPILE_LLVM (cfg))
9979                                 use_op_switch = TRUE;
9980
9981                         cfg->cbb->has_jump_table = 1;
9982
9983                         if (use_op_switch) {
9984                                 MONO_INST_NEW (cfg, ins, OP_SWITCH);
9985                                 ins->sreg1 = src1->dreg;
9986                                 ins->inst_p0 = table;
9987                                 ins->inst_many_bb = targets;
9988                                 ins->klass = GUINT_TO_POINTER (n);
9989                                 MONO_ADD_INS (cfg->cbb, ins);
9990                         } else {
9991                                 if (sizeof (gpointer) == 8)
9992                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 3);
9993                                 else
9994                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 2);
9995
9996 #if SIZEOF_REGISTER == 8
9997                                 /* The upper word might not be zero, and we add it to a 64 bit address later */
9998                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, offset_reg, offset_reg);
9999 #endif
10000
10001                                 if (cfg->compile_aot) {
10002                                         MONO_EMIT_NEW_AOTCONST (cfg, table_reg, table, MONO_PATCH_INFO_SWITCH);
10003                                 } else {
10004                                         MONO_INST_NEW (cfg, ins, OP_JUMP_TABLE);
10005                                         ins->inst_c1 = MONO_PATCH_INFO_SWITCH;
10006                                         ins->inst_p0 = table;
10007                                         ins->dreg = table_reg;
10008                                         MONO_ADD_INS (cfg->cbb, ins);
10009                                 }
10010
10011                                 /* FIXME: Use load_memindex */
10012                                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, table_reg, offset_reg);
10013                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, target_reg, sum_reg, 0);
10014                                 MONO_EMIT_NEW_UNALU (cfg, OP_BR_REG, -1, target_reg);
10015                         }
10016                         start_new_bblock = 1;
10017                         inline_costs += (BRANCH_COST * 2);
10018                         break;
10019                 }
10020                 case CEE_LDIND_I1:
10021                 case CEE_LDIND_U1:
10022                 case CEE_LDIND_I2:
10023                 case CEE_LDIND_U2:
10024                 case CEE_LDIND_I4:
10025                 case CEE_LDIND_U4:
10026                 case CEE_LDIND_I8:
10027                 case CEE_LDIND_I:
10028                 case CEE_LDIND_R4:
10029                 case CEE_LDIND_R8:
10030                 case CEE_LDIND_REF:
10031                         CHECK_STACK (1);
10032                         --sp;
10033
10034                         switch (*ip) {
10035                         case CEE_LDIND_R4:
10036                         case CEE_LDIND_R8:
10037                                 dreg = alloc_freg (cfg);
10038                                 break;
10039                         case CEE_LDIND_I8:
10040                                 dreg = alloc_lreg (cfg);
10041                                 break;
10042                         case CEE_LDIND_REF:
10043                                 dreg = alloc_ireg_ref (cfg);
10044                                 break;
10045                         default:
10046                                 dreg = alloc_preg (cfg);
10047                         }
10048
10049                         NEW_LOAD_MEMBASE (cfg, ins, ldind_to_load_membase (*ip), dreg, sp [0]->dreg, 0);
10050                         ins->type = ldind_type [*ip - CEE_LDIND_I1];
10051                         if (*ip == CEE_LDIND_R4)
10052                                 ins->type = cfg->r4_stack_type;
10053                         ins->flags |= ins_flag;
10054                         MONO_ADD_INS (cfg->cbb, ins);
10055                         *sp++ = ins;
10056                         if (ins_flag & MONO_INST_VOLATILE) {
10057                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10058                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10059                         }
10060                         ins_flag = 0;
10061                         ++ip;
10062                         break;
10063                 case CEE_STIND_REF:
10064                 case CEE_STIND_I1:
10065                 case CEE_STIND_I2:
10066                 case CEE_STIND_I4:
10067                 case CEE_STIND_I8:
10068                 case CEE_STIND_R4:
10069                 case CEE_STIND_R8:
10070                 case CEE_STIND_I:
10071                         CHECK_STACK (2);
10072                         sp -= 2;
10073
10074                         if (ins_flag & MONO_INST_VOLATILE) {
10075                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
10076                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
10077                         }
10078
10079                         NEW_STORE_MEMBASE (cfg, ins, stind_to_store_membase (*ip), sp [0]->dreg, 0, sp [1]->dreg);
10080                         ins->flags |= ins_flag;
10081                         ins_flag = 0;
10082
10083                         MONO_ADD_INS (cfg->cbb, ins);
10084
10085                         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)))
10086                                 emit_write_barrier (cfg, sp [0], sp [1]);
10087
10088                         inline_costs += 1;
10089                         ++ip;
10090                         break;
10091
10092                 case CEE_MUL:
10093                         CHECK_STACK (2);
10094
10095                         MONO_INST_NEW (cfg, ins, (*ip));
10096                         sp -= 2;
10097                         ins->sreg1 = sp [0]->dreg;
10098                         ins->sreg2 = sp [1]->dreg;
10099                         type_from_op (cfg, ins, sp [0], sp [1]);
10100                         CHECK_TYPE (ins);
10101                         ins->dreg = alloc_dreg ((cfg), (ins)->type);
10102
10103                         /* Use the immediate opcodes if possible */
10104                         if ((sp [1]->opcode == OP_ICONST) && mono_arch_is_inst_imm (sp [1]->inst_c0)) {
10105                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
10106                                 if (imm_opcode != -1) {
10107                                         ins->opcode = imm_opcode;
10108                                         ins->inst_p1 = (gpointer)(gssize)(sp [1]->inst_c0);
10109                                         ins->sreg2 = -1;
10110
10111                                         NULLIFY_INS (sp [1]);
10112                                 }
10113                         }
10114
10115                         MONO_ADD_INS ((cfg)->cbb, (ins));
10116
10117                         *sp++ = mono_decompose_opcode (cfg, ins);
10118                         ip++;
10119                         break;
10120                 case CEE_ADD:
10121                 case CEE_SUB:
10122                 case CEE_DIV:
10123                 case CEE_DIV_UN:
10124                 case CEE_REM:
10125                 case CEE_REM_UN:
10126                 case CEE_AND:
10127                 case CEE_OR:
10128                 case CEE_XOR:
10129                 case CEE_SHL:
10130                 case CEE_SHR:
10131                 case CEE_SHR_UN:
10132                         CHECK_STACK (2);
10133
10134                         MONO_INST_NEW (cfg, ins, (*ip));
10135                         sp -= 2;
10136                         ins->sreg1 = sp [0]->dreg;
10137                         ins->sreg2 = sp [1]->dreg;
10138                         type_from_op (cfg, ins, sp [0], sp [1]);
10139                         CHECK_TYPE (ins);
10140                         add_widen_op (cfg, ins, &sp [0], &sp [1]);
10141                         ins->dreg = alloc_dreg ((cfg), (ins)->type);
10142
10143                         /* FIXME: Pass opcode to is_inst_imm */
10144
10145                         /* Use the immediate opcodes if possible */
10146                         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)) {
10147                                 int imm_opcode;
10148
10149                                 imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
10150 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
10151                                 /* Keep emulated opcodes which are optimized away later */
10152                                 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) {
10153                                         imm_opcode = mono_op_to_op_imm (ins->opcode);
10154                                 }
10155 #endif
10156                                 if (imm_opcode != -1) {
10157                                         ins->opcode = imm_opcode;
10158                                         if (sp [1]->opcode == OP_I8CONST) {
10159 #if SIZEOF_REGISTER == 8
10160                                                 ins->inst_imm = sp [1]->inst_l;
10161 #else
10162                                                 ins->inst_ls_word = sp [1]->inst_ls_word;
10163                                                 ins->inst_ms_word = sp [1]->inst_ms_word;
10164 #endif
10165                                         }
10166                                         else
10167                                                 ins->inst_imm = (gssize)(sp [1]->inst_c0);
10168                                         ins->sreg2 = -1;
10169
10170                                         /* Might be followed by an instruction added by add_widen_op */
10171                                         if (sp [1]->next == NULL)
10172                                                 NULLIFY_INS (sp [1]);
10173                                 }
10174                         }
10175                         MONO_ADD_INS ((cfg)->cbb, (ins));
10176
10177                         *sp++ = mono_decompose_opcode (cfg, ins);
10178                         ip++;
10179                         break;
10180                 case CEE_NEG:
10181                 case CEE_NOT:
10182                 case CEE_CONV_I1:
10183                 case CEE_CONV_I2:
10184                 case CEE_CONV_I4:
10185                 case CEE_CONV_R4:
10186                 case CEE_CONV_R8:
10187                 case CEE_CONV_U4:
10188                 case CEE_CONV_I8:
10189                 case CEE_CONV_U8:
10190                 case CEE_CONV_OVF_I8:
10191                 case CEE_CONV_OVF_U8:
10192                 case CEE_CONV_R_UN:
10193                         CHECK_STACK (1);
10194
10195                         /* Special case this earlier so we have long constants in the IR */
10196                         if ((((*ip) == CEE_CONV_I8) || ((*ip) == CEE_CONV_U8)) && (sp [-1]->opcode == OP_ICONST)) {
10197                                 int data = sp [-1]->inst_c0;
10198                                 sp [-1]->opcode = OP_I8CONST;
10199                                 sp [-1]->type = STACK_I8;
10200 #if SIZEOF_REGISTER == 8
10201                                 if ((*ip) == CEE_CONV_U8)
10202                                         sp [-1]->inst_c0 = (guint32)data;
10203                                 else
10204                                         sp [-1]->inst_c0 = data;
10205 #else
10206                                 sp [-1]->inst_ls_word = data;
10207                                 if ((*ip) == CEE_CONV_U8)
10208                                         sp [-1]->inst_ms_word = 0;
10209                                 else
10210                                         sp [-1]->inst_ms_word = (data < 0) ? -1 : 0;
10211 #endif
10212                                 sp [-1]->dreg = alloc_dreg (cfg, STACK_I8);
10213                         }
10214                         else {
10215                                 ADD_UNOP (*ip);
10216                         }
10217                         ip++;
10218                         break;
10219                 case CEE_CONV_OVF_I4:
10220                 case CEE_CONV_OVF_I1:
10221                 case CEE_CONV_OVF_I2:
10222                 case CEE_CONV_OVF_I:
10223                 case CEE_CONV_OVF_U:
10224                         CHECK_STACK (1);
10225
10226                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
10227                                 ADD_UNOP (CEE_CONV_OVF_I8);
10228                                 ADD_UNOP (*ip);
10229                         } else {
10230                                 ADD_UNOP (*ip);
10231                         }
10232                         ip++;
10233                         break;
10234                 case CEE_CONV_OVF_U1:
10235                 case CEE_CONV_OVF_U2:
10236                 case CEE_CONV_OVF_U4:
10237                         CHECK_STACK (1);
10238
10239                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
10240                                 ADD_UNOP (CEE_CONV_OVF_U8);
10241                                 ADD_UNOP (*ip);
10242                         } else {
10243                                 ADD_UNOP (*ip);
10244                         }
10245                         ip++;
10246                         break;
10247                 case CEE_CONV_OVF_I1_UN:
10248                 case CEE_CONV_OVF_I2_UN:
10249                 case CEE_CONV_OVF_I4_UN:
10250                 case CEE_CONV_OVF_I8_UN:
10251                 case CEE_CONV_OVF_U1_UN:
10252                 case CEE_CONV_OVF_U2_UN:
10253                 case CEE_CONV_OVF_U4_UN:
10254                 case CEE_CONV_OVF_U8_UN:
10255                 case CEE_CONV_OVF_I_UN:
10256                 case CEE_CONV_OVF_U_UN:
10257                 case CEE_CONV_U2:
10258                 case CEE_CONV_U1:
10259                 case CEE_CONV_I:
10260                 case CEE_CONV_U:
10261                         CHECK_STACK (1);
10262                         ADD_UNOP (*ip);
10263                         CHECK_CFG_EXCEPTION;
10264                         ip++;
10265                         break;
10266                 case CEE_ADD_OVF:
10267                 case CEE_ADD_OVF_UN:
10268                 case CEE_MUL_OVF:
10269                 case CEE_MUL_OVF_UN:
10270                 case CEE_SUB_OVF:
10271                 case CEE_SUB_OVF_UN:
10272                         CHECK_STACK (2);
10273                         ADD_BINOP (*ip);
10274                         ip++;
10275                         break;
10276                 case CEE_CPOBJ:
10277                         GSHAREDVT_FAILURE (*ip);
10278                         CHECK_OPSIZE (5);
10279                         CHECK_STACK (2);
10280                         token = read32 (ip + 1);
10281                         klass = mini_get_class (method, token, generic_context);
10282                         CHECK_TYPELOAD (klass);
10283                         sp -= 2;
10284                         if (generic_class_is_reference_type (cfg, klass)) {
10285                                 MonoInst *store, *load;
10286                                 int dreg = alloc_ireg_ref (cfg);
10287
10288                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, dreg, sp [1]->dreg, 0);
10289                                 load->flags |= ins_flag;
10290                                 MONO_ADD_INS (cfg->cbb, load);
10291
10292                                 NEW_STORE_MEMBASE (cfg, store, OP_STORE_MEMBASE_REG, sp [0]->dreg, 0, dreg);
10293                                 store->flags |= ins_flag;
10294                                 MONO_ADD_INS (cfg->cbb, store);
10295
10296                                 if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER)
10297                                         emit_write_barrier (cfg, sp [0], sp [1]);
10298                         } else {
10299                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
10300                         }
10301                         ins_flag = 0;
10302                         ip += 5;
10303                         break;
10304                 case CEE_LDOBJ: {
10305                         int loc_index = -1;
10306                         int stloc_len = 0;
10307
10308                         CHECK_OPSIZE (5);
10309                         CHECK_STACK (1);
10310                         --sp;
10311                         token = read32 (ip + 1);
10312                         klass = mini_get_class (method, token, generic_context);
10313                         CHECK_TYPELOAD (klass);
10314
10315                         /* Optimize the common ldobj+stloc combination */
10316                         switch (ip [5]) {
10317                         case CEE_STLOC_S:
10318                                 loc_index = ip [6];
10319                                 stloc_len = 2;
10320                                 break;
10321                         case CEE_STLOC_0:
10322                         case CEE_STLOC_1:
10323                         case CEE_STLOC_2:
10324                         case CEE_STLOC_3:
10325                                 loc_index = ip [5] - CEE_STLOC_0;
10326                                 stloc_len = 1;
10327                                 break;
10328                         default:
10329                                 break;
10330                         }
10331
10332                         if ((loc_index != -1) && ip_in_bb (cfg, cfg->cbb, ip + 5)) {
10333                                 CHECK_LOCAL (loc_index);
10334
10335                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10336                                 ins->dreg = cfg->locals [loc_index]->dreg;
10337                                 ins->flags |= ins_flag;
10338                                 ip += 5;
10339                                 ip += stloc_len;
10340                                 if (ins_flag & MONO_INST_VOLATILE) {
10341                                         /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10342                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10343                                 }
10344                                 ins_flag = 0;
10345                                 break;
10346                         }
10347
10348                         /* Optimize the ldobj+stobj combination */
10349                         /* The reference case ends up being a load+store anyway */
10350                         /* Skip this if the operation is volatile. */
10351                         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)) {
10352                                 CHECK_STACK (1);
10353
10354                                 sp --;
10355
10356                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
10357
10358                                 ip += 5 + 5;
10359                                 ins_flag = 0;
10360                                 break;
10361                         }
10362
10363                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10364                         ins->flags |= ins_flag;
10365                         *sp++ = ins;
10366
10367                         if (ins_flag & MONO_INST_VOLATILE) {
10368                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10369                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10370                         }
10371
10372                         ip += 5;
10373                         ins_flag = 0;
10374                         inline_costs += 1;
10375                         break;
10376                 }
10377                 case CEE_LDSTR:
10378                         CHECK_STACK_OVF (1);
10379                         CHECK_OPSIZE (5);
10380                         n = read32 (ip + 1);
10381
10382                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
10383                                 EMIT_NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
10384                                 ins->type = STACK_OBJ;
10385                                 *sp = ins;
10386                         }
10387                         else if (method->wrapper_type != MONO_WRAPPER_NONE) {
10388                                 MonoInst *iargs [1];
10389                                 char *str = mono_method_get_wrapper_data (method, n);
10390
10391                                 if (cfg->compile_aot)
10392                                         EMIT_NEW_LDSTRLITCONST (cfg, iargs [0], str);
10393                                 else
10394                                         EMIT_NEW_PCONST (cfg, iargs [0], str);
10395                                 *sp = mono_emit_jit_icall (cfg, mono_string_new_wrapper, iargs);
10396                         } else {
10397                                 if (cfg->opt & MONO_OPT_SHARED) {
10398                                         MonoInst *iargs [3];
10399
10400                                         if (cfg->compile_aot) {
10401                                                 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
10402                                         }
10403                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10404                                         EMIT_NEW_IMAGECONST (cfg, iargs [1], image);
10405                                         EMIT_NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
10406                                         *sp = mono_emit_jit_icall (cfg, mono_ldstr, iargs);
10407                                         mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
10408                                 } else {
10409                                         if (cfg->cbb->out_of_line) {
10410                                                 MonoInst *iargs [2];
10411
10412                                                 if (image == mono_defaults.corlib) {
10413                                                         /* 
10414                                                          * Avoid relocations in AOT and save some space by using a 
10415                                                          * version of helper_ldstr specialized to mscorlib.
10416                                                          */
10417                                                         EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (n));
10418                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr_mscorlib, iargs);
10419                                                 } else {
10420                                                         /* Avoid creating the string object */
10421                                                         EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
10422                                                         EMIT_NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n));
10423                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr, iargs);
10424                                                 }
10425                                         } 
10426                                         else
10427                                         if (cfg->compile_aot) {
10428                                                 NEW_LDSTRCONST (cfg, ins, image, n);
10429                                                 *sp = ins;
10430                                                 MONO_ADD_INS (cfg->cbb, ins);
10431                                         } 
10432                                         else {
10433                                                 NEW_PCONST (cfg, ins, NULL);
10434                                                 ins->type = STACK_OBJ;
10435                                                 ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
10436                                                 if (!ins->inst_p0)
10437                                                         OUT_OF_MEMORY_FAILURE;
10438
10439                                                 *sp = ins;
10440                                                 MONO_ADD_INS (cfg->cbb, ins);
10441                                         }
10442                                 }
10443                         }
10444
10445                         sp++;
10446                         ip += 5;
10447                         break;
10448                 case CEE_NEWOBJ: {
10449                         MonoInst *iargs [2];
10450                         MonoMethodSignature *fsig;
10451                         MonoInst this_ins;
10452                         MonoInst *alloc;
10453                         MonoInst *vtable_arg = NULL;
10454
10455                         CHECK_OPSIZE (5);
10456                         token = read32 (ip + 1);
10457                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
10458                         if (!cmethod || mono_loader_get_last_error ())
10459                                 LOAD_ERROR;
10460                         fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
10461                         CHECK_CFG_ERROR;
10462
10463                         mono_save_token_info (cfg, image, token, cmethod);
10464
10465                         if (!mono_class_init (cmethod->klass))
10466                                 TYPE_LOAD_ERROR (cmethod->klass);
10467
10468                         context_used = mini_method_check_context_used (cfg, cmethod);
10469
10470                         if (mono_security_core_clr_enabled ())
10471                                 ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
10472
10473                         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)) {
10474                                 emit_class_init (cfg, cmethod->klass);
10475                                 CHECK_TYPELOAD (cmethod->klass);
10476                         }
10477
10478                         /*
10479                         if (cfg->gsharedvt) {
10480                                 if (mini_is_gsharedvt_variable_signature (sig))
10481                                         GSHAREDVT_FAILURE (*ip);
10482                         }
10483                         */
10484
10485                         n = fsig->param_count;
10486                         CHECK_STACK (n);
10487
10488                         /* 
10489                          * Generate smaller code for the common newobj <exception> instruction in
10490                          * argument checking code.
10491                          */
10492                         if (cfg->cbb->out_of_line && cmethod->klass->image == mono_defaults.corlib &&
10493                                 is_exception_class (cmethod->klass) && n <= 2 &&
10494                                 ((n < 1) || (!fsig->params [0]->byref && fsig->params [0]->type == MONO_TYPE_STRING)) && 
10495                                 ((n < 2) || (!fsig->params [1]->byref && fsig->params [1]->type == MONO_TYPE_STRING))) {
10496                                 MonoInst *iargs [3];
10497
10498                                 sp -= n;
10499
10500                                 EMIT_NEW_ICONST (cfg, iargs [0], cmethod->klass->type_token);
10501                                 switch (n) {
10502                                 case 0:
10503                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_0, iargs);
10504                                         break;
10505                                 case 1:
10506                                         iargs [1] = sp [0];
10507                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_1, iargs);
10508                                         break;
10509                                 case 2:
10510                                         iargs [1] = sp [0];
10511                                         iargs [2] = sp [1];
10512                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_2, iargs);
10513                                         break;
10514                                 default:
10515                                         g_assert_not_reached ();
10516                                 }
10517
10518                                 ip += 5;
10519                                 inline_costs += 5;
10520                                 break;
10521                         }
10522
10523                         /* move the args to allow room for 'this' in the first position */
10524                         while (n--) {
10525                                 --sp;
10526                                 sp [1] = sp [0];
10527                         }
10528
10529                         /* check_call_signature () requires sp[0] to be set */
10530                         this_ins.type = STACK_OBJ;
10531                         sp [0] = &this_ins;
10532                         if (check_call_signature (cfg, fsig, sp))
10533                                 UNVERIFIED;
10534
10535                         iargs [0] = NULL;
10536
10537                         if (mini_class_is_system_array (cmethod->klass)) {
10538                                 *sp = emit_get_rgctx_method (cfg, context_used,
10539                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
10540
10541                                 /* Avoid varargs in the common case */
10542                                 if (fsig->param_count == 1)
10543                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_1, sp);
10544                                 else if (fsig->param_count == 2)
10545                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_2, sp);
10546                                 else if (fsig->param_count == 3)
10547                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_3, sp);
10548                                 else if (fsig->param_count == 4)
10549                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_4, sp);
10550                                 else
10551                                         alloc = handle_array_new (cfg, fsig->param_count, sp, ip);
10552                         } else if (cmethod->string_ctor) {
10553                                 g_assert (!context_used);
10554                                 g_assert (!vtable_arg);
10555                                 /* we simply pass a null pointer */
10556                                 EMIT_NEW_PCONST (cfg, *sp, NULL); 
10557                                 /* now call the string ctor */
10558                                 alloc = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, NULL, NULL, NULL);
10559                         } else {
10560                                 if (cmethod->klass->valuetype) {
10561                                         iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
10562                                         emit_init_rvar (cfg, iargs [0]->dreg, &cmethod->klass->byval_arg);
10563                                         EMIT_NEW_TEMPLOADA (cfg, *sp, iargs [0]->inst_c0);
10564
10565                                         alloc = NULL;
10566
10567                                         /* 
10568                                          * The code generated by mini_emit_virtual_call () expects
10569                                          * iargs [0] to be a boxed instance, but luckily the vcall
10570                                          * will be transformed into a normal call there.
10571                                          */
10572                                 } else if (context_used) {
10573                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, context_used);
10574                                         *sp = alloc;
10575                                 } else {
10576                                         MonoVTable *vtable = NULL;
10577
10578                                         if (!cfg->compile_aot)
10579                                                 vtable = mono_class_vtable (cfg->domain, cmethod->klass);
10580                                         CHECK_TYPELOAD (cmethod->klass);
10581
10582                                         /*
10583                                          * TypeInitializationExceptions thrown from the mono_runtime_class_init
10584                                          * call in mono_jit_runtime_invoke () can abort the finalizer thread.
10585                                          * As a workaround, we call class cctors before allocating objects.
10586                                          */
10587                                         if (mini_field_access_needs_cctor_run (cfg, method, cmethod->klass, vtable) && !(g_slist_find (class_inits, cmethod->klass))) {
10588                                                 emit_class_init (cfg, cmethod->klass);
10589                                                 if (cfg->verbose_level > 2)
10590                                                         printf ("class %s.%s needs init call for ctor\n", cmethod->klass->name_space, cmethod->klass->name);
10591                                                 class_inits = g_slist_prepend (class_inits, cmethod->klass);
10592                                         }
10593
10594                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, 0);
10595                                         *sp = alloc;
10596                                 }
10597                                 CHECK_CFG_EXCEPTION; /*for handle_alloc*/
10598
10599                                 if (alloc)
10600                                         MONO_EMIT_NEW_UNALU (cfg, OP_NOT_NULL, -1, alloc->dreg);
10601
10602                                 /* Now call the actual ctor */
10603                                 handle_ctor_call (cfg, cmethod, fsig, context_used, sp, ip, &inline_costs);
10604                                 CHECK_CFG_EXCEPTION;
10605                         }
10606
10607                         if (alloc == NULL) {
10608                                 /* Valuetype */
10609                                 EMIT_NEW_TEMPLOAD (cfg, ins, iargs [0]->inst_c0);
10610                                 type_to_eval_stack_type (cfg, &ins->klass->byval_arg, ins);
10611                                 *sp++= ins;
10612                         } else {
10613                                 *sp++ = alloc;
10614                         }
10615                         
10616                         ip += 5;
10617                         inline_costs += 5;
10618                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip - header->code)))
10619                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
10620                         break;
10621                 }
10622                 case CEE_CASTCLASS:
10623                         CHECK_STACK (1);
10624                         --sp;
10625                         CHECK_OPSIZE (5);
10626                         token = read32 (ip + 1);
10627                         klass = mini_get_class (method, token, generic_context);
10628                         CHECK_TYPELOAD (klass);
10629                         if (sp [0]->type != STACK_OBJ)
10630                                 UNVERIFIED;
10631
10632                         ins = handle_castclass (cfg, klass, *sp, ip, &inline_costs);
10633                         CHECK_CFG_EXCEPTION;
10634
10635                         *sp ++ = ins;
10636                         ip += 5;
10637                         break;
10638                 case CEE_ISINST: {
10639                         CHECK_STACK (1);
10640                         --sp;
10641                         CHECK_OPSIZE (5);
10642                         token = read32 (ip + 1);
10643                         klass = mini_get_class (method, token, generic_context);
10644                         CHECK_TYPELOAD (klass);
10645                         if (sp [0]->type != STACK_OBJ)
10646                                 UNVERIFIED;
10647  
10648                         context_used = mini_class_check_context_used (cfg, klass);
10649
10650                         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
10651                                 MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
10652                                 MonoInst *args [3];
10653                                 int idx;
10654
10655                                 /* obj */
10656                                 args [0] = *sp;
10657
10658                                 /* klass */
10659                                 EMIT_NEW_CLASSCONST (cfg, args [1], klass);
10660
10661                                 /* inline cache*/
10662                                 if (cfg->compile_aot) {
10663                                         idx = get_castclass_cache_idx (cfg);
10664                                         EMIT_NEW_AOTCONST (cfg, args [2], MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
10665                                 } else {
10666                                         EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));
10667                                 }
10668
10669                                 *sp++ = mono_emit_method_call (cfg, mono_isinst, args, NULL);
10670                                 ip += 5;
10671                                 inline_costs += 2;
10672                         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
10673                                 MonoMethod *mono_isinst;
10674                                 MonoInst *iargs [1];
10675                                 int costs;
10676
10677                                 mono_isinst = mono_marshal_get_isinst (klass); 
10678                                 iargs [0] = sp [0];
10679
10680                                 costs = inline_method (cfg, mono_isinst, mono_method_signature (mono_isinst), 
10681                                                                            iargs, ip, cfg->real_offset, TRUE);
10682                                 CHECK_CFG_EXCEPTION;
10683                                 g_assert (costs > 0);
10684                                 
10685                                 ip += 5;
10686                                 cfg->real_offset += 5;
10687
10688                                 *sp++= iargs [0];
10689
10690                                 inline_costs += costs;
10691                         }
10692                         else {
10693                                 ins = handle_isinst (cfg, klass, *sp, context_used);
10694                                 CHECK_CFG_EXCEPTION;
10695                                 *sp ++ = ins;
10696                                 ip += 5;
10697                         }
10698                         break;
10699                 }
10700                 case CEE_UNBOX_ANY: {
10701                         MonoInst *res, *addr;
10702
10703                         CHECK_STACK (1);
10704                         --sp;
10705                         CHECK_OPSIZE (5);
10706                         token = read32 (ip + 1);
10707                         klass = mini_get_class (method, token, generic_context);
10708                         CHECK_TYPELOAD (klass);
10709
10710                         mono_save_token_info (cfg, image, token, klass);
10711
10712                         context_used = mini_class_check_context_used (cfg, klass);
10713
10714                         if (mini_is_gsharedvt_klass (klass)) {
10715                                 res = handle_unbox_gsharedvt (cfg, klass, *sp);
10716                                 inline_costs += 2;
10717                         } else if (generic_class_is_reference_type (cfg, klass)) {
10718                                 res = handle_castclass (cfg, klass, *sp, ip, &inline_costs);
10719                                 CHECK_CFG_EXCEPTION;
10720                         } else if (mono_class_is_nullable (klass)) {
10721                                 res = handle_unbox_nullable (cfg, *sp, klass, context_used);
10722                         } else {
10723                                 addr = handle_unbox (cfg, klass, sp, context_used);
10724                                 /* LDOBJ */
10725                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
10726                                 res = ins;
10727                                 inline_costs += 2;
10728                         }
10729
10730                         *sp ++ = res;
10731                         ip += 5;
10732                         break;
10733                 }
10734                 case CEE_BOX: {
10735                         MonoInst *val;
10736                         MonoClass *enum_class;
10737                         MonoMethod *has_flag;
10738
10739                         CHECK_STACK (1);
10740                         --sp;
10741                         val = *sp;
10742                         CHECK_OPSIZE (5);
10743                         token = read32 (ip + 1);
10744                         klass = mini_get_class (method, token, generic_context);
10745                         CHECK_TYPELOAD (klass);
10746
10747                         mono_save_token_info (cfg, image, token, klass);
10748
10749                         context_used = mini_class_check_context_used (cfg, klass);
10750
10751                         if (generic_class_is_reference_type (cfg, klass)) {
10752                                 *sp++ = val;
10753                                 ip += 5;
10754                                 break;
10755                         }
10756
10757                         if (klass == mono_defaults.void_class)
10758                                 UNVERIFIED;
10759                         if (target_type_is_incompatible (cfg, &klass->byval_arg, *sp))
10760                                 UNVERIFIED;
10761                         /* frequent check in generic code: box (struct), brtrue */
10762
10763                         /*
10764                          * Look for:
10765                          *
10766                          *   <push int/long ptr>
10767                          *   <push int/long>
10768                          *   box MyFlags
10769                          *   constrained. MyFlags
10770                          *   callvirt instace bool class [mscorlib] System.Enum::HasFlag (class [mscorlib] System.Enum)
10771                          *
10772                          * If we find this sequence and the operand types on box and constrained
10773                          * are equal, we can emit a specialized instruction sequence instead of
10774                          * the very slow HasFlag () call.
10775                          */
10776                         if ((cfg->opt & MONO_OPT_INTRINS) &&
10777                             /* Cheap checks first. */
10778                             ip + 5 + 6 + 5 < end &&
10779                             ip [5] == CEE_PREFIX1 &&
10780                             ip [6] == CEE_CONSTRAINED_ &&
10781                             ip [11] == CEE_CALLVIRT &&
10782                             ip_in_bb (cfg, cfg->cbb, ip + 5 + 6 + 5) &&
10783                             mono_class_is_enum (klass) &&
10784                             (enum_class = mini_get_class (method, read32 (ip + 7), generic_context)) &&
10785                             (has_flag = mini_get_method (cfg, method, read32 (ip + 12), NULL, generic_context)) &&
10786                             has_flag->klass == mono_defaults.enum_class &&
10787                             !strcmp (has_flag->name, "HasFlag") &&
10788                             has_flag->signature->hasthis &&
10789                             has_flag->signature->param_count == 1) {
10790                                 CHECK_TYPELOAD (enum_class);
10791
10792                                 if (enum_class == klass) {
10793                                         MonoInst *enum_this, *enum_flag;
10794
10795                                         ip += 5 + 6 + 5;
10796                                         --sp;
10797
10798                                         enum_this = sp [0];
10799                                         enum_flag = sp [1];
10800
10801                                         *sp++ = handle_enum_has_flag (cfg, klass, enum_this, enum_flag);
10802                                         break;
10803                                 }
10804                         }
10805
10806                         // FIXME: LLVM can't handle the inconsistent bb linking
10807                         if (!mono_class_is_nullable (klass) &&
10808                                 !mini_is_gsharedvt_klass (klass) &&
10809                                 ip + 5 < end && ip_in_bb (cfg, cfg->cbb, ip + 5) &&
10810                                 (ip [5] == CEE_BRTRUE || 
10811                                  ip [5] == CEE_BRTRUE_S ||
10812                                  ip [5] == CEE_BRFALSE ||
10813                                  ip [5] == CEE_BRFALSE_S)) {
10814                                 gboolean is_true = ip [5] == CEE_BRTRUE || ip [5] == CEE_BRTRUE_S;
10815                                 int dreg;
10816                                 MonoBasicBlock *true_bb, *false_bb;
10817
10818                                 ip += 5;
10819
10820                                 if (cfg->verbose_level > 3) {
10821                                         printf ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
10822                                         printf ("<box+brtrue opt>\n");
10823                                 }
10824
10825                                 switch (*ip) {
10826                                 case CEE_BRTRUE_S:
10827                                 case CEE_BRFALSE_S:
10828                                         CHECK_OPSIZE (2);
10829                                         ip++;
10830                                         target = ip + 1 + (signed char)(*ip);
10831                                         ip++;
10832                                         break;
10833                                 case CEE_BRTRUE:
10834                                 case CEE_BRFALSE:
10835                                         CHECK_OPSIZE (5);
10836                                         ip++;
10837                                         target = ip + 4 + (gint)(read32 (ip));
10838                                         ip += 4;
10839                                         break;
10840                                 default:
10841                                         g_assert_not_reached ();
10842                                 }
10843
10844                                 /* 
10845                                  * We need to link both bblocks, since it is needed for handling stack
10846                                  * arguments correctly (See test_0_box_brtrue_opt_regress_81102).
10847                                  * Branching to only one of them would lead to inconsistencies, so
10848                                  * generate an ICONST+BRTRUE, the branch opts will get rid of them.
10849                                  */
10850                                 GET_BBLOCK (cfg, true_bb, target);
10851                                 GET_BBLOCK (cfg, false_bb, ip);
10852
10853                                 mono_link_bblock (cfg, cfg->cbb, true_bb);
10854                                 mono_link_bblock (cfg, cfg->cbb, false_bb);
10855
10856                                 if (sp != stack_start) {
10857                                         handle_stack_args (cfg, stack_start, sp - stack_start);
10858                                         sp = stack_start;
10859                                         CHECK_UNVERIFIABLE (cfg);
10860                                 }
10861
10862                                 if (COMPILE_LLVM (cfg)) {
10863                                         dreg = alloc_ireg (cfg);
10864                                         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
10865                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, dreg, is_true ? 0 : 1);
10866
10867                                         MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, OP_IBEQ, true_bb, false_bb);
10868                                 } else {
10869                                         /* The JIT can't eliminate the iconst+compare */
10870                                         MONO_INST_NEW (cfg, ins, OP_BR);
10871                                         ins->inst_target_bb = is_true ? true_bb : false_bb;
10872                                         MONO_ADD_INS (cfg->cbb, ins);
10873                                 }
10874
10875                                 start_new_bblock = 1;
10876                                 break;
10877                         }
10878
10879                         *sp++ = handle_box (cfg, val, klass, context_used);
10880
10881                         CHECK_CFG_EXCEPTION;
10882                         ip += 5;
10883                         inline_costs += 1;
10884                         break;
10885                 }
10886                 case CEE_UNBOX: {
10887                         CHECK_STACK (1);
10888                         --sp;
10889                         CHECK_OPSIZE (5);
10890                         token = read32 (ip + 1);
10891                         klass = mini_get_class (method, token, generic_context);
10892                         CHECK_TYPELOAD (klass);
10893
10894                         mono_save_token_info (cfg, image, token, klass);
10895
10896                         context_used = mini_class_check_context_used (cfg, klass);
10897
10898                         if (mono_class_is_nullable (klass)) {
10899                                 MonoInst *val;
10900
10901                                 val = handle_unbox_nullable (cfg, *sp, klass, context_used);
10902                                 EMIT_NEW_VARLOADA (cfg, ins, get_vreg_to_inst (cfg, val->dreg), &val->klass->byval_arg);
10903
10904                                 *sp++= ins;
10905                         } else {
10906                                 ins = handle_unbox (cfg, klass, sp, context_used);
10907                                 *sp++ = ins;
10908                         }
10909                         ip += 5;
10910                         inline_costs += 2;
10911                         break;
10912                 }
10913                 case CEE_LDFLD:
10914                 case CEE_LDFLDA:
10915                 case CEE_STFLD:
10916                 case CEE_LDSFLD:
10917                 case CEE_LDSFLDA:
10918                 case CEE_STSFLD: {
10919                         MonoClassField *field;
10920 #ifndef DISABLE_REMOTING
10921                         int costs;
10922 #endif
10923                         guint foffset;
10924                         gboolean is_instance;
10925                         int op;
10926                         gpointer addr = NULL;
10927                         gboolean is_special_static;
10928                         MonoType *ftype;
10929                         MonoInst *store_val = NULL;
10930                         MonoInst *thread_ins;
10931
10932                         op = *ip;
10933                         is_instance = (op == CEE_LDFLD || op == CEE_LDFLDA || op == CEE_STFLD);
10934                         if (is_instance) {
10935                                 if (op == CEE_STFLD) {
10936                                         CHECK_STACK (2);
10937                                         sp -= 2;
10938                                         store_val = sp [1];
10939                                 } else {
10940                                         CHECK_STACK (1);
10941                                         --sp;
10942                                 }
10943                                 if (sp [0]->type == STACK_I4 || sp [0]->type == STACK_I8 || sp [0]->type == STACK_R8)
10944                                         UNVERIFIED;
10945                                 if (*ip != CEE_LDFLD && sp [0]->type == STACK_VTYPE)
10946                                         UNVERIFIED;
10947                         } else {
10948                                 if (op == CEE_STSFLD) {
10949                                         CHECK_STACK (1);
10950                                         sp--;
10951                                         store_val = sp [0];
10952                                 }
10953                         }
10954
10955                         CHECK_OPSIZE (5);
10956                         token = read32 (ip + 1);
10957                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
10958                                 field = mono_method_get_wrapper_data (method, token);
10959                                 klass = field->parent;
10960                         }
10961                         else {
10962                                 field = mono_field_from_token_checked (image, token, &klass, generic_context, &cfg->error);
10963                                 CHECK_CFG_ERROR;
10964                         }
10965                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
10966                                 FIELD_ACCESS_FAILURE (method, field);
10967                         mono_class_init (klass);
10968
10969                         /* if the class is Critical then transparent code cannot access it's fields */
10970                         if (!is_instance && mono_security_core_clr_enabled ())
10971                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
10972
10973                         /* XXX this is technically required but, so far (SL2), no [SecurityCritical] types (not many exists) have
10974                            any visible *instance* field  (in fact there's a single case for a static field in Marshal) XXX
10975                         if (mono_security_core_clr_enabled ())
10976                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
10977                         */
10978
10979                         ftype = mono_field_get_type (field);
10980
10981                         /*
10982                          * LDFLD etc. is usable on static fields as well, so convert those cases to
10983                          * the static case.
10984                          */
10985                         if (is_instance && ftype->attrs & FIELD_ATTRIBUTE_STATIC) {
10986                                 switch (op) {
10987                                 case CEE_LDFLD:
10988                                         op = CEE_LDSFLD;
10989                                         break;
10990                                 case CEE_STFLD:
10991                                         op = CEE_STSFLD;
10992                                         break;
10993                                 case CEE_LDFLDA:
10994                                         op = CEE_LDSFLDA;
10995                                         break;
10996                                 default:
10997                                         g_assert_not_reached ();
10998                                 }
10999                                 is_instance = FALSE;
11000                         }
11001
11002                         context_used = mini_class_check_context_used (cfg, klass);
11003
11004                         /* INSTANCE CASE */
11005
11006                         foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
11007                         if (op == CEE_STFLD) {
11008                                 if (target_type_is_incompatible (cfg, field->type, sp [1]))
11009                                         UNVERIFIED;
11010 #ifndef DISABLE_REMOTING
11011                                 if ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class) {
11012                                         MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type); 
11013                                         MonoInst *iargs [5];
11014
11015                                         GSHAREDVT_FAILURE (op);
11016
11017                                         iargs [0] = sp [0];
11018                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11019                                         EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
11020                                         EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : 
11021                                                     field->offset);
11022                                         iargs [4] = sp [1];
11023
11024                                         if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
11025                                                 costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), 
11026                                                                                            iargs, ip, cfg->real_offset, TRUE);
11027                                                 CHECK_CFG_EXCEPTION;
11028                                                 g_assert (costs > 0);
11029                                                       
11030                                                 cfg->real_offset += 5;
11031
11032                                                 inline_costs += costs;
11033                                         } else {
11034                                                 mono_emit_method_call (cfg, stfld_wrapper, iargs, NULL);
11035                                         }
11036                                 } else
11037 #endif
11038                                 {
11039                                         MonoInst *store;
11040
11041                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
11042
11043                                         if (mini_is_gsharedvt_klass (klass)) {
11044                                                 MonoInst *offset_ins;
11045
11046                                                 context_used = mini_class_check_context_used (cfg, klass);
11047
11048                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11049                                                 dreg = alloc_ireg_mp (cfg);
11050                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11051                                                 /* The decomposition will call mini_emit_stobj () which will emit a wbarrier if needed */
11052                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, dreg, 0, sp [1]->dreg);
11053                                         } else {
11054                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, sp [0]->dreg, foffset, sp [1]->dreg);
11055                                         }
11056                                         if (sp [0]->opcode != OP_LDADDR)
11057                                                 store->flags |= MONO_INST_FAULT;
11058
11059                                 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)) {
11060                                         /* insert call to write barrier */
11061                                         MonoInst *ptr;
11062                                         int dreg;
11063
11064                                         dreg = alloc_ireg_mp (cfg);
11065                                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
11066                                         emit_write_barrier (cfg, ptr, sp [1]);
11067                                 }
11068
11069                                         store->flags |= ins_flag;
11070                                 }
11071                                 ins_flag = 0;
11072                                 ip += 5;
11073                                 break;
11074                         }
11075
11076 #ifndef DISABLE_REMOTING
11077                         if (is_instance && ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class)) {
11078                                 MonoMethod *wrapper = (op == CEE_LDFLDA) ? mono_marshal_get_ldflda_wrapper (field->type) : mono_marshal_get_ldfld_wrapper (field->type); 
11079                                 MonoInst *iargs [4];
11080
11081                                 GSHAREDVT_FAILURE (op);
11082
11083                                 iargs [0] = sp [0];
11084                                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11085                                 EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
11086                                 EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
11087                                 if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
11088                                         costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), 
11089                                                                                    iargs, ip, cfg->real_offset, TRUE);
11090                                         CHECK_CFG_EXCEPTION;
11091                                         g_assert (costs > 0);
11092                                                       
11093                                         cfg->real_offset += 5;
11094
11095                                         *sp++ = iargs [0];
11096
11097                                         inline_costs += costs;
11098                                 } else {
11099                                         ins = mono_emit_method_call (cfg, wrapper, iargs, NULL);
11100                                         *sp++ = ins;
11101                                 }
11102                         } else 
11103 #endif
11104                         if (is_instance) {
11105                                 if (sp [0]->type == STACK_VTYPE) {
11106                                         MonoInst *var;
11107
11108                                         /* Have to compute the address of the variable */
11109
11110                                         var = get_vreg_to_inst (cfg, sp [0]->dreg);
11111                                         if (!var)
11112                                                 var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, sp [0]->dreg);
11113                                         else
11114                                                 g_assert (var->klass == klass);
11115                                         
11116                                         EMIT_NEW_VARLOADA (cfg, ins, var, &var->klass->byval_arg);
11117                                         sp [0] = ins;
11118                                 }
11119
11120                                 if (op == CEE_LDFLDA) {
11121                                         if (sp [0]->type == STACK_OBJ) {
11122                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
11123                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "NullReferenceException");
11124                                         }
11125
11126                                         dreg = alloc_ireg_mp (cfg);
11127
11128                                         if (mini_is_gsharedvt_klass (klass)) {
11129                                                 MonoInst *offset_ins;
11130
11131                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11132                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11133                                         } else {
11134                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
11135                                         }
11136                                         ins->klass = mono_class_from_mono_type (field->type);
11137                                         ins->type = STACK_MP;
11138                                         *sp++ = ins;
11139                                 } else {
11140                                         MonoInst *load;
11141
11142                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
11143
11144                                         if (mini_is_gsharedvt_klass (klass)) {
11145                                                 MonoInst *offset_ins;
11146
11147                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11148                                                 dreg = alloc_ireg_mp (cfg);
11149                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11150                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, dreg, 0);
11151                                         } else {
11152                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, sp [0]->dreg, foffset);
11153                                         }
11154                                         load->flags |= ins_flag;
11155                                         if (sp [0]->opcode != OP_LDADDR)
11156                                                 load->flags |= MONO_INST_FAULT;
11157                                         *sp++ = load;
11158                                 }
11159                         }
11160
11161                         if (is_instance) {
11162                                 ins_flag = 0;
11163                                 ip += 5;
11164                                 break;
11165                         }
11166
11167                         /* STATIC CASE */
11168                         context_used = mini_class_check_context_used (cfg, klass);
11169
11170                         if (ftype->attrs & FIELD_ATTRIBUTE_LITERAL)
11171                                 UNVERIFIED;
11172
11173                         /* The special_static_fields field is init'd in mono_class_vtable, so it needs
11174                          * to be called here.
11175                          */
11176                         if (!context_used && !(cfg->opt & MONO_OPT_SHARED)) {
11177                                 mono_class_vtable (cfg->domain, klass);
11178                                 CHECK_TYPELOAD (klass);
11179                         }
11180                         mono_domain_lock (cfg->domain);
11181                         if (cfg->domain->special_static_fields)
11182                                 addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
11183                         mono_domain_unlock (cfg->domain);
11184
11185                         is_special_static = mono_class_field_is_special_static (field);
11186
11187                         if (is_special_static && ((gsize)addr & 0x80000000) == 0)
11188                                 thread_ins = mono_get_thread_intrinsic (cfg);
11189                         else
11190                                 thread_ins = NULL;
11191
11192                         /* Generate IR to compute the field address */
11193                         if (is_special_static && ((gsize)addr & 0x80000000) == 0 && thread_ins && !(cfg->opt & MONO_OPT_SHARED) && !context_used) {
11194                                 /*
11195                                  * Fast access to TLS data
11196                                  * Inline version of get_thread_static_data () in
11197                                  * threads.c.
11198                                  */
11199                                 guint32 offset;
11200                                 int idx, static_data_reg, array_reg, dreg;
11201
11202                                 GSHAREDVT_FAILURE (op);
11203
11204                                 MONO_ADD_INS (cfg->cbb, thread_ins);
11205                                 static_data_reg = alloc_ireg (cfg);
11206                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, MONO_STRUCT_OFFSET (MonoInternalThread, static_data));
11207
11208                                 if (cfg->compile_aot) {
11209                                         int offset_reg, offset2_reg, idx_reg;
11210
11211                                         /* For TLS variables, this will return the TLS offset */
11212                                         EMIT_NEW_SFLDACONST (cfg, ins, field);
11213                                         offset_reg = ins->dreg;
11214                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset_reg, offset_reg, 0x7fffffff);
11215                                         idx_reg = alloc_ireg (cfg);
11216                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, idx_reg, offset_reg, 0x3f);
11217                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
11218                                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
11219                                         array_reg = alloc_ireg (cfg);
11220                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
11221                                         offset2_reg = alloc_ireg (cfg);
11222                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, offset2_reg, offset_reg, 6);
11223                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset2_reg, 0x1ffffff);
11224                                         dreg = alloc_ireg (cfg);
11225                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, array_reg, offset2_reg);
11226                                 } else {
11227                                         offset = (gsize)addr & 0x7fffffff;
11228                                         idx = offset & 0x3f;
11229
11230                                         array_reg = alloc_ireg (cfg);
11231                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, idx * sizeof (gpointer));
11232                                         dreg = alloc_ireg (cfg);
11233                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_ADD_IMM, dreg, array_reg, ((offset >> 6) & 0x1ffffff));
11234                                 }
11235                         } else if ((cfg->opt & MONO_OPT_SHARED) ||
11236                                         (cfg->compile_aot && is_special_static) ||
11237                                         (context_used && is_special_static)) {
11238                                 MonoInst *iargs [2];
11239
11240                                 g_assert (field->parent);
11241                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11242                                 if (context_used) {
11243                                         iargs [1] = emit_get_rgctx_field (cfg, context_used,
11244                                                 field, MONO_RGCTX_INFO_CLASS_FIELD);
11245                                 } else {
11246                                         EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
11247                                 }
11248                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
11249                         } else if (context_used) {
11250                                 MonoInst *static_data;
11251
11252                                 /*
11253                                 g_print ("sharing static field access in %s.%s.%s - depth %d offset %d\n",
11254                                         method->klass->name_space, method->klass->name, method->name,
11255                                         depth, field->offset);
11256                                 */
11257
11258                                 if (mono_class_needs_cctor_run (klass, method))
11259                                         emit_class_init (cfg, klass);
11260
11261                                 /*
11262                                  * The pointer we're computing here is
11263                                  *
11264                                  *   super_info.static_data + field->offset
11265                                  */
11266                                 static_data = emit_get_rgctx_klass (cfg, context_used,
11267                                         klass, MONO_RGCTX_INFO_STATIC_DATA);
11268
11269                                 if (mini_is_gsharedvt_klass (klass)) {
11270                                         MonoInst *offset_ins;
11271
11272                                         offset_ins = emit_get_rgctx_field (cfg, context_used, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11273                                         dreg = alloc_ireg_mp (cfg);
11274                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, static_data->dreg, offset_ins->dreg);
11275                                 } else if (field->offset == 0) {
11276                                         ins = static_data;
11277                                 } else {
11278                                         int addr_reg = mono_alloc_preg (cfg);
11279                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, addr_reg, static_data->dreg, field->offset);
11280                                 }
11281                                 } else if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
11282                                 MonoInst *iargs [2];
11283
11284                                 g_assert (field->parent);
11285                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11286                                 EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
11287                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
11288                         } else {
11289                                 MonoVTable *vtable = NULL;
11290
11291                                 if (!cfg->compile_aot)
11292                                         vtable = mono_class_vtable (cfg->domain, klass);
11293                                 CHECK_TYPELOAD (klass);
11294
11295                                 if (!addr) {
11296                                         if (mini_field_access_needs_cctor_run (cfg, method, klass, vtable)) {
11297                                                 if (!(g_slist_find (class_inits, klass))) {
11298                                                         emit_class_init (cfg, klass);
11299                                                         if (cfg->verbose_level > 2)
11300                                                                 printf ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, mono_field_get_name (field));
11301                                                         class_inits = g_slist_prepend (class_inits, klass);
11302                                                 }
11303                                         } else {
11304                                                 if (cfg->run_cctors) {
11305                                                         MonoException *ex;
11306                                                         /* This makes so that inline cannot trigger */
11307                                                         /* .cctors: too many apps depend on them */
11308                                                         /* running with a specific order... */
11309                                                         g_assert (vtable);
11310                                                         if (! vtable->initialized)
11311                                                                 INLINE_FAILURE ("class init");
11312                                                         ex = mono_runtime_class_init_full (vtable, FALSE);
11313                                                         if (ex) {
11314                                                                 set_exception_object (cfg, ex);
11315                                                                 goto exception_exit;
11316                                                         }
11317                                                 }
11318                                         }
11319                                         if (cfg->compile_aot)
11320                                                 EMIT_NEW_SFLDACONST (cfg, ins, field);
11321                                         else {
11322                                                 g_assert (vtable);
11323                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11324                                                 g_assert (addr);
11325                                                 EMIT_NEW_PCONST (cfg, ins, addr);
11326                                         }
11327                                 } else {
11328                                         MonoInst *iargs [1];
11329                                         EMIT_NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
11330                                         ins = mono_emit_jit_icall (cfg, mono_get_special_static_data, iargs);
11331                                 }
11332                         }
11333
11334                         /* Generate IR to do the actual load/store operation */
11335
11336                         if ((op == CEE_STFLD || op == CEE_STSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11337                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11338                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11339                         }
11340
11341                         if (op == CEE_LDSFLDA) {
11342                                 ins->klass = mono_class_from_mono_type (ftype);
11343                                 ins->type = STACK_PTR;
11344                                 *sp++ = ins;
11345                         } else if (op == CEE_STSFLD) {
11346                                 MonoInst *store;
11347
11348                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, ftype, ins->dreg, 0, store_val->dreg);
11349                                 store->flags |= ins_flag;
11350                         } else {
11351                                 gboolean is_const = FALSE;
11352                                 MonoVTable *vtable = NULL;
11353                                 gpointer addr = NULL;
11354
11355                                 if (!context_used) {
11356                                         vtable = mono_class_vtable (cfg->domain, klass);
11357                                         CHECK_TYPELOAD (klass);
11358                                 }
11359                                 if ((ftype->attrs & FIELD_ATTRIBUTE_INIT_ONLY) && (((addr = mono_aot_readonly_field_override (field)) != NULL) ||
11360                                                 (!context_used && !((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && vtable->initialized))) {
11361                                         int ro_type = ftype->type;
11362                                         if (!addr)
11363                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11364                                         if (ro_type == MONO_TYPE_VALUETYPE && ftype->data.klass->enumtype) {
11365                                                 ro_type = mono_class_enum_basetype (ftype->data.klass)->type;
11366                                         }
11367
11368                                         GSHAREDVT_FAILURE (op);
11369
11370                                         /* printf ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, mono_field_get_name (field));*/
11371                                         is_const = TRUE;
11372                                         switch (ro_type) {
11373                                         case MONO_TYPE_BOOLEAN:
11374                                         case MONO_TYPE_U1:
11375                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint8 *)addr));
11376                                                 sp++;
11377                                                 break;
11378                                         case MONO_TYPE_I1:
11379                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint8 *)addr));
11380                                                 sp++;
11381                                                 break;                                          
11382                                         case MONO_TYPE_CHAR:
11383                                         case MONO_TYPE_U2:
11384                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint16 *)addr));
11385                                                 sp++;
11386                                                 break;
11387                                         case MONO_TYPE_I2:
11388                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint16 *)addr));
11389                                                 sp++;
11390                                                 break;
11391                                                 break;
11392                                         case MONO_TYPE_I4:
11393                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint32 *)addr));
11394                                                 sp++;
11395                                                 break;                                          
11396                                         case MONO_TYPE_U4:
11397                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint32 *)addr));
11398                                                 sp++;
11399                                                 break;
11400                                         case MONO_TYPE_I:
11401                                         case MONO_TYPE_U:
11402                                         case MONO_TYPE_PTR:
11403                                         case MONO_TYPE_FNPTR:
11404                                                 EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11405                                                 type_to_eval_stack_type ((cfg), field->type, *sp);
11406                                                 sp++;
11407                                                 break;
11408                                         case MONO_TYPE_STRING:
11409                                         case MONO_TYPE_OBJECT:
11410                                         case MONO_TYPE_CLASS:
11411                                         case MONO_TYPE_SZARRAY:
11412                                         case MONO_TYPE_ARRAY:
11413                                                 if (!mono_gc_is_moving ()) {
11414                                                         EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11415                                                         type_to_eval_stack_type ((cfg), field->type, *sp);
11416                                                         sp++;
11417                                                 } else {
11418                                                         is_const = FALSE;
11419                                                 }
11420                                                 break;
11421                                         case MONO_TYPE_I8:
11422                                         case MONO_TYPE_U8:
11423                                                 EMIT_NEW_I8CONST (cfg, *sp, *((gint64 *)addr));
11424                                                 sp++;
11425                                                 break;
11426                                         case MONO_TYPE_R4:
11427                                         case MONO_TYPE_R8:
11428                                         case MONO_TYPE_VALUETYPE:
11429                                         default:
11430                                                 is_const = FALSE;
11431                                                 break;
11432                                         }
11433                                 }
11434
11435                                 if (!is_const) {
11436                                         MonoInst *load;
11437
11438                                         CHECK_STACK_OVF (1);
11439
11440                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, ins->dreg, 0);
11441                                         load->flags |= ins_flag;
11442                                         ins_flag = 0;
11443                                         *sp++ = load;
11444                                 }
11445                         }
11446
11447                         if ((op == CEE_LDFLD || op == CEE_LDSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11448                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
11449                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
11450                         }
11451
11452                         ins_flag = 0;
11453                         ip += 5;
11454                         break;
11455                 }
11456                 case CEE_STOBJ:
11457                         CHECK_STACK (2);
11458                         sp -= 2;
11459                         CHECK_OPSIZE (5);
11460                         token = read32 (ip + 1);
11461                         klass = mini_get_class (method, token, generic_context);
11462                         CHECK_TYPELOAD (klass);
11463                         if (ins_flag & MONO_INST_VOLATILE) {
11464                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11465                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11466                         }
11467                         /* FIXME: should check item at sp [1] is compatible with the type of the store. */
11468                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0, sp [1]->dreg);
11469                         ins->flags |= ins_flag;
11470                         if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER &&
11471                                         generic_class_is_reference_type (cfg, klass)) {
11472                                 /* insert call to write barrier */
11473                                 emit_write_barrier (cfg, sp [0], sp [1]);
11474                         }
11475                         ins_flag = 0;
11476                         ip += 5;
11477                         inline_costs += 1;
11478                         break;
11479
11480                         /*
11481                          * Array opcodes
11482                          */
11483                 case CEE_NEWARR: {
11484                         MonoInst *len_ins;
11485                         const char *data_ptr;
11486                         int data_size = 0;
11487                         guint32 field_token;
11488
11489                         CHECK_STACK (1);
11490                         --sp;
11491
11492                         CHECK_OPSIZE (5);
11493                         token = read32 (ip + 1);
11494
11495                         klass = mini_get_class (method, token, generic_context);
11496                         CHECK_TYPELOAD (klass);
11497
11498                         context_used = mini_class_check_context_used (cfg, klass);
11499
11500                         if (sp [0]->type == STACK_I8 || (SIZEOF_VOID_P == 8 && sp [0]->type == STACK_PTR)) {
11501                                 MONO_INST_NEW (cfg, ins, OP_LCONV_TO_OVF_U4);
11502                                 ins->sreg1 = sp [0]->dreg;
11503                                 ins->type = STACK_I4;
11504                                 ins->dreg = alloc_ireg (cfg);
11505                                 MONO_ADD_INS (cfg->cbb, ins);
11506                                 *sp = mono_decompose_opcode (cfg, ins);
11507                         }
11508
11509                         if (context_used) {
11510                                 MonoInst *args [3];
11511                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11512                                 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
11513
11514                                 /* FIXME: Use OP_NEWARR and decompose later to help abcrem */
11515
11516                                 /* vtable */
11517                                 args [0] = emit_get_rgctx_klass (cfg, context_used,
11518                                         array_class, MONO_RGCTX_INFO_VTABLE);
11519                                 /* array len */
11520                                 args [1] = sp [0];
11521
11522                                 if (managed_alloc)
11523                                         ins = mono_emit_method_call (cfg, managed_alloc, args, NULL);
11524                                 else
11525                                         ins = mono_emit_jit_icall (cfg, mono_array_new_specific, args);
11526                         } else {
11527                                 if (cfg->opt & MONO_OPT_SHARED) {
11528                                         /* Decompose now to avoid problems with references to the domainvar */
11529                                         MonoInst *iargs [3];
11530
11531                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11532                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11533                                         iargs [2] = sp [0];
11534
11535                                         ins = mono_emit_jit_icall (cfg, mono_array_new, iargs);
11536                                 } else {
11537                                         /* Decompose later since it is needed by abcrem */
11538                                         MonoClass *array_type = mono_array_class_get (klass, 1);
11539                                         mono_class_vtable (cfg->domain, array_type);
11540                                         CHECK_TYPELOAD (array_type);
11541
11542                                         MONO_INST_NEW (cfg, ins, OP_NEWARR);
11543                                         ins->dreg = alloc_ireg_ref (cfg);
11544                                         ins->sreg1 = sp [0]->dreg;
11545                                         ins->inst_newa_class = klass;
11546                                         ins->type = STACK_OBJ;
11547                                         ins->klass = array_type;
11548                                         MONO_ADD_INS (cfg->cbb, ins);
11549                                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11550                                         cfg->cbb->has_array_access = TRUE;
11551
11552                                         /* Needed so mono_emit_load_get_addr () gets called */
11553                                         mono_get_got_var (cfg);
11554                                 }
11555                         }
11556
11557                         len_ins = sp [0];
11558                         ip += 5;
11559                         *sp++ = ins;
11560                         inline_costs += 1;
11561
11562                         /* 
11563                          * we inline/optimize the initialization sequence if possible.
11564                          * we should also allocate the array as not cleared, since we spend as much time clearing to 0 as initializing
11565                          * for small sizes open code the memcpy
11566                          * ensure the rva field is big enough
11567                          */
11568                         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))) {
11569                                 MonoMethod *memcpy_method = get_memcpy_method ();
11570                                 MonoInst *iargs [3];
11571                                 int add_reg = alloc_ireg_mp (cfg);
11572
11573                                 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, add_reg, ins->dreg, MONO_STRUCT_OFFSET (MonoArray, vector));
11574                                 if (cfg->compile_aot) {
11575                                         EMIT_NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(field_token), STACK_PTR, NULL);
11576                                 } else {
11577                                         EMIT_NEW_PCONST (cfg, iargs [1], (char*)data_ptr);
11578                                 }
11579                                 EMIT_NEW_ICONST (cfg, iargs [2], data_size);
11580                                 mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
11581                                 ip += 11;
11582                         }
11583
11584                         break;
11585                 }
11586                 case CEE_LDLEN:
11587                         CHECK_STACK (1);
11588                         --sp;
11589                         if (sp [0]->type != STACK_OBJ)
11590                                 UNVERIFIED;
11591
11592                         MONO_INST_NEW (cfg, ins, OP_LDLEN);
11593                         ins->dreg = alloc_preg (cfg);
11594                         ins->sreg1 = sp [0]->dreg;
11595                         ins->type = STACK_I4;
11596                         /* This flag will be inherited by the decomposition */
11597                         ins->flags |= MONO_INST_FAULT;
11598                         MONO_ADD_INS (cfg->cbb, ins);
11599                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11600                         cfg->cbb->has_array_access = TRUE;
11601                         ip ++;
11602                         *sp++ = ins;
11603                         break;
11604                 case CEE_LDELEMA:
11605                         CHECK_STACK (2);
11606                         sp -= 2;
11607                         CHECK_OPSIZE (5);
11608                         if (sp [0]->type != STACK_OBJ)
11609                                 UNVERIFIED;
11610
11611                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11612
11613                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11614                         CHECK_TYPELOAD (klass);
11615                         /* we need to make sure that this array is exactly the type it needs
11616                          * to be for correctness. the wrappers are lax with their usage
11617                          * so we need to ignore them here
11618                          */
11619                         if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE && !readonly) {
11620                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11621                                 mini_emit_check_array_type (cfg, sp [0], array_class);
11622                                 CHECK_TYPELOAD (array_class);
11623                         }
11624
11625                         readonly = FALSE;
11626                         ins = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11627                         *sp++ = ins;
11628                         ip += 5;
11629                         break;
11630                 case CEE_LDELEM:
11631                 case CEE_LDELEM_I1:
11632                 case CEE_LDELEM_U1:
11633                 case CEE_LDELEM_I2:
11634                 case CEE_LDELEM_U2:
11635                 case CEE_LDELEM_I4:
11636                 case CEE_LDELEM_U4:
11637                 case CEE_LDELEM_I8:
11638                 case CEE_LDELEM_I:
11639                 case CEE_LDELEM_R4:
11640                 case CEE_LDELEM_R8:
11641                 case CEE_LDELEM_REF: {
11642                         MonoInst *addr;
11643
11644                         CHECK_STACK (2);
11645                         sp -= 2;
11646
11647                         if (*ip == CEE_LDELEM) {
11648                                 CHECK_OPSIZE (5);
11649                                 token = read32 (ip + 1);
11650                                 klass = mini_get_class (method, token, generic_context);
11651                                 CHECK_TYPELOAD (klass);
11652                                 mono_class_init (klass);
11653                         }
11654                         else
11655                                 klass = array_access_to_klass (*ip);
11656
11657                         if (sp [0]->type != STACK_OBJ)
11658                                 UNVERIFIED;
11659
11660                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11661
11662                         if (mini_is_gsharedvt_variable_klass (klass)) {
11663                                 // FIXME-VT: OP_ICONST optimization
11664                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11665                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11666                                 ins->opcode = OP_LOADV_MEMBASE;
11667                         } else if (sp [1]->opcode == OP_ICONST) {
11668                                 int array_reg = sp [0]->dreg;
11669                                 int index_reg = sp [1]->dreg;
11670                                 int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
11671
11672                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
11673                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset);
11674                         } else {
11675                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11676                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11677                         }
11678                         *sp++ = ins;
11679                         if (*ip == CEE_LDELEM)
11680                                 ip += 5;
11681                         else
11682                                 ++ip;
11683                         break;
11684                 }
11685                 case CEE_STELEM_I:
11686                 case CEE_STELEM_I1:
11687                 case CEE_STELEM_I2:
11688                 case CEE_STELEM_I4:
11689                 case CEE_STELEM_I8:
11690                 case CEE_STELEM_R4:
11691                 case CEE_STELEM_R8:
11692                 case CEE_STELEM_REF:
11693                 case CEE_STELEM: {
11694                         CHECK_STACK (3);
11695                         sp -= 3;
11696
11697                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11698
11699                         if (*ip == CEE_STELEM) {
11700                                 CHECK_OPSIZE (5);
11701                                 token = read32 (ip + 1);
11702                                 klass = mini_get_class (method, token, generic_context);
11703                                 CHECK_TYPELOAD (klass);
11704                                 mono_class_init (klass);
11705                         }
11706                         else
11707                                 klass = array_access_to_klass (*ip);
11708
11709                         if (sp [0]->type != STACK_OBJ)
11710                                 UNVERIFIED;
11711
11712                         emit_array_store (cfg, klass, sp, TRUE);
11713
11714                         if (*ip == CEE_STELEM)
11715                                 ip += 5;
11716                         else
11717                                 ++ip;
11718                         inline_costs += 1;
11719                         break;
11720                 }
11721                 case CEE_CKFINITE: {
11722                         CHECK_STACK (1);
11723                         --sp;
11724
11725                         MONO_INST_NEW (cfg, ins, OP_CKFINITE);
11726                         ins->sreg1 = sp [0]->dreg;
11727                         ins->dreg = alloc_freg (cfg);
11728                         ins->type = STACK_R8;
11729                         MONO_ADD_INS (cfg->cbb, ins);
11730
11731                         *sp++ = mono_decompose_opcode (cfg, ins);
11732
11733                         ++ip;
11734                         break;
11735                 }
11736                 case CEE_REFANYVAL: {
11737                         MonoInst *src_var, *src;
11738
11739                         int klass_reg = alloc_preg (cfg);
11740                         int dreg = alloc_preg (cfg);
11741
11742                         GSHAREDVT_FAILURE (*ip);
11743
11744                         CHECK_STACK (1);
11745                         MONO_INST_NEW (cfg, ins, *ip);
11746                         --sp;
11747                         CHECK_OPSIZE (5);
11748                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11749                         CHECK_TYPELOAD (klass);
11750
11751                         context_used = mini_class_check_context_used (cfg, klass);
11752
11753                         // FIXME:
11754                         src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
11755                         if (!src_var)
11756                                 src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
11757                         EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
11758                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass));
11759
11760                         if (context_used) {
11761                                 MonoInst *klass_ins;
11762
11763                                 klass_ins = emit_get_rgctx_klass (cfg, context_used,
11764                                                 klass, MONO_RGCTX_INFO_KLASS);
11765
11766                                 // FIXME:
11767                                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_ins->dreg);
11768                                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
11769                         } else {
11770                                 mini_emit_class_check (cfg, klass_reg, klass);
11771                         }
11772                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value));
11773                         ins->type = STACK_MP;
11774                         ins->klass = klass;
11775                         *sp++ = ins;
11776                         ip += 5;
11777                         break;
11778                 }
11779                 case CEE_MKREFANY: {
11780                         MonoInst *loc, *addr;
11781
11782                         GSHAREDVT_FAILURE (*ip);
11783
11784                         CHECK_STACK (1);
11785                         MONO_INST_NEW (cfg, ins, *ip);
11786                         --sp;
11787                         CHECK_OPSIZE (5);
11788                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11789                         CHECK_TYPELOAD (klass);
11790
11791                         context_used = mini_class_check_context_used (cfg, klass);
11792
11793                         loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
11794                         EMIT_NEW_TEMPLOADA (cfg, addr, loc->inst_c0);
11795
11796                         if (context_used) {
11797                                 MonoInst *const_ins;
11798                                 int type_reg = alloc_preg (cfg);
11799
11800                                 const_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
11801                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_ins->dreg);
11802                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_ins->dreg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
11803                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
11804                         } else if (cfg->compile_aot) {
11805                                 int const_reg = alloc_preg (cfg);
11806                                 int type_reg = alloc_preg (cfg);
11807
11808                                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
11809                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_reg);
11810                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_reg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
11811                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
11812                         } else {
11813                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), &klass->byval_arg);
11814                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), klass);
11815                         }
11816                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value), sp [0]->dreg);
11817
11818                         EMIT_NEW_TEMPLOAD (cfg, ins, loc->inst_c0);
11819                         ins->type = STACK_VTYPE;
11820                         ins->klass = mono_defaults.typed_reference_class;
11821                         *sp++ = ins;
11822                         ip += 5;
11823                         break;
11824                 }
11825                 case CEE_LDTOKEN: {
11826                         gpointer handle;
11827                         MonoClass *handle_class;
11828
11829                         CHECK_STACK_OVF (1);
11830
11831                         CHECK_OPSIZE (5);
11832                         n = read32 (ip + 1);
11833
11834                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD ||
11835                                         method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
11836                                 handle = mono_method_get_wrapper_data (method, n);
11837                                 handle_class = mono_method_get_wrapper_data (method, n + 1);
11838                                 if (handle_class == mono_defaults.typehandle_class)
11839                                         handle = &((MonoClass*)handle)->byval_arg;
11840                         }
11841                         else {
11842                                 handle = mono_ldtoken_checked (image, n, &handle_class, generic_context, &cfg->error);
11843                                 CHECK_CFG_ERROR;
11844                         }
11845                         if (!handle)
11846                                 LOAD_ERROR;
11847                         mono_class_init (handle_class);
11848                         if (cfg->gshared) {
11849                                 if (mono_metadata_token_table (n) == MONO_TABLE_TYPEDEF ||
11850                                                 mono_metadata_token_table (n) == MONO_TABLE_TYPEREF) {
11851                                         /* This case handles ldtoken
11852                                            of an open type, like for
11853                                            typeof(Gen<>). */
11854                                         context_used = 0;
11855                                 } else if (handle_class == mono_defaults.typehandle_class) {
11856                                         context_used = mini_class_check_context_used (cfg, mono_class_from_mono_type (handle));
11857                                 } else if (handle_class == mono_defaults.fieldhandle_class)
11858                                         context_used = mini_class_check_context_used (cfg, ((MonoClassField*)handle)->parent);
11859                                 else if (handle_class == mono_defaults.methodhandle_class)
11860                                         context_used = mini_method_check_context_used (cfg, handle);
11861                                 else
11862                                         g_assert_not_reached ();
11863                         }
11864
11865                         if ((cfg->opt & MONO_OPT_SHARED) &&
11866                                         method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD &&
11867                                         method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED) {
11868                                 MonoInst *addr, *vtvar, *iargs [3];
11869                                 int method_context_used;
11870
11871                                 method_context_used = mini_method_check_context_used (cfg, method);
11872
11873                                 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL); 
11874
11875                                 EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
11876                                 EMIT_NEW_ICONST (cfg, iargs [1], n);
11877                                 if (method_context_used) {
11878                                         iargs [2] = emit_get_rgctx_method (cfg, method_context_used,
11879                                                 method, MONO_RGCTX_INFO_METHOD);
11880                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper_generic_shared, iargs);
11881                                 } else {
11882                                         EMIT_NEW_PCONST (cfg, iargs [2], generic_context);
11883                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper, iargs);
11884                                 }
11885                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
11886
11887                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
11888
11889                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
11890                         } else {
11891                                 if ((ip + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 5) && 
11892                                         ((ip [5] == CEE_CALL) || (ip [5] == CEE_CALLVIRT)) && 
11893                                         (cmethod = mini_get_method (cfg, method, read32 (ip + 6), NULL, generic_context)) &&
11894                                         (cmethod->klass == mono_defaults.systemtype_class) &&
11895                                         (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
11896                                         MonoClass *tclass = mono_class_from_mono_type (handle);
11897
11898                                         mono_class_init (tclass);
11899                                         if (context_used) {
11900                                                 ins = emit_get_rgctx_klass (cfg, context_used,
11901                                                         tclass, MONO_RGCTX_INFO_REFLECTION_TYPE);
11902                                         } else if (cfg->compile_aot) {
11903                                                 if (method->wrapper_type) {
11904                                                         mono_error_init (&error); //got to do it since there are multiple conditionals below
11905                                                         if (mono_class_get_checked (tclass->image, tclass->type_token, &error) == tclass && !generic_context) {
11906                                                                 /* Special case for static synchronized wrappers */
11907                                                                 EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, tclass->image, tclass->type_token, generic_context);
11908                                                         } else {
11909                                                                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
11910                                                                 /* FIXME: n is not a normal token */
11911                                                                 DISABLE_AOT (cfg);
11912                                                                 EMIT_NEW_PCONST (cfg, ins, NULL);
11913                                                         }
11914                                                 } else {
11915                                                         EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n, generic_context);
11916                                                 }
11917                                         } else {
11918                                                 EMIT_NEW_PCONST (cfg, ins, mono_type_get_object (cfg->domain, handle));
11919                                         }
11920                                         ins->type = STACK_OBJ;
11921                                         ins->klass = cmethod->klass;
11922                                         ip += 5;
11923                                 } else {
11924                                         MonoInst *addr, *vtvar;
11925
11926                                         vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
11927
11928                                         if (context_used) {
11929                                                 if (handle_class == mono_defaults.typehandle_class) {
11930                                                         ins = emit_get_rgctx_klass (cfg, context_used,
11931                                                                         mono_class_from_mono_type (handle),
11932                                                                         MONO_RGCTX_INFO_TYPE);
11933                                                 } else if (handle_class == mono_defaults.methodhandle_class) {
11934                                                         ins = emit_get_rgctx_method (cfg, context_used,
11935                                                                         handle, MONO_RGCTX_INFO_METHOD);
11936                                                 } else if (handle_class == mono_defaults.fieldhandle_class) {
11937                                                         ins = emit_get_rgctx_field (cfg, context_used,
11938                                                                         handle, MONO_RGCTX_INFO_CLASS_FIELD);
11939                                                 } else {
11940                                                         g_assert_not_reached ();
11941                                                 }
11942                                         } else if (cfg->compile_aot) {
11943                                                 EMIT_NEW_LDTOKENCONST (cfg, ins, image, n, generic_context);
11944                                         } else {
11945                                                 EMIT_NEW_PCONST (cfg, ins, handle);
11946                                         }
11947                                         EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
11948                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
11949                                         EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
11950                                 }
11951                         }
11952
11953                         *sp++ = ins;
11954                         ip += 5;
11955                         break;
11956                 }
11957                 case CEE_THROW:
11958                         CHECK_STACK (1);
11959                         MONO_INST_NEW (cfg, ins, OP_THROW);
11960                         --sp;
11961                         ins->sreg1 = sp [0]->dreg;
11962                         ip++;
11963                         cfg->cbb->out_of_line = TRUE;
11964                         MONO_ADD_INS (cfg->cbb, ins);
11965                         MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
11966                         MONO_ADD_INS (cfg->cbb, ins);
11967                         sp = stack_start;
11968                         
11969                         link_bblock (cfg, cfg->cbb, end_bblock);
11970                         start_new_bblock = 1;
11971                         break;
11972                 case CEE_ENDFINALLY:
11973                         /* mono_save_seq_point_info () depends on this */
11974                         if (sp != stack_start)
11975                                 emit_seq_point (cfg, method, ip, FALSE, FALSE);
11976                         MONO_INST_NEW (cfg, ins, OP_ENDFINALLY);
11977                         MONO_ADD_INS (cfg->cbb, ins);
11978                         ip++;
11979                         start_new_bblock = 1;
11980
11981                         /*
11982                          * Control will leave the method so empty the stack, otherwise
11983                          * the next basic block will start with a nonempty stack.
11984                          */
11985                         while (sp != stack_start) {
11986                                 sp--;
11987                         }
11988                         break;
11989                 case CEE_LEAVE:
11990                 case CEE_LEAVE_S: {
11991                         GList *handlers;
11992
11993                         if (*ip == CEE_LEAVE) {
11994                                 CHECK_OPSIZE (5);
11995                                 target = ip + 5 + (gint32)read32(ip + 1);
11996                         } else {
11997                                 CHECK_OPSIZE (2);
11998                                 target = ip + 2 + (signed char)(ip [1]);
11999                         }
12000
12001                         /* empty the stack */
12002                         while (sp != stack_start) {
12003                                 sp--;
12004                         }
12005
12006                         /* 
12007                          * If this leave statement is in a catch block, check for a
12008                          * pending exception, and rethrow it if necessary.
12009                          * We avoid doing this in runtime invoke wrappers, since those are called
12010                          * by native code which excepts the wrapper to catch all exceptions.
12011                          */
12012                         for (i = 0; i < header->num_clauses; ++i) {
12013                                 MonoExceptionClause *clause = &header->clauses [i];
12014
12015                                 /* 
12016                                  * Use <= in the final comparison to handle clauses with multiple
12017                                  * leave statements, like in bug #78024.
12018                                  * The ordering of the exception clauses guarantees that we find the
12019                                  * innermost clause.
12020                                  */
12021                                 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) {
12022                                         MonoInst *exc_ins;
12023                                         MonoBasicBlock *dont_throw;
12024
12025                                         /*
12026                                           MonoInst *load;
12027
12028                                           NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, clause->handler_offset)->inst_c0);
12029                                         */
12030
12031                                         exc_ins = mono_emit_jit_icall (cfg, mono_thread_get_undeniable_exception, NULL);
12032
12033                                         NEW_BBLOCK (cfg, dont_throw);
12034
12035                                         /*
12036                                          * Currently, we always rethrow the abort exception, despite the 
12037                                          * fact that this is not correct. See thread6.cs for an example. 
12038                                          * But propagating the abort exception is more important than 
12039                                          * getting the sematics right.
12040                                          */
12041                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, exc_ins->dreg, 0);
12042                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, dont_throw);
12043                                         MONO_EMIT_NEW_UNALU (cfg, OP_THROW, -1, exc_ins->dreg);
12044
12045                                         MONO_START_BB (cfg, dont_throw);
12046                                 }
12047                         }
12048
12049                         if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
12050                                 GList *tmp;
12051                                 MonoExceptionClause *clause;
12052
12053                                 for (tmp = handlers; tmp; tmp = tmp->next) {
12054                                         clause = tmp->data;
12055                                         tblock = cfg->cil_offset_to_bb [clause->handler_offset];
12056                                         g_assert (tblock);
12057                                         link_bblock (cfg, cfg->cbb, tblock);
12058                                         MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
12059                                         ins->inst_target_bb = tblock;
12060                                         ins->inst_eh_block = clause;
12061                                         MONO_ADD_INS (cfg->cbb, ins);
12062                                         cfg->cbb->has_call_handler = 1;
12063                                         if (COMPILE_LLVM (cfg)) {
12064                                                 MonoBasicBlock *target_bb;
12065
12066                                                 /* 
12067                                                  * Link the finally bblock with the target, since it will
12068                                                  * conceptually branch there.
12069                                                  * FIXME: Have to link the bblock containing the endfinally.
12070                                                  */
12071                                                 GET_BBLOCK (cfg, target_bb, target);
12072                                                 link_bblock (cfg, tblock, target_bb);
12073                                         }
12074                                 }
12075                                 g_list_free (handlers);
12076                         } 
12077
12078                         MONO_INST_NEW (cfg, ins, OP_BR);
12079                         MONO_ADD_INS (cfg->cbb, ins);
12080                         GET_BBLOCK (cfg, tblock, target);
12081                         link_bblock (cfg, cfg->cbb, tblock);
12082                         ins->inst_target_bb = tblock;
12083                         start_new_bblock = 1;
12084
12085                         if (*ip == CEE_LEAVE)
12086                                 ip += 5;
12087                         else
12088                                 ip += 2;
12089
12090                         break;
12091                 }
12092
12093                         /*
12094                          * Mono specific opcodes
12095                          */
12096                 case MONO_CUSTOM_PREFIX: {
12097
12098                         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
12099
12100                         CHECK_OPSIZE (2);
12101                         switch (ip [1]) {
12102                         case CEE_MONO_ICALL: {
12103                                 gpointer func;
12104                                 MonoJitICallInfo *info;
12105
12106                                 token = read32 (ip + 2);
12107                                 func = mono_method_get_wrapper_data (method, token);
12108                                 info = mono_find_jit_icall_by_addr (func);
12109                                 if (!info)
12110                                         g_error ("Could not find icall address in wrapper %s", mono_method_full_name (method, 1));
12111                                 g_assert (info);
12112
12113                                 CHECK_STACK (info->sig->param_count);
12114                                 sp -= info->sig->param_count;
12115
12116                                 ins = mono_emit_jit_icall (cfg, info->func, sp);
12117                                 if (!MONO_TYPE_IS_VOID (info->sig->ret))
12118                                         *sp++ = ins;
12119
12120                                 ip += 6;
12121                                 inline_costs += 10 * num_calls++;
12122
12123                                 break;
12124                         }
12125                         case CEE_MONO_LDPTR_CARD_TABLE: {
12126                                 int shift_bits;
12127                                 gpointer card_mask;
12128                                 CHECK_STACK_OVF (1);
12129
12130                                 if (cfg->compile_aot)
12131                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR, NULL);
12132                                 else
12133                                         EMIT_NEW_PCONST (cfg, ins, mono_gc_get_card_table (&shift_bits, &card_mask));
12134
12135                                 *sp++ = ins;
12136                                 ip += 2;
12137                                 inline_costs += 10 * num_calls++;
12138                                 break;
12139                         }
12140                         case CEE_MONO_LDPTR_NURSERY_START: {
12141                                 int shift_bits;
12142                                 size_t size;
12143                                 CHECK_STACK_OVF (1);
12144
12145                                 if (cfg->compile_aot)
12146                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_GC_NURSERY_START, NULL);
12147                                 else
12148                                         EMIT_NEW_PCONST (cfg, ins, mono_gc_get_nursery (&shift_bits, &size));
12149
12150                                 *sp++ = ins;
12151                                 ip += 2;
12152                                 inline_costs += 10 * num_calls++;
12153                                 break;
12154                         }
12155                         case CEE_MONO_LDPTR_INT_REQ_FLAG: {
12156                                 CHECK_STACK_OVF (1);
12157
12158                                 if (cfg->compile_aot)
12159                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG, NULL);
12160                                 else
12161                                         EMIT_NEW_PCONST (cfg, ins, mono_thread_interruption_request_flag ());
12162
12163                                 *sp++ = ins;
12164                                 ip += 2;
12165                                 inline_costs += 10 * num_calls++;
12166                                 break;
12167                         }
12168                         case CEE_MONO_LDPTR: {
12169                                 gpointer ptr;
12170
12171                                 CHECK_STACK_OVF (1);
12172                                 CHECK_OPSIZE (6);
12173                                 token = read32 (ip + 2);
12174
12175                                 ptr = mono_method_get_wrapper_data (method, token);
12176                                 EMIT_NEW_PCONST (cfg, ins, ptr);
12177                                 *sp++ = ins;
12178                                 ip += 6;
12179                                 inline_costs += 10 * num_calls++;
12180                                 /* Can't embed random pointers into AOT code */
12181                                 DISABLE_AOT (cfg);
12182                                 break;
12183                         }
12184                         case CEE_MONO_JIT_ICALL_ADDR: {
12185                                 MonoJitICallInfo *callinfo;
12186                                 gpointer ptr;
12187
12188                                 CHECK_STACK_OVF (1);
12189                                 CHECK_OPSIZE (6);
12190                                 token = read32 (ip + 2);
12191
12192                                 ptr = mono_method_get_wrapper_data (method, token);
12193                                 callinfo = mono_find_jit_icall_by_addr (ptr);
12194                                 g_assert (callinfo);
12195                                 EMIT_NEW_JIT_ICALL_ADDRCONST (cfg, ins, (char*)callinfo->name);
12196                                 *sp++ = ins;
12197                                 ip += 6;
12198                                 inline_costs += 10 * num_calls++;
12199                                 break;
12200                         }
12201                         case CEE_MONO_ICALL_ADDR: {
12202                                 MonoMethod *cmethod;
12203                                 gpointer ptr;
12204
12205                                 CHECK_STACK_OVF (1);
12206                                 CHECK_OPSIZE (6);
12207                                 token = read32 (ip + 2);
12208
12209                                 cmethod = mono_method_get_wrapper_data (method, token);
12210
12211                                 if (cfg->compile_aot) {
12212                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, cmethod);
12213                                 } else {
12214                                         ptr = mono_lookup_internal_call (cmethod);
12215                                         g_assert (ptr);
12216                                         EMIT_NEW_PCONST (cfg, ins, ptr);
12217                                 }
12218                                 *sp++ = ins;
12219                                 ip += 6;
12220                                 break;
12221                         }
12222                         case CEE_MONO_VTADDR: {
12223                                 MonoInst *src_var, *src;
12224
12225                                 CHECK_STACK (1);
12226                                 --sp;
12227
12228                                 // FIXME:
12229                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
12230                                 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
12231                                 *sp++ = src;
12232                                 ip += 2;
12233                                 break;
12234                         }
12235                         case CEE_MONO_NEWOBJ: {
12236                                 MonoInst *iargs [2];
12237
12238                                 CHECK_STACK_OVF (1);
12239                                 CHECK_OPSIZE (6);
12240                                 token = read32 (ip + 2);
12241                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12242                                 mono_class_init (klass);
12243                                 NEW_DOMAINCONST (cfg, iargs [0]);
12244                                 MONO_ADD_INS (cfg->cbb, iargs [0]);
12245                                 NEW_CLASSCONST (cfg, iargs [1], klass);
12246                                 MONO_ADD_INS (cfg->cbb, iargs [1]);
12247                                 *sp++ = mono_emit_jit_icall (cfg, mono_object_new, iargs);
12248                                 ip += 6;
12249                                 inline_costs += 10 * num_calls++;
12250                                 break;
12251                         }
12252                         case CEE_MONO_OBJADDR:
12253                                 CHECK_STACK (1);
12254                                 --sp;
12255                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
12256                                 ins->dreg = alloc_ireg_mp (cfg);
12257                                 ins->sreg1 = sp [0]->dreg;
12258                                 ins->type = STACK_MP;
12259                                 MONO_ADD_INS (cfg->cbb, ins);
12260                                 *sp++ = ins;
12261                                 ip += 2;
12262                                 break;
12263                         case CEE_MONO_LDNATIVEOBJ:
12264                                 /*
12265                                  * Similar to LDOBJ, but instead load the unmanaged 
12266                                  * representation of the vtype to the stack.
12267                                  */
12268                                 CHECK_STACK (1);
12269                                 CHECK_OPSIZE (6);
12270                                 --sp;
12271                                 token = read32 (ip + 2);
12272                                 klass = mono_method_get_wrapper_data (method, token);
12273                                 g_assert (klass->valuetype);
12274                                 mono_class_init (klass);
12275
12276                                 {
12277                                         MonoInst *src, *dest, *temp;
12278
12279                                         src = sp [0];
12280                                         temp = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
12281                                         temp->backend.is_pinvoke = 1;
12282                                         EMIT_NEW_TEMPLOADA (cfg, dest, temp->inst_c0);
12283                                         mini_emit_stobj (cfg, dest, src, klass, TRUE);
12284
12285                                         EMIT_NEW_TEMPLOAD (cfg, dest, temp->inst_c0);
12286                                         dest->type = STACK_VTYPE;
12287                                         dest->klass = klass;
12288
12289                                         *sp ++ = dest;
12290                                         ip += 6;
12291                                 }
12292                                 break;
12293                         case CEE_MONO_RETOBJ: {
12294                                 /*
12295                                  * Same as RET, but return the native representation of a vtype
12296                                  * to the caller.
12297                                  */
12298                                 g_assert (cfg->ret);
12299                                 g_assert (mono_method_signature (method)->pinvoke); 
12300                                 CHECK_STACK (1);
12301                                 --sp;
12302                                 
12303                                 CHECK_OPSIZE (6);
12304                                 token = read32 (ip + 2);    
12305                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12306
12307                                 if (!cfg->vret_addr) {
12308                                         g_assert (cfg->ret_var_is_local);
12309
12310                                         EMIT_NEW_VARLOADA (cfg, ins, cfg->ret, cfg->ret->inst_vtype);
12311                                 } else {
12312                                         EMIT_NEW_RETLOADA (cfg, ins);
12313                                 }
12314                                 mini_emit_stobj (cfg, ins, sp [0], klass, TRUE);
12315                                 
12316                                 if (sp != stack_start)
12317                                         UNVERIFIED;
12318                                 
12319                                 MONO_INST_NEW (cfg, ins, OP_BR);
12320                                 ins->inst_target_bb = end_bblock;
12321                                 MONO_ADD_INS (cfg->cbb, ins);
12322                                 link_bblock (cfg, cfg->cbb, end_bblock);
12323                                 start_new_bblock = 1;
12324                                 ip += 6;
12325                                 break;
12326                         }
12327                         case CEE_MONO_CISINST:
12328                         case CEE_MONO_CCASTCLASS: {
12329                                 int token;
12330                                 CHECK_STACK (1);
12331                                 --sp;
12332                                 CHECK_OPSIZE (6);
12333                                 token = read32 (ip + 2);
12334                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12335                                 if (ip [1] == CEE_MONO_CISINST)
12336                                         ins = handle_cisinst (cfg, klass, sp [0]);
12337                                 else
12338                                         ins = handle_ccastclass (cfg, klass, sp [0]);
12339                                 *sp++ = ins;
12340                                 ip += 6;
12341                                 break;
12342                         }
12343                         case CEE_MONO_SAVE_LMF:
12344                         case CEE_MONO_RESTORE_LMF:
12345                                 ip += 2;
12346                                 break;
12347                         case CEE_MONO_CLASSCONST:
12348                                 CHECK_STACK_OVF (1);
12349                                 CHECK_OPSIZE (6);
12350                                 token = read32 (ip + 2);
12351                                 EMIT_NEW_CLASSCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
12352                                 *sp++ = ins;
12353                                 ip += 6;
12354                                 inline_costs += 10 * num_calls++;
12355                                 break;
12356                         case CEE_MONO_NOT_TAKEN:
12357                                 cfg->cbb->out_of_line = TRUE;
12358                                 ip += 2;
12359                                 break;
12360                         case CEE_MONO_TLS: {
12361                                 int key;
12362
12363                                 CHECK_STACK_OVF (1);
12364                                 CHECK_OPSIZE (6);
12365                                 key = (gint32)read32 (ip + 2);
12366                                 g_assert (key < TLS_KEY_NUM);
12367
12368                                 ins = mono_create_tls_get (cfg, key);
12369                                 if (!ins) {
12370                                         if (cfg->compile_aot) {
12371                                                 DISABLE_AOT (cfg);
12372                                                 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
12373                                                 ins->dreg = alloc_preg (cfg);
12374                                                 ins->type = STACK_PTR;
12375                                         } else {
12376                                                 g_assert_not_reached ();
12377                                         }
12378                                 }
12379                                 ins->type = STACK_PTR;
12380                                 MONO_ADD_INS (cfg->cbb, ins);
12381                                 *sp++ = ins;
12382                                 ip += 6;
12383                                 break;
12384                         }
12385                         case CEE_MONO_DYN_CALL: {
12386                                 MonoCallInst *call;
12387
12388                                 /* It would be easier to call a trampoline, but that would put an
12389                                  * extra frame on the stack, confusing exception handling. So
12390                                  * implement it inline using an opcode for now.
12391                                  */
12392
12393                                 if (!cfg->dyn_call_var) {
12394                                         cfg->dyn_call_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12395                                         /* prevent it from being register allocated */
12396                                         cfg->dyn_call_var->flags |= MONO_INST_VOLATILE;
12397                                 }
12398
12399                                 /* Has to use a call inst since it local regalloc expects it */
12400                                 MONO_INST_NEW_CALL (cfg, call, OP_DYN_CALL);
12401                                 ins = (MonoInst*)call;
12402                                 sp -= 2;
12403                                 ins->sreg1 = sp [0]->dreg;
12404                                 ins->sreg2 = sp [1]->dreg;
12405                                 MONO_ADD_INS (cfg->cbb, ins);
12406
12407                                 cfg->param_area = MAX (cfg->param_area, MONO_ARCH_DYN_CALL_PARAM_AREA);
12408
12409                                 ip += 2;
12410                                 inline_costs += 10 * num_calls++;
12411
12412                                 break;
12413                         }
12414                         case CEE_MONO_MEMORY_BARRIER: {
12415                                 CHECK_OPSIZE (6);
12416                                 emit_memory_barrier (cfg, (int)read32 (ip + 2));
12417                                 ip += 6;
12418                                 break;
12419                         }
12420                         case CEE_MONO_JIT_ATTACH: {
12421                                 MonoInst *args [16], *domain_ins;
12422                                 MonoInst *ad_ins, *jit_tls_ins;
12423                                 MonoBasicBlock *next_bb = NULL, *call_bb = NULL;
12424
12425                                 cfg->orig_domain_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12426
12427                                 EMIT_NEW_PCONST (cfg, ins, NULL);
12428                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12429
12430                                 ad_ins = mono_get_domain_intrinsic (cfg);
12431                                 jit_tls_ins = mono_get_jit_tls_intrinsic (cfg);
12432
12433                                 if (MONO_ARCH_HAVE_TLS_GET && ad_ins && jit_tls_ins) {
12434                                         NEW_BBLOCK (cfg, next_bb);
12435                                         NEW_BBLOCK (cfg, call_bb);
12436
12437                                         if (cfg->compile_aot) {
12438                                                 /* AOT code is only used in the root domain */
12439                                                 EMIT_NEW_PCONST (cfg, domain_ins, NULL);
12440                                         } else {
12441                                                 EMIT_NEW_PCONST (cfg, domain_ins, cfg->domain);
12442                                         }
12443                                         MONO_ADD_INS (cfg->cbb, ad_ins);
12444                                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, ad_ins->dreg, domain_ins->dreg);
12445                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, call_bb);
12446
12447                                         MONO_ADD_INS (cfg->cbb, jit_tls_ins);
12448                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, jit_tls_ins->dreg, 0);
12449                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, call_bb);
12450
12451                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, next_bb);
12452                                         MONO_START_BB (cfg, call_bb);
12453                                 }
12454
12455                                 if (cfg->compile_aot) {
12456                                         /* AOT code is only used in the root domain */
12457                                         EMIT_NEW_PCONST (cfg, args [0], NULL);
12458                                 } else {
12459                                         EMIT_NEW_PCONST (cfg, args [0], cfg->domain);
12460                                 }
12461                                 ins = mono_emit_jit_icall (cfg, mono_jit_thread_attach, args);
12462                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12463
12464                                 if (next_bb)
12465                                         MONO_START_BB (cfg, next_bb);
12466                                 ip += 2;
12467                                 break;
12468                         }
12469                         case CEE_MONO_JIT_DETACH: {
12470                                 MonoInst *args [16];
12471
12472                                 /* Restore the original domain */
12473                                 dreg = alloc_ireg (cfg);
12474                                 EMIT_NEW_UNALU (cfg, args [0], OP_MOVE, dreg, cfg->orig_domain_var->dreg);
12475                                 mono_emit_jit_icall (cfg, mono_jit_set_domain, args);
12476                                 ip += 2;
12477                                 break;
12478                         }
12479                         default:
12480                                 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
12481                                 break;
12482                         }
12483                         break;
12484                 }
12485
12486                 case CEE_PREFIX1: {
12487                         CHECK_OPSIZE (2);
12488                         switch (ip [1]) {
12489                         case CEE_ARGLIST: {
12490                                 /* somewhat similar to LDTOKEN */
12491                                 MonoInst *addr, *vtvar;
12492                                 CHECK_STACK_OVF (1);
12493                                 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL); 
12494
12495                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
12496                                 EMIT_NEW_UNALU (cfg, ins, OP_ARGLIST, -1, addr->dreg);
12497
12498                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
12499                                 ins->type = STACK_VTYPE;
12500                                 ins->klass = mono_defaults.argumenthandle_class;
12501                                 *sp++ = ins;
12502                                 ip += 2;
12503                                 break;
12504                         }
12505                         case CEE_CEQ:
12506                         case CEE_CGT:
12507                         case CEE_CGT_UN:
12508                         case CEE_CLT:
12509                         case CEE_CLT_UN: {
12510                                 MonoInst *cmp, *arg1, *arg2;
12511
12512                                 CHECK_STACK (2);
12513                                 sp -= 2;
12514                                 arg1 = sp [0];
12515                                 arg2 = sp [1];
12516
12517                                 /*
12518                                  * The following transforms:
12519                                  *    CEE_CEQ    into OP_CEQ
12520                                  *    CEE_CGT    into OP_CGT
12521                                  *    CEE_CGT_UN into OP_CGT_UN
12522                                  *    CEE_CLT    into OP_CLT
12523                                  *    CEE_CLT_UN into OP_CLT_UN
12524                                  */
12525                                 MONO_INST_NEW (cfg, cmp, (OP_CEQ - CEE_CEQ) + ip [1]);
12526
12527                                 MONO_INST_NEW (cfg, ins, cmp->opcode);
12528                                 cmp->sreg1 = arg1->dreg;
12529                                 cmp->sreg2 = arg2->dreg;
12530                                 type_from_op (cfg, cmp, arg1, arg2);
12531                                 CHECK_TYPE (cmp);
12532                                 add_widen_op (cfg, cmp, &arg1, &arg2);
12533                                 if ((arg1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((arg1->type == STACK_PTR) || (arg1->type == STACK_OBJ) || (arg1->type == STACK_MP))))
12534                                         cmp->opcode = OP_LCOMPARE;
12535                                 else if (arg1->type == STACK_R4)
12536                                         cmp->opcode = OP_RCOMPARE;
12537                                 else if (arg1->type == STACK_R8)
12538                                         cmp->opcode = OP_FCOMPARE;
12539                                 else
12540                                         cmp->opcode = OP_ICOMPARE;
12541                                 MONO_ADD_INS (cfg->cbb, cmp);
12542                                 ins->type = STACK_I4;
12543                                 ins->dreg = alloc_dreg (cfg, ins->type);
12544                                 type_from_op (cfg, ins, arg1, arg2);
12545
12546                                 if (cmp->opcode == OP_FCOMPARE || cmp->opcode == OP_RCOMPARE) {
12547                                         /*
12548                                          * The backends expect the fceq opcodes to do the
12549                                          * comparison too.
12550                                          */
12551                                         ins->sreg1 = cmp->sreg1;
12552                                         ins->sreg2 = cmp->sreg2;
12553                                         NULLIFY_INS (cmp);
12554                                 }
12555                                 MONO_ADD_INS (cfg->cbb, ins);
12556                                 *sp++ = ins;
12557                                 ip += 2;
12558                                 break;
12559                         }
12560                         case CEE_LDFTN: {
12561                                 MonoInst *argconst;
12562                                 MonoMethod *cil_method;
12563
12564                                 CHECK_STACK_OVF (1);
12565                                 CHECK_OPSIZE (6);
12566                                 n = read32 (ip + 2);
12567                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
12568                                 if (!cmethod || mono_loader_get_last_error ())
12569                                         LOAD_ERROR;
12570                                 mono_class_init (cmethod->klass);
12571
12572                                 mono_save_token_info (cfg, image, n, cmethod);
12573
12574                                 context_used = mini_method_check_context_used (cfg, cmethod);
12575
12576                                 cil_method = cmethod;
12577                                 if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
12578                                         METHOD_ACCESS_FAILURE (method, cil_method);
12579
12580                                 if (mono_security_core_clr_enabled ())
12581                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
12582
12583                                 /* 
12584                                  * Optimize the common case of ldftn+delegate creation
12585                                  */
12586                                 if ((sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 6) && (ip [6] == CEE_NEWOBJ)) {
12587                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
12588                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
12589                                                 MonoInst *target_ins, *handle_ins;
12590                                                 MonoMethod *invoke;
12591                                                 int invoke_context_used;
12592
12593                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
12594                                                 if (!invoke || !mono_method_signature (invoke))
12595                                                         LOAD_ERROR;
12596
12597                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
12598
12599                                                 target_ins = sp [-1];
12600
12601                                                 if (mono_security_core_clr_enabled ())
12602                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
12603
12604                                                 if (!(cmethod->flags & METHOD_ATTRIBUTE_STATIC)) {
12605                                                         /*LAME IMPL: We must not add a null check for virtual invoke delegates.*/
12606                                                         if (mono_method_signature (invoke)->param_count == mono_method_signature (cmethod)->param_count) {
12607                                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, target_ins->dreg, 0);
12608                                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "ArgumentException");
12609                                                         }
12610                                                 }
12611
12612                                                 /* FIXME: SGEN support */
12613                                                 if (invoke_context_used == 0) {
12614                                                         ip += 6;
12615                                                         if (cfg->verbose_level > 3)
12616                                                                 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));
12617                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, FALSE))) {
12618                                                                 sp --;
12619                                                                 *sp = handle_ins;
12620                                                                 CHECK_CFG_EXCEPTION;
12621                                                                 ip += 5;
12622                                                                 sp ++;
12623                                                                 break;
12624                                                         }
12625                                                         ip -= 6;
12626                                                 }
12627                                         }
12628                                 }
12629
12630                                 argconst = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD);
12631                                 ins = mono_emit_jit_icall (cfg, mono_ldftn, &argconst);
12632                                 *sp++ = ins;
12633                                 
12634                                 ip += 6;
12635                                 inline_costs += 10 * num_calls++;
12636                                 break;
12637                         }
12638                         case CEE_LDVIRTFTN: {
12639                                 MonoInst *args [2];
12640
12641                                 CHECK_STACK (1);
12642                                 CHECK_OPSIZE (6);
12643                                 n = read32 (ip + 2);
12644                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
12645                                 if (!cmethod || mono_loader_get_last_error ())
12646                                         LOAD_ERROR;
12647                                 mono_class_init (cmethod->klass);
12648  
12649                                 context_used = mini_method_check_context_used (cfg, cmethod);
12650
12651                                 if (mono_security_core_clr_enabled ())
12652                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
12653
12654                                 /*
12655                                  * Optimize the common case of ldvirtftn+delegate creation
12656                                  */
12657                                 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)) {
12658                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
12659                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
12660                                                 MonoInst *target_ins, *handle_ins;
12661                                                 MonoMethod *invoke;
12662                                                 int invoke_context_used;
12663                                                 gboolean is_virtual = cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL;
12664
12665                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
12666                                                 if (!invoke || !mono_method_signature (invoke))
12667                                                         LOAD_ERROR;
12668
12669                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
12670
12671                                                 target_ins = sp [-1];
12672
12673                                                 if (mono_security_core_clr_enabled ())
12674                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
12675
12676                                                 /* FIXME: SGEN support */
12677                                                 if (invoke_context_used == 0 || cfg->llvm_only) {
12678                                                         ip += 6;
12679                                                         if (cfg->verbose_level > 3)
12680                                                                 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));
12681                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, is_virtual))) {
12682                                                                 sp -= 2;
12683                                                                 *sp = handle_ins;
12684                                                                 CHECK_CFG_EXCEPTION;
12685                                                                 ip += 5;
12686                                                                 sp ++;
12687                                                                 break;
12688                                                         }
12689                                                         ip -= 6;
12690                                                 }
12691                                         }
12692                                 }
12693
12694                                 --sp;
12695                                 args [0] = *sp;
12696
12697                                 args [1] = emit_get_rgctx_method (cfg, context_used,
12698                                                                                                   cmethod, MONO_RGCTX_INFO_METHOD);
12699
12700                                 if (context_used)
12701                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn_gshared, args);
12702                                 else
12703                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn, args);
12704
12705                                 ip += 6;
12706                                 inline_costs += 10 * num_calls++;
12707                                 break;
12708                         }
12709                         case CEE_LDARG:
12710                                 CHECK_STACK_OVF (1);
12711                                 CHECK_OPSIZE (4);
12712                                 n = read16 (ip + 2);
12713                                 CHECK_ARG (n);
12714                                 EMIT_NEW_ARGLOAD (cfg, ins, n);
12715                                 *sp++ = ins;
12716                                 ip += 4;
12717                                 break;
12718                         case CEE_LDARGA:
12719                                 CHECK_STACK_OVF (1);
12720                                 CHECK_OPSIZE (4);
12721                                 n = read16 (ip + 2);
12722                                 CHECK_ARG (n);
12723                                 NEW_ARGLOADA (cfg, ins, n);
12724                                 MONO_ADD_INS (cfg->cbb, ins);
12725                                 *sp++ = ins;
12726                                 ip += 4;
12727                                 break;
12728                         case CEE_STARG:
12729                                 CHECK_STACK (1);
12730                                 --sp;
12731                                 CHECK_OPSIZE (4);
12732                                 n = read16 (ip + 2);
12733                                 CHECK_ARG (n);
12734                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
12735                                         UNVERIFIED;
12736                                 EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
12737                                 ip += 4;
12738                                 break;
12739                         case CEE_LDLOC:
12740                                 CHECK_STACK_OVF (1);
12741                                 CHECK_OPSIZE (4);
12742                                 n = read16 (ip + 2);
12743                                 CHECK_LOCAL (n);
12744                                 EMIT_NEW_LOCLOAD (cfg, ins, n);
12745                                 *sp++ = ins;
12746                                 ip += 4;
12747                                 break;
12748                         case CEE_LDLOCA: {
12749                                 unsigned char *tmp_ip;
12750                                 CHECK_STACK_OVF (1);
12751                                 CHECK_OPSIZE (4);
12752                                 n = read16 (ip + 2);
12753                                 CHECK_LOCAL (n);
12754
12755                                 if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 2))) {
12756                                         ip = tmp_ip;
12757                                         inline_costs += 1;
12758                                         break;
12759                                 }                       
12760                                 
12761                                 EMIT_NEW_LOCLOADA (cfg, ins, n);
12762                                 *sp++ = ins;
12763                                 ip += 4;
12764                                 break;
12765                         }
12766                         case CEE_STLOC:
12767                                 CHECK_STACK (1);
12768                                 --sp;
12769                                 CHECK_OPSIZE (4);
12770                                 n = read16 (ip + 2);
12771                                 CHECK_LOCAL (n);
12772                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
12773                                         UNVERIFIED;
12774                                 emit_stloc_ir (cfg, sp, header, n);
12775                                 ip += 4;
12776                                 inline_costs += 1;
12777                                 break;
12778                         case CEE_LOCALLOC:
12779                                 CHECK_STACK (1);
12780                                 --sp;
12781                                 if (sp != stack_start) 
12782                                         UNVERIFIED;
12783                                 if (cfg->method != method) 
12784                                         /* 
12785                                          * Inlining this into a loop in a parent could lead to 
12786                                          * stack overflows which is different behavior than the
12787                                          * non-inlined case, thus disable inlining in this case.
12788                                          */
12789                                         INLINE_FAILURE("localloc");
12790
12791                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
12792                                 ins->dreg = alloc_preg (cfg);
12793                                 ins->sreg1 = sp [0]->dreg;
12794                                 ins->type = STACK_PTR;
12795                                 MONO_ADD_INS (cfg->cbb, ins);
12796
12797                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12798                                 if (init_locals)
12799                                         ins->flags |= MONO_INST_INIT;
12800
12801                                 *sp++ = ins;
12802                                 ip += 2;
12803                                 break;
12804                         case CEE_ENDFILTER: {
12805                                 MonoExceptionClause *clause, *nearest;
12806                                 int cc;
12807
12808                                 CHECK_STACK (1);
12809                                 --sp;
12810                                 if ((sp != stack_start) || (sp [0]->type != STACK_I4)) 
12811                                         UNVERIFIED;
12812                                 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
12813                                 ins->sreg1 = (*sp)->dreg;
12814                                 MONO_ADD_INS (cfg->cbb, ins);
12815                                 start_new_bblock = 1;
12816                                 ip += 2;
12817
12818                                 nearest = NULL;
12819                                 for (cc = 0; cc < header->num_clauses; ++cc) {
12820                                         clause = &header->clauses [cc];
12821                                         if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
12822                                                 ((ip - header->code) > clause->data.filter_offset && (ip - header->code) <= clause->handler_offset) &&
12823                                             (!nearest || (clause->data.filter_offset < nearest->data.filter_offset)))
12824                                                 nearest = clause;
12825                                 }
12826                                 g_assert (nearest);
12827                                 if ((ip - header->code) != nearest->handler_offset)
12828                                         UNVERIFIED;
12829
12830                                 break;
12831                         }
12832                         case CEE_UNALIGNED_:
12833                                 ins_flag |= MONO_INST_UNALIGNED;
12834                                 /* FIXME: record alignment? we can assume 1 for now */
12835                                 CHECK_OPSIZE (3);
12836                                 ip += 3;
12837                                 break;
12838                         case CEE_VOLATILE_:
12839                                 ins_flag |= MONO_INST_VOLATILE;
12840                                 ip += 2;
12841                                 break;
12842                         case CEE_TAIL_:
12843                                 ins_flag   |= MONO_INST_TAILCALL;
12844                                 cfg->flags |= MONO_CFG_HAS_TAIL;
12845                                 /* Can't inline tail calls at this time */
12846                                 inline_costs += 100000;
12847                                 ip += 2;
12848                                 break;
12849                         case CEE_INITOBJ:
12850                                 CHECK_STACK (1);
12851                                 --sp;
12852                                 CHECK_OPSIZE (6);
12853                                 token = read32 (ip + 2);
12854                                 klass = mini_get_class (method, token, generic_context);
12855                                 CHECK_TYPELOAD (klass);
12856                                 if (generic_class_is_reference_type (cfg, klass))
12857                                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, sp [0]->dreg, 0, 0);
12858                                 else
12859                                         mini_emit_initobj (cfg, *sp, NULL, klass);
12860                                 ip += 6;
12861                                 inline_costs += 1;
12862                                 break;
12863                         case CEE_CONSTRAINED_:
12864                                 CHECK_OPSIZE (6);
12865                                 token = read32 (ip + 2);
12866                                 constrained_class = mini_get_class (method, token, generic_context);
12867                                 CHECK_TYPELOAD (constrained_class);
12868                                 ip += 6;
12869                                 break;
12870                         case CEE_CPBLK:
12871                         case CEE_INITBLK: {
12872                                 MonoInst *iargs [3];
12873                                 CHECK_STACK (3);
12874                                 sp -= 3;
12875
12876                                 /* Skip optimized paths for volatile operations. */
12877                                 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)) {
12878                                         mini_emit_memcpy (cfg, sp [0]->dreg, 0, sp [1]->dreg, 0, sp [2]->inst_c0, 0);
12879                                 } 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)) {
12880                                         /* emit_memset only works when val == 0 */
12881                                         mini_emit_memset (cfg, sp [0]->dreg, 0, sp [2]->inst_c0, sp [1]->inst_c0, 0);
12882                                 } else {
12883                                         MonoInst *call;
12884                                         iargs [0] = sp [0];
12885                                         iargs [1] = sp [1];
12886                                         iargs [2] = sp [2];
12887                                         if (ip [1] == CEE_CPBLK) {
12888                                                 /*
12889                                                  * FIXME: It's unclear whether we should be emitting both the acquire
12890                                                  * and release barriers for cpblk. It is technically both a load and
12891                                                  * store operation, so it seems like that's the sensible thing to do.
12892                                                  *
12893                                                  * FIXME: We emit full barriers on both sides of the operation for
12894                                                  * simplicity. We should have a separate atomic memcpy method instead.
12895                                                  */
12896                                                 MonoMethod *memcpy_method = get_memcpy_method ();
12897
12898                                                 if (ins_flag & MONO_INST_VOLATILE)
12899                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
12900
12901                                                 call = mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
12902                                                 call->flags |= ins_flag;
12903
12904                                                 if (ins_flag & MONO_INST_VOLATILE)
12905                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
12906                                         } else {
12907                                                 MonoMethod *memset_method = get_memset_method ();
12908                                                 if (ins_flag & MONO_INST_VOLATILE) {
12909                                                         /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
12910                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
12911                                                 }
12912                                                 call = mono_emit_method_call (cfg, memset_method, iargs, NULL);
12913                                                 call->flags |= ins_flag;
12914                                         }
12915                                 }
12916                                 ip += 2;
12917                                 ins_flag = 0;
12918                                 inline_costs += 1;
12919                                 break;
12920                         }
12921                         case CEE_NO_:
12922                                 CHECK_OPSIZE (3);
12923                                 if (ip [2] & 0x1)
12924                                         ins_flag |= MONO_INST_NOTYPECHECK;
12925                                 if (ip [2] & 0x2)
12926                                         ins_flag |= MONO_INST_NORANGECHECK;
12927                                 /* we ignore the no-nullcheck for now since we
12928                                  * really do it explicitly only when doing callvirt->call
12929                                  */
12930                                 ip += 3;
12931                                 break;
12932                         case CEE_RETHROW: {
12933                                 MonoInst *load;
12934                                 int handler_offset = -1;
12935
12936                                 for (i = 0; i < header->num_clauses; ++i) {
12937                                         MonoExceptionClause *clause = &header->clauses [i];
12938                                         if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
12939                                                 handler_offset = clause->handler_offset;
12940                                                 break;
12941                                         }
12942                                 }
12943
12944                                 cfg->cbb->flags |= BB_EXCEPTION_UNSAFE;
12945
12946                                 if (handler_offset == -1)
12947                                         UNVERIFIED;
12948
12949                                 EMIT_NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
12950                                 MONO_INST_NEW (cfg, ins, OP_RETHROW);
12951                                 ins->sreg1 = load->dreg;
12952                                 MONO_ADD_INS (cfg->cbb, ins);
12953
12954                                 MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
12955                                 MONO_ADD_INS (cfg->cbb, ins);
12956
12957                                 sp = stack_start;
12958                                 link_bblock (cfg, cfg->cbb, end_bblock);
12959                                 start_new_bblock = 1;
12960                                 ip += 2;
12961                                 break;
12962                         }
12963                         case CEE_SIZEOF: {
12964                                 guint32 val;
12965                                 int ialign;
12966
12967                                 CHECK_STACK_OVF (1);
12968                                 CHECK_OPSIZE (6);
12969                                 token = read32 (ip + 2);
12970                                 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC && !image_is_dynamic (method->klass->image) && !generic_context) {
12971                                         MonoType *type = mono_type_create_from_typespec_checked (image, token, &cfg->error);
12972                                         CHECK_CFG_ERROR;
12973
12974                                         val = mono_type_size (type, &ialign);
12975                                 } else {
12976                                         MonoClass *klass = mini_get_class (method, token, generic_context);
12977                                         CHECK_TYPELOAD (klass);
12978
12979                                         val = mono_type_size (&klass->byval_arg, &ialign);
12980
12981                                         if (mini_is_gsharedvt_klass (klass))
12982                                                 GSHAREDVT_FAILURE (*ip);
12983                                 }
12984                                 EMIT_NEW_ICONST (cfg, ins, val);
12985                                 *sp++= ins;
12986                                 ip += 6;
12987                                 break;
12988                         }
12989                         case CEE_REFANYTYPE: {
12990                                 MonoInst *src_var, *src;
12991
12992                                 GSHAREDVT_FAILURE (*ip);
12993
12994                                 CHECK_STACK (1);
12995                                 --sp;
12996
12997                                 // FIXME:
12998                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
12999                                 if (!src_var)
13000                                         src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
13001                                 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
13002                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &mono_defaults.typehandle_class->byval_arg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type));
13003                                 *sp++ = ins;
13004                                 ip += 2;
13005                                 break;
13006                         }
13007                         case CEE_READONLY_:
13008                                 readonly = TRUE;
13009                                 ip += 2;
13010                                 break;
13011
13012                         case CEE_UNUSED56:
13013                         case CEE_UNUSED57:
13014                         case CEE_UNUSED70:
13015                         case CEE_UNUSED:
13016                         case CEE_UNUSED99:
13017                                 UNVERIFIED;
13018                                 
13019                         default:
13020                                 g_warning ("opcode 0xfe 0x%02x not handled", ip [1]);
13021                                 UNVERIFIED;
13022                         }
13023                         break;
13024                 }
13025                 case CEE_UNUSED58:
13026                 case CEE_UNUSED1:
13027                         UNVERIFIED;
13028
13029                 default:
13030                         g_warning ("opcode 0x%02x not handled", *ip);
13031                         UNVERIFIED;
13032                 }
13033         }
13034         if (start_new_bblock != 1)
13035                 UNVERIFIED;
13036
13037         cfg->cbb->cil_length = ip - cfg->cbb->cil_code;
13038         if (cfg->cbb->next_bb) {
13039                 /* This could already be set because of inlining, #693905 */
13040                 MonoBasicBlock *bb = cfg->cbb;
13041
13042                 while (bb->next_bb)
13043                         bb = bb->next_bb;
13044                 bb->next_bb = end_bblock;
13045         } else {
13046                 cfg->cbb->next_bb = end_bblock;
13047         }
13048
13049         if (cfg->method == method && cfg->domainvar) {
13050                 MonoInst *store;
13051                 MonoInst *get_domain;
13052
13053                 cfg->cbb = init_localsbb;
13054
13055                 if ((get_domain = mono_get_domain_intrinsic (cfg))) {
13056                         MONO_ADD_INS (cfg->cbb, get_domain);
13057                 } else {
13058                         get_domain = mono_emit_jit_icall (cfg, mono_domain_get, NULL);
13059                 }
13060                 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, get_domain);
13061                 MONO_ADD_INS (cfg->cbb, store);
13062         }
13063
13064 #if defined(TARGET_POWERPC) || defined(TARGET_X86)
13065         if (cfg->compile_aot)
13066                 /* FIXME: The plt slots require a GOT var even if the method doesn't use it */
13067                 mono_get_got_var (cfg);
13068 #endif
13069
13070         if (cfg->method == method && cfg->got_var)
13071                 mono_emit_load_got_addr (cfg);
13072
13073         if (init_localsbb) {
13074                 cfg->cbb = init_localsbb;
13075                 cfg->ip = NULL;
13076                 for (i = 0; i < header->num_locals; ++i) {
13077                         emit_init_local (cfg, i, header->locals [i], init_locals);
13078                 }
13079         }
13080
13081         if (cfg->init_ref_vars && cfg->method == method) {
13082                 /* Emit initialization for ref vars */
13083                 // FIXME: Avoid duplication initialization for IL locals.
13084                 for (i = 0; i < cfg->num_varinfo; ++i) {
13085                         MonoInst *ins = cfg->varinfo [i];
13086
13087                         if (ins->opcode == OP_LOCAL && ins->type == STACK_OBJ)
13088                                 MONO_EMIT_NEW_PCONST (cfg, ins->dreg, NULL);
13089                 }
13090         }
13091
13092         if (cfg->lmf_var && cfg->method == method && !(cfg->llvm_only && REALLY_LLVMONLY)) {
13093                 cfg->cbb = init_localsbb;
13094                 emit_push_lmf (cfg);
13095         }
13096
13097         cfg->cbb = init_localsbb;
13098         emit_instrumentation_call (cfg, mono_profiler_method_enter);
13099
13100         if (seq_points) {
13101                 MonoBasicBlock *bb;
13102
13103                 /*
13104                  * Make seq points at backward branch targets interruptable.
13105                  */
13106                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
13107                         if (bb->code && bb->in_count > 1 && bb->code->opcode == OP_SEQ_POINT)
13108                                 bb->code->flags |= MONO_INST_SINGLE_STEP_LOC;
13109         }
13110
13111         /* Add a sequence point for method entry/exit events */
13112         if (seq_points && cfg->gen_sdb_seq_points) {
13113                 NEW_SEQ_POINT (cfg, ins, METHOD_ENTRY_IL_OFFSET, FALSE);
13114                 MONO_ADD_INS (init_localsbb, ins);
13115                 NEW_SEQ_POINT (cfg, ins, METHOD_EXIT_IL_OFFSET, FALSE);
13116                 MONO_ADD_INS (cfg->bb_exit, ins);
13117         }
13118
13119         /*
13120          * Add seq points for IL offsets which have line number info, but wasn't generated a seq point during JITting because
13121          * the code they refer to was dead (#11880).
13122          */
13123         if (sym_seq_points) {
13124                 for (i = 0; i < header->code_size; ++i) {
13125                         if (mono_bitset_test_fast (seq_point_locs, i) && !mono_bitset_test_fast (seq_point_set_locs, i)) {
13126                                 MonoInst *ins;
13127
13128                                 NEW_SEQ_POINT (cfg, ins, i, FALSE);
13129                                 mono_add_seq_point (cfg, NULL, ins, SEQ_POINT_NATIVE_OFFSET_DEAD_CODE);
13130                         }
13131                 }
13132         }
13133
13134         cfg->ip = NULL;
13135
13136         if (cfg->method == method) {
13137                 MonoBasicBlock *bb;
13138                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13139                         bb->region = mono_find_block_region (cfg, bb->real_offset);
13140                         if (cfg->spvars)
13141                                 mono_create_spvar_for_region (cfg, bb->region);
13142                         if (cfg->verbose_level > 2)
13143                                 printf ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
13144                 }
13145         }
13146
13147         if (inline_costs < 0) {
13148                 char *mname;
13149
13150                 /* Method is too large */
13151                 mname = mono_method_full_name (method, TRUE);
13152                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
13153                 cfg->exception_message = g_strdup_printf ("Method %s is too complex.", mname);
13154                 g_free (mname);
13155         }
13156
13157         if ((cfg->verbose_level > 2) && (cfg->method == method)) 
13158                 mono_print_code (cfg, "AFTER METHOD-TO-IR");
13159
13160         goto cleanup;
13161
13162 mono_error_exit:
13163         g_assert (!mono_error_ok (&cfg->error));
13164         goto cleanup;
13165  
13166  exception_exit:
13167         g_assert (cfg->exception_type != MONO_EXCEPTION_NONE);
13168         goto cleanup;
13169
13170  unverified:
13171         set_exception_type_from_invalid_il (cfg, method, ip);
13172         goto cleanup;
13173
13174  cleanup:
13175         g_slist_free (class_inits);
13176         mono_basic_block_free (original_bb);
13177         cfg->dont_inline = g_list_remove (cfg->dont_inline, method);
13178         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
13179         if (cfg->exception_type)
13180                 return -1;
13181         else
13182                 return inline_costs;
13183 }
13184
13185 static int
13186 store_membase_reg_to_store_membase_imm (int opcode)
13187 {
13188         switch (opcode) {
13189         case OP_STORE_MEMBASE_REG:
13190                 return OP_STORE_MEMBASE_IMM;
13191         case OP_STOREI1_MEMBASE_REG:
13192                 return OP_STOREI1_MEMBASE_IMM;
13193         case OP_STOREI2_MEMBASE_REG:
13194                 return OP_STOREI2_MEMBASE_IMM;
13195         case OP_STOREI4_MEMBASE_REG:
13196                 return OP_STOREI4_MEMBASE_IMM;
13197         case OP_STOREI8_MEMBASE_REG:
13198                 return OP_STOREI8_MEMBASE_IMM;
13199         default:
13200                 g_assert_not_reached ();
13201         }
13202
13203         return -1;
13204 }               
13205
13206 int
13207 mono_op_to_op_imm (int opcode)
13208 {
13209         switch (opcode) {
13210         case OP_IADD:
13211                 return OP_IADD_IMM;
13212         case OP_ISUB:
13213                 return OP_ISUB_IMM;
13214         case OP_IDIV:
13215                 return OP_IDIV_IMM;
13216         case OP_IDIV_UN:
13217                 return OP_IDIV_UN_IMM;
13218         case OP_IREM:
13219                 return OP_IREM_IMM;
13220         case OP_IREM_UN:
13221                 return OP_IREM_UN_IMM;
13222         case OP_IMUL:
13223                 return OP_IMUL_IMM;
13224         case OP_IAND:
13225                 return OP_IAND_IMM;
13226         case OP_IOR:
13227                 return OP_IOR_IMM;
13228         case OP_IXOR:
13229                 return OP_IXOR_IMM;
13230         case OP_ISHL:
13231                 return OP_ISHL_IMM;
13232         case OP_ISHR:
13233                 return OP_ISHR_IMM;
13234         case OP_ISHR_UN:
13235                 return OP_ISHR_UN_IMM;
13236
13237         case OP_LADD:
13238                 return OP_LADD_IMM;
13239         case OP_LSUB:
13240                 return OP_LSUB_IMM;
13241         case OP_LAND:
13242                 return OP_LAND_IMM;
13243         case OP_LOR:
13244                 return OP_LOR_IMM;
13245         case OP_LXOR:
13246                 return OP_LXOR_IMM;
13247         case OP_LSHL:
13248                 return OP_LSHL_IMM;
13249         case OP_LSHR:
13250                 return OP_LSHR_IMM;
13251         case OP_LSHR_UN:
13252                 return OP_LSHR_UN_IMM;
13253 #if SIZEOF_REGISTER == 8
13254         case OP_LREM:
13255                 return OP_LREM_IMM;
13256 #endif
13257
13258         case OP_COMPARE:
13259                 return OP_COMPARE_IMM;
13260         case OP_ICOMPARE:
13261                 return OP_ICOMPARE_IMM;
13262         case OP_LCOMPARE:
13263                 return OP_LCOMPARE_IMM;
13264
13265         case OP_STORE_MEMBASE_REG:
13266                 return OP_STORE_MEMBASE_IMM;
13267         case OP_STOREI1_MEMBASE_REG:
13268                 return OP_STOREI1_MEMBASE_IMM;
13269         case OP_STOREI2_MEMBASE_REG:
13270                 return OP_STOREI2_MEMBASE_IMM;
13271         case OP_STOREI4_MEMBASE_REG:
13272                 return OP_STOREI4_MEMBASE_IMM;
13273
13274 #if defined(TARGET_X86) || defined (TARGET_AMD64)
13275         case OP_X86_PUSH:
13276                 return OP_X86_PUSH_IMM;
13277         case OP_X86_COMPARE_MEMBASE_REG:
13278                 return OP_X86_COMPARE_MEMBASE_IMM;
13279 #endif
13280 #if defined(TARGET_AMD64)
13281         case OP_AMD64_ICOMPARE_MEMBASE_REG:
13282                 return OP_AMD64_ICOMPARE_MEMBASE_IMM;
13283 #endif
13284         case OP_VOIDCALL_REG:
13285                 return OP_VOIDCALL;
13286         case OP_CALL_REG:
13287                 return OP_CALL;
13288         case OP_LCALL_REG:
13289                 return OP_LCALL;
13290         case OP_FCALL_REG:
13291                 return OP_FCALL;
13292         case OP_LOCALLOC:
13293                 return OP_LOCALLOC_IMM;
13294         }
13295
13296         return -1;
13297 }
13298
13299 static int
13300 ldind_to_load_membase (int opcode)
13301 {
13302         switch (opcode) {
13303         case CEE_LDIND_I1:
13304                 return OP_LOADI1_MEMBASE;
13305         case CEE_LDIND_U1:
13306                 return OP_LOADU1_MEMBASE;
13307         case CEE_LDIND_I2:
13308                 return OP_LOADI2_MEMBASE;
13309         case CEE_LDIND_U2:
13310                 return OP_LOADU2_MEMBASE;
13311         case CEE_LDIND_I4:
13312                 return OP_LOADI4_MEMBASE;
13313         case CEE_LDIND_U4:
13314                 return OP_LOADU4_MEMBASE;
13315         case CEE_LDIND_I:
13316                 return OP_LOAD_MEMBASE;
13317         case CEE_LDIND_REF:
13318                 return OP_LOAD_MEMBASE;
13319         case CEE_LDIND_I8:
13320                 return OP_LOADI8_MEMBASE;
13321         case CEE_LDIND_R4:
13322                 return OP_LOADR4_MEMBASE;
13323         case CEE_LDIND_R8:
13324                 return OP_LOADR8_MEMBASE;
13325         default:
13326                 g_assert_not_reached ();
13327         }
13328
13329         return -1;
13330 }
13331
13332 static int
13333 stind_to_store_membase (int opcode)
13334 {
13335         switch (opcode) {
13336         case CEE_STIND_I1:
13337                 return OP_STOREI1_MEMBASE_REG;
13338         case CEE_STIND_I2:
13339                 return OP_STOREI2_MEMBASE_REG;
13340         case CEE_STIND_I4:
13341                 return OP_STOREI4_MEMBASE_REG;
13342         case CEE_STIND_I:
13343         case CEE_STIND_REF:
13344                 return OP_STORE_MEMBASE_REG;
13345         case CEE_STIND_I8:
13346                 return OP_STOREI8_MEMBASE_REG;
13347         case CEE_STIND_R4:
13348                 return OP_STORER4_MEMBASE_REG;
13349         case CEE_STIND_R8:
13350                 return OP_STORER8_MEMBASE_REG;
13351         default:
13352                 g_assert_not_reached ();
13353         }
13354
13355         return -1;
13356 }
13357
13358 int
13359 mono_load_membase_to_load_mem (int opcode)
13360 {
13361         // FIXME: Add a MONO_ARCH_HAVE_LOAD_MEM macro
13362 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13363         switch (opcode) {
13364         case OP_LOAD_MEMBASE:
13365                 return OP_LOAD_MEM;
13366         case OP_LOADU1_MEMBASE:
13367                 return OP_LOADU1_MEM;
13368         case OP_LOADU2_MEMBASE:
13369                 return OP_LOADU2_MEM;
13370         case OP_LOADI4_MEMBASE:
13371                 return OP_LOADI4_MEM;
13372         case OP_LOADU4_MEMBASE:
13373                 return OP_LOADU4_MEM;
13374 #if SIZEOF_REGISTER == 8
13375         case OP_LOADI8_MEMBASE:
13376                 return OP_LOADI8_MEM;
13377 #endif
13378         }
13379 #endif
13380
13381         return -1;
13382 }
13383
13384 static inline int
13385 op_to_op_dest_membase (int store_opcode, int opcode)
13386 {
13387 #if defined(TARGET_X86)
13388         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG)))
13389                 return -1;
13390
13391         switch (opcode) {
13392         case OP_IADD:
13393                 return OP_X86_ADD_MEMBASE_REG;
13394         case OP_ISUB:
13395                 return OP_X86_SUB_MEMBASE_REG;
13396         case OP_IAND:
13397                 return OP_X86_AND_MEMBASE_REG;
13398         case OP_IOR:
13399                 return OP_X86_OR_MEMBASE_REG;
13400         case OP_IXOR:
13401                 return OP_X86_XOR_MEMBASE_REG;
13402         case OP_ADD_IMM:
13403         case OP_IADD_IMM:
13404                 return OP_X86_ADD_MEMBASE_IMM;
13405         case OP_SUB_IMM:
13406         case OP_ISUB_IMM:
13407                 return OP_X86_SUB_MEMBASE_IMM;
13408         case OP_AND_IMM:
13409         case OP_IAND_IMM:
13410                 return OP_X86_AND_MEMBASE_IMM;
13411         case OP_OR_IMM:
13412         case OP_IOR_IMM:
13413                 return OP_X86_OR_MEMBASE_IMM;
13414         case OP_XOR_IMM:
13415         case OP_IXOR_IMM:
13416                 return OP_X86_XOR_MEMBASE_IMM;
13417         case OP_MOVE:
13418                 return OP_NOP;
13419         }
13420 #endif
13421
13422 #if defined(TARGET_AMD64)
13423         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG) || (store_opcode == OP_STOREI8_MEMBASE_REG)))
13424                 return -1;
13425
13426         switch (opcode) {
13427         case OP_IADD:
13428                 return OP_X86_ADD_MEMBASE_REG;
13429         case OP_ISUB:
13430                 return OP_X86_SUB_MEMBASE_REG;
13431         case OP_IAND:
13432                 return OP_X86_AND_MEMBASE_REG;
13433         case OP_IOR:
13434                 return OP_X86_OR_MEMBASE_REG;
13435         case OP_IXOR:
13436                 return OP_X86_XOR_MEMBASE_REG;
13437         case OP_IADD_IMM:
13438                 return OP_X86_ADD_MEMBASE_IMM;
13439         case OP_ISUB_IMM:
13440                 return OP_X86_SUB_MEMBASE_IMM;
13441         case OP_IAND_IMM:
13442                 return OP_X86_AND_MEMBASE_IMM;
13443         case OP_IOR_IMM:
13444                 return OP_X86_OR_MEMBASE_IMM;
13445         case OP_IXOR_IMM:
13446                 return OP_X86_XOR_MEMBASE_IMM;
13447         case OP_LADD:
13448                 return OP_AMD64_ADD_MEMBASE_REG;
13449         case OP_LSUB:
13450                 return OP_AMD64_SUB_MEMBASE_REG;
13451         case OP_LAND:
13452                 return OP_AMD64_AND_MEMBASE_REG;
13453         case OP_LOR:
13454                 return OP_AMD64_OR_MEMBASE_REG;
13455         case OP_LXOR:
13456                 return OP_AMD64_XOR_MEMBASE_REG;
13457         case OP_ADD_IMM:
13458         case OP_LADD_IMM:
13459                 return OP_AMD64_ADD_MEMBASE_IMM;
13460         case OP_SUB_IMM:
13461         case OP_LSUB_IMM:
13462                 return OP_AMD64_SUB_MEMBASE_IMM;
13463         case OP_AND_IMM:
13464         case OP_LAND_IMM:
13465                 return OP_AMD64_AND_MEMBASE_IMM;
13466         case OP_OR_IMM:
13467         case OP_LOR_IMM:
13468                 return OP_AMD64_OR_MEMBASE_IMM;
13469         case OP_XOR_IMM:
13470         case OP_LXOR_IMM:
13471                 return OP_AMD64_XOR_MEMBASE_IMM;
13472         case OP_MOVE:
13473                 return OP_NOP;
13474         }
13475 #endif
13476
13477         return -1;
13478 }
13479
13480 static inline int
13481 op_to_op_store_membase (int store_opcode, int opcode)
13482 {
13483 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13484         switch (opcode) {
13485         case OP_ICEQ:
13486                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13487                         return OP_X86_SETEQ_MEMBASE;
13488         case OP_CNE:
13489                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13490                         return OP_X86_SETNE_MEMBASE;
13491         }
13492 #endif
13493
13494         return -1;
13495 }
13496
13497 static inline int
13498 op_to_op_src1_membase (int load_opcode, int opcode)
13499 {
13500 #ifdef TARGET_X86
13501         /* FIXME: This has sign extension issues */
13502         /*
13503         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
13504                 return OP_X86_COMPARE_MEMBASE8_IMM;
13505         */
13506
13507         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
13508                 return -1;
13509
13510         switch (opcode) {
13511         case OP_X86_PUSH:
13512                 return OP_X86_PUSH_MEMBASE;
13513         case OP_COMPARE_IMM:
13514         case OP_ICOMPARE_IMM:
13515                 return OP_X86_COMPARE_MEMBASE_IMM;
13516         case OP_COMPARE:
13517         case OP_ICOMPARE:
13518                 return OP_X86_COMPARE_MEMBASE_REG;
13519         }
13520 #endif
13521
13522 #ifdef TARGET_AMD64
13523         /* FIXME: This has sign extension issues */
13524         /*
13525         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
13526                 return OP_X86_COMPARE_MEMBASE8_IMM;
13527         */
13528
13529         switch (opcode) {
13530         case OP_X86_PUSH:
13531 #ifdef __mono_ilp32__
13532                 if (load_opcode == OP_LOADI8_MEMBASE)
13533 #else
13534                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
13535 #endif
13536                         return OP_X86_PUSH_MEMBASE;
13537                 break;
13538                 /* FIXME: This only works for 32 bit immediates
13539         case OP_COMPARE_IMM:
13540         case OP_LCOMPARE_IMM:
13541                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
13542                         return OP_AMD64_COMPARE_MEMBASE_IMM;
13543                 */
13544         case OP_ICOMPARE_IMM:
13545                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
13546                         return OP_AMD64_ICOMPARE_MEMBASE_IMM;
13547                 break;
13548         case OP_COMPARE:
13549         case OP_LCOMPARE:
13550 #ifdef __mono_ilp32__
13551                 if (load_opcode == OP_LOAD_MEMBASE)
13552                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
13553                 if (load_opcode == OP_LOADI8_MEMBASE)
13554 #else
13555                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
13556 #endif
13557                         return OP_AMD64_COMPARE_MEMBASE_REG;
13558                 break;
13559         case OP_ICOMPARE:
13560                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
13561                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
13562                 break;
13563         }
13564 #endif
13565
13566         return -1;
13567 }
13568
13569 static inline int
13570 op_to_op_src2_membase (int load_opcode, int opcode)
13571 {
13572 #ifdef TARGET_X86
13573         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
13574                 return -1;
13575         
13576         switch (opcode) {
13577         case OP_COMPARE:
13578         case OP_ICOMPARE:
13579                 return OP_X86_COMPARE_REG_MEMBASE;
13580         case OP_IADD:
13581                 return OP_X86_ADD_REG_MEMBASE;
13582         case OP_ISUB:
13583                 return OP_X86_SUB_REG_MEMBASE;
13584         case OP_IAND:
13585                 return OP_X86_AND_REG_MEMBASE;
13586         case OP_IOR:
13587                 return OP_X86_OR_REG_MEMBASE;
13588         case OP_IXOR:
13589                 return OP_X86_XOR_REG_MEMBASE;
13590         }
13591 #endif
13592
13593 #ifdef TARGET_AMD64
13594 #ifdef __mono_ilp32__
13595         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE) ) {
13596 #else
13597         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)) {
13598 #endif
13599                 switch (opcode) {
13600                 case OP_ICOMPARE:
13601                         return OP_AMD64_ICOMPARE_REG_MEMBASE;
13602                 case OP_IADD:
13603                         return OP_X86_ADD_REG_MEMBASE;
13604                 case OP_ISUB:
13605                         return OP_X86_SUB_REG_MEMBASE;
13606                 case OP_IAND:
13607                         return OP_X86_AND_REG_MEMBASE;
13608                 case OP_IOR:
13609                         return OP_X86_OR_REG_MEMBASE;
13610                 case OP_IXOR:
13611                         return OP_X86_XOR_REG_MEMBASE;
13612                 }
13613 #ifdef __mono_ilp32__
13614         } else if (load_opcode == OP_LOADI8_MEMBASE) {
13615 #else
13616         } else if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE)) {
13617 #endif
13618                 switch (opcode) {
13619                 case OP_COMPARE:
13620                 case OP_LCOMPARE:
13621                         return OP_AMD64_COMPARE_REG_MEMBASE;
13622                 case OP_LADD:
13623                         return OP_AMD64_ADD_REG_MEMBASE;
13624                 case OP_LSUB:
13625                         return OP_AMD64_SUB_REG_MEMBASE;
13626                 case OP_LAND:
13627                         return OP_AMD64_AND_REG_MEMBASE;
13628                 case OP_LOR:
13629                         return OP_AMD64_OR_REG_MEMBASE;
13630                 case OP_LXOR:
13631                         return OP_AMD64_XOR_REG_MEMBASE;
13632                 }
13633         }
13634 #endif
13635
13636         return -1;
13637 }
13638
13639 int
13640 mono_op_to_op_imm_noemul (int opcode)
13641 {
13642         switch (opcode) {
13643 #if SIZEOF_REGISTER == 4 && !defined(MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS)
13644         case OP_LSHR:
13645         case OP_LSHL:
13646         case OP_LSHR_UN:
13647                 return -1;
13648 #endif
13649 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
13650         case OP_IDIV:
13651         case OP_IDIV_UN:
13652         case OP_IREM:
13653         case OP_IREM_UN:
13654                 return -1;
13655 #endif
13656 #if defined(MONO_ARCH_EMULATE_MUL_DIV)
13657         case OP_IMUL:
13658                 return -1;
13659 #endif
13660         default:
13661                 return mono_op_to_op_imm (opcode);
13662         }
13663 }
13664
13665 /**
13666  * mono_handle_global_vregs:
13667  *
13668  *   Make vregs used in more than one bblock 'global', i.e. allocate a variable
13669  * for them.
13670  */
13671 void
13672 mono_handle_global_vregs (MonoCompile *cfg)
13673 {
13674         gint32 *vreg_to_bb;
13675         MonoBasicBlock *bb;
13676         int i, pos;
13677
13678         vreg_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (gint32*) * cfg->next_vreg + 1);
13679
13680 #ifdef MONO_ARCH_SIMD_INTRINSICS
13681         if (cfg->uses_simd_intrinsics)
13682                 mono_simd_simplify_indirection (cfg);
13683 #endif
13684
13685         /* Find local vregs used in more than one bb */
13686         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13687                 MonoInst *ins = bb->code;       
13688                 int block_num = bb->block_num;
13689
13690                 if (cfg->verbose_level > 2)
13691                         printf ("\nHANDLE-GLOBAL-VREGS BLOCK %d:\n", bb->block_num);
13692
13693                 cfg->cbb = bb;
13694                 for (; ins; ins = ins->next) {
13695                         const char *spec = INS_INFO (ins->opcode);
13696                         int regtype = 0, regindex;
13697                         gint32 prev_bb;
13698
13699                         if (G_UNLIKELY (cfg->verbose_level > 2))
13700                                 mono_print_ins (ins);
13701
13702                         g_assert (ins->opcode >= MONO_CEE_LAST);
13703
13704                         for (regindex = 0; regindex < 4; regindex ++) {
13705                                 int vreg = 0;
13706
13707                                 if (regindex == 0) {
13708                                         regtype = spec [MONO_INST_DEST];
13709                                         if (regtype == ' ')
13710                                                 continue;
13711                                         vreg = ins->dreg;
13712                                 } else if (regindex == 1) {
13713                                         regtype = spec [MONO_INST_SRC1];
13714                                         if (regtype == ' ')
13715                                                 continue;
13716                                         vreg = ins->sreg1;
13717                                 } else if (regindex == 2) {
13718                                         regtype = spec [MONO_INST_SRC2];
13719                                         if (regtype == ' ')
13720                                                 continue;
13721                                         vreg = ins->sreg2;
13722                                 } else if (regindex == 3) {
13723                                         regtype = spec [MONO_INST_SRC3];
13724                                         if (regtype == ' ')
13725                                                 continue;
13726                                         vreg = ins->sreg3;
13727                                 }
13728
13729 #if SIZEOF_REGISTER == 4
13730                                 /* In the LLVM case, the long opcodes are not decomposed */
13731                                 if (regtype == 'l' && !COMPILE_LLVM (cfg)) {
13732                                         /*
13733                                          * Since some instructions reference the original long vreg,
13734                                          * and some reference the two component vregs, it is quite hard
13735                                          * to determine when it needs to be global. So be conservative.
13736                                          */
13737                                         if (!get_vreg_to_inst (cfg, vreg)) {
13738                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
13739
13740                                                 if (cfg->verbose_level > 2)
13741                                                         printf ("LONG VREG R%d made global.\n", vreg);
13742                                         }
13743
13744                                         /*
13745                                          * Make the component vregs volatile since the optimizations can
13746                                          * get confused otherwise.
13747                                          */
13748                                         get_vreg_to_inst (cfg, vreg + 1)->flags |= MONO_INST_VOLATILE;
13749                                         get_vreg_to_inst (cfg, vreg + 2)->flags |= MONO_INST_VOLATILE;
13750                                 }
13751 #endif
13752
13753                                 g_assert (vreg != -1);
13754
13755                                 prev_bb = vreg_to_bb [vreg];
13756                                 if (prev_bb == 0) {
13757                                         /* 0 is a valid block num */
13758                                         vreg_to_bb [vreg] = block_num + 1;
13759                                 } else if ((prev_bb != block_num + 1) && (prev_bb != -1)) {
13760                                         if (((regtype == 'i' && (vreg < MONO_MAX_IREGS))) || (regtype == 'f' && (vreg < MONO_MAX_FREGS)))
13761                                                 continue;
13762
13763                                         if (!get_vreg_to_inst (cfg, vreg)) {
13764                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
13765                                                         printf ("VREG R%d used in BB%d and BB%d made global.\n", vreg, vreg_to_bb [vreg], block_num);
13766
13767                                                 switch (regtype) {
13768                                                 case 'i':
13769                                                         if (vreg_is_ref (cfg, vreg))
13770                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL, vreg);
13771                                                         else
13772                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL, vreg);
13773                                                         break;
13774                                                 case 'l':
13775                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
13776                                                         break;
13777                                                 case 'f':
13778                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL, vreg);
13779                                                         break;
13780                                                 case 'v':
13781                                                         mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, vreg);
13782                                                         break;
13783                                                 default:
13784                                                         g_assert_not_reached ();
13785                                                 }
13786                                         }
13787
13788                                         /* Flag as having been used in more than one bb */
13789                                         vreg_to_bb [vreg] = -1;
13790                                 }
13791                         }
13792                 }
13793         }
13794
13795         /* If a variable is used in only one bblock, convert it into a local vreg */
13796         for (i = 0; i < cfg->num_varinfo; i++) {
13797                 MonoInst *var = cfg->varinfo [i];
13798                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
13799
13800                 switch (var->type) {
13801                 case STACK_I4:
13802                 case STACK_OBJ:
13803                 case STACK_PTR:
13804                 case STACK_MP:
13805                 case STACK_VTYPE:
13806 #if SIZEOF_REGISTER == 8
13807                 case STACK_I8:
13808 #endif
13809 #if !defined(TARGET_X86)
13810                 /* Enabling this screws up the fp stack on x86 */
13811                 case STACK_R8:
13812 #endif
13813                         if (mono_arch_is_soft_float ())
13814                                 break;
13815
13816                         /* Arguments are implicitly global */
13817                         /* Putting R4 vars into registers doesn't work currently */
13818                         /* The gsharedvt vars are implicitly referenced by ldaddr opcodes, but those opcodes are only generated later */
13819                         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) {
13820                                 /* 
13821                                  * Make that the variable's liveness interval doesn't contain a call, since
13822                                  * that would cause the lvreg to be spilled, making the whole optimization
13823                                  * useless.
13824                                  */
13825                                 /* This is too slow for JIT compilation */
13826 #if 0
13827                                 if (cfg->compile_aot && vreg_to_bb [var->dreg]) {
13828                                         MonoInst *ins;
13829                                         int def_index, call_index, ins_index;
13830                                         gboolean spilled = FALSE;
13831
13832                                         def_index = -1;
13833                                         call_index = -1;
13834                                         ins_index = 0;
13835                                         for (ins = vreg_to_bb [var->dreg]->code; ins; ins = ins->next) {
13836                                                 const char *spec = INS_INFO (ins->opcode);
13837
13838                                                 if ((spec [MONO_INST_DEST] != ' ') && (ins->dreg == var->dreg))
13839                                                         def_index = ins_index;
13840
13841                                                 if (((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg)) ||
13842                                                         ((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg))) {
13843                                                         if (call_index > def_index) {
13844                                                                 spilled = TRUE;
13845                                                                 break;
13846                                                         }
13847                                                 }
13848
13849                                                 if (MONO_IS_CALL (ins))
13850                                                         call_index = ins_index;
13851
13852                                                 ins_index ++;
13853                                         }
13854
13855                                         if (spilled)
13856                                                 break;
13857                                 }
13858 #endif
13859
13860                                 if (G_UNLIKELY (cfg->verbose_level > 2))
13861                                         printf ("CONVERTED R%d(%d) TO VREG.\n", var->dreg, vmv->idx);
13862                                 var->flags |= MONO_INST_IS_DEAD;
13863                                 cfg->vreg_to_inst [var->dreg] = NULL;
13864                         }
13865                         break;
13866                 }
13867         }
13868
13869         /* 
13870          * Compress the varinfo and vars tables so the liveness computation is faster and
13871          * takes up less space.
13872          */
13873         pos = 0;
13874         for (i = 0; i < cfg->num_varinfo; ++i) {
13875                 MonoInst *var = cfg->varinfo [i];
13876                 if (pos < i && cfg->locals_start == i)
13877                         cfg->locals_start = pos;
13878                 if (!(var->flags & MONO_INST_IS_DEAD)) {
13879                         if (pos < i) {
13880                                 cfg->varinfo [pos] = cfg->varinfo [i];
13881                                 cfg->varinfo [pos]->inst_c0 = pos;
13882                                 memcpy (&cfg->vars [pos], &cfg->vars [i], sizeof (MonoMethodVar));
13883                                 cfg->vars [pos].idx = pos;
13884 #if SIZEOF_REGISTER == 4
13885                                 if (cfg->varinfo [pos]->type == STACK_I8) {
13886                                         /* Modify the two component vars too */
13887                                         MonoInst *var1;
13888
13889                                         var1 = get_vreg_to_inst (cfg, cfg->varinfo [pos]->dreg + 1);
13890                                         var1->inst_c0 = pos;
13891                                         var1 = get_vreg_to_inst (cfg, cfg->varinfo [pos]->dreg + 2);
13892                                         var1->inst_c0 = pos;
13893                                 }
13894 #endif
13895                         }
13896                         pos ++;
13897                 }
13898         }
13899         cfg->num_varinfo = pos;
13900         if (cfg->locals_start > cfg->num_varinfo)
13901                 cfg->locals_start = cfg->num_varinfo;
13902 }
13903
13904 /**
13905  * mono_spill_global_vars:
13906  *
13907  *   Generate spill code for variables which are not allocated to registers, 
13908  * and replace vregs with their allocated hregs. *need_local_opts is set to TRUE if
13909  * code is generated which could be optimized by the local optimization passes.
13910  */
13911 void
13912 mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
13913 {
13914         MonoBasicBlock *bb;
13915         char spec2 [16];
13916         int orig_next_vreg;
13917         guint32 *vreg_to_lvreg;
13918         guint32 *lvregs;
13919         guint32 i, lvregs_len;
13920         gboolean dest_has_lvreg = FALSE;
13921         guint32 stacktypes [128];
13922         MonoInst **live_range_start, **live_range_end;
13923         MonoBasicBlock **live_range_start_bb, **live_range_end_bb;
13924         int *gsharedvt_vreg_to_idx = NULL;
13925
13926         *need_local_opts = FALSE;
13927
13928         memset (spec2, 0, sizeof (spec2));
13929
13930         /* FIXME: Move this function to mini.c */
13931         stacktypes ['i'] = STACK_PTR;
13932         stacktypes ['l'] = STACK_I8;
13933         stacktypes ['f'] = STACK_R8;
13934 #ifdef MONO_ARCH_SIMD_INTRINSICS
13935         stacktypes ['x'] = STACK_VTYPE;
13936 #endif
13937
13938 #if SIZEOF_REGISTER == 4
13939         /* Create MonoInsts for longs */
13940         for (i = 0; i < cfg->num_varinfo; i++) {
13941                 MonoInst *ins = cfg->varinfo [i];
13942
13943                 if ((ins->opcode != OP_REGVAR) && !(ins->flags & MONO_INST_IS_DEAD)) {
13944                         switch (ins->type) {
13945                         case STACK_R8:
13946                         case STACK_I8: {
13947                                 MonoInst *tree;
13948
13949                                 if (ins->type == STACK_R8 && !COMPILE_SOFT_FLOAT (cfg))
13950                                         break;
13951
13952                                 g_assert (ins->opcode == OP_REGOFFSET);
13953
13954                                 tree = get_vreg_to_inst (cfg, ins->dreg + 1);
13955                                 g_assert (tree);
13956                                 tree->opcode = OP_REGOFFSET;
13957                                 tree->inst_basereg = ins->inst_basereg;
13958                                 tree->inst_offset = ins->inst_offset + MINI_LS_WORD_OFFSET;
13959
13960                                 tree = get_vreg_to_inst (cfg, ins->dreg + 2);
13961                                 g_assert (tree);
13962                                 tree->opcode = OP_REGOFFSET;
13963                                 tree->inst_basereg = ins->inst_basereg;
13964                                 tree->inst_offset = ins->inst_offset + MINI_MS_WORD_OFFSET;
13965                                 break;
13966                         }
13967                         default:
13968                                 break;
13969                         }
13970                 }
13971         }
13972 #endif
13973
13974         if (cfg->compute_gc_maps) {
13975                 /* registers need liveness info even for !non refs */
13976                 for (i = 0; i < cfg->num_varinfo; i++) {
13977                         MonoInst *ins = cfg->varinfo [i];
13978
13979                         if (ins->opcode == OP_REGVAR)
13980                                 ins->flags |= MONO_INST_GC_TRACK;
13981                 }
13982         }
13983
13984         if (cfg->gsharedvt) {
13985                 gsharedvt_vreg_to_idx = mono_mempool_alloc0 (cfg->mempool, sizeof (int) * cfg->next_vreg);
13986
13987                 for (i = 0; i < cfg->num_varinfo; ++i) {
13988                         MonoInst *ins = cfg->varinfo [i];
13989                         int idx;
13990
13991                         if (mini_is_gsharedvt_variable_type (ins->inst_vtype)) {
13992                                 if (i >= cfg->locals_start) {
13993                                         /* Local */
13994                                         idx = get_gsharedvt_info_slot (cfg, ins->inst_vtype, MONO_RGCTX_INFO_LOCAL_OFFSET);
13995                                         gsharedvt_vreg_to_idx [ins->dreg] = idx + 1;
13996                                         ins->opcode = OP_GSHAREDVT_LOCAL;
13997                                         ins->inst_imm = idx;
13998                                 } else {
13999                                         /* Arg */
14000                                         gsharedvt_vreg_to_idx [ins->dreg] = -1;
14001                                         ins->opcode = OP_GSHAREDVT_ARG_REGOFFSET;
14002                                 }
14003                         }
14004                 }
14005         }
14006                 
14007         /* FIXME: widening and truncation */
14008
14009         /*
14010          * As an optimization, when a variable allocated to the stack is first loaded into 
14011          * an lvreg, we will remember the lvreg and use it the next time instead of loading
14012          * the variable again.
14013          */
14014         orig_next_vreg = cfg->next_vreg;
14015         vreg_to_lvreg = mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * cfg->next_vreg);
14016         lvregs = mono_mempool_alloc (cfg->mempool, sizeof (guint32) * 1024);
14017         lvregs_len = 0;
14018
14019         /* 
14020          * These arrays contain the first and last instructions accessing a given
14021          * variable.
14022          * Since we emit bblocks in the same order we process them here, and we
14023          * don't split live ranges, these will precisely describe the live range of
14024          * the variable, i.e. the instruction range where a valid value can be found
14025          * in the variables location.
14026          * The live range is computed using the liveness info computed by the liveness pass.
14027          * We can't use vmv->range, since that is an abstract live range, and we need
14028          * one which is instruction precise.
14029          * FIXME: Variables used in out-of-line bblocks have a hole in their live range.
14030          */
14031         /* FIXME: Only do this if debugging info is requested */
14032         live_range_start = g_new0 (MonoInst*, cfg->next_vreg);
14033         live_range_end = g_new0 (MonoInst*, cfg->next_vreg);
14034         live_range_start_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
14035         live_range_end_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
14036         
14037         /* Add spill loads/stores */
14038         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
14039                 MonoInst *ins;
14040
14041                 if (cfg->verbose_level > 2)
14042                         printf ("\nSPILL BLOCK %d:\n", bb->block_num);
14043
14044                 /* Clear vreg_to_lvreg array */
14045                 for (i = 0; i < lvregs_len; i++)
14046                         vreg_to_lvreg [lvregs [i]] = 0;
14047                 lvregs_len = 0;
14048
14049                 cfg->cbb = bb;
14050                 MONO_BB_FOR_EACH_INS (bb, ins) {
14051                         const char *spec = INS_INFO (ins->opcode);
14052                         int regtype, srcindex, sreg, tmp_reg, prev_dreg, num_sregs;
14053                         gboolean store, no_lvreg;
14054                         int sregs [MONO_MAX_SRC_REGS];
14055
14056                         if (G_UNLIKELY (cfg->verbose_level > 2))
14057                                 mono_print_ins (ins);
14058
14059                         if (ins->opcode == OP_NOP)
14060                                 continue;
14061
14062                         /* 
14063                          * We handle LDADDR here as well, since it can only be decomposed
14064                          * when variable addresses are known.
14065                          */
14066                         if (ins->opcode == OP_LDADDR) {
14067                                 MonoInst *var = ins->inst_p0;
14068
14069                                 if (var->opcode == OP_VTARG_ADDR) {
14070                                         /* Happens on SPARC/S390 where vtypes are passed by reference */
14071                                         MonoInst *vtaddr = var->inst_left;
14072                                         if (vtaddr->opcode == OP_REGVAR) {
14073                                                 ins->opcode = OP_MOVE;
14074                                                 ins->sreg1 = vtaddr->dreg;
14075                                         }
14076                                         else if (var->inst_left->opcode == OP_REGOFFSET) {
14077                                                 ins->opcode = OP_LOAD_MEMBASE;
14078                                                 ins->inst_basereg = vtaddr->inst_basereg;
14079                                                 ins->inst_offset = vtaddr->inst_offset;
14080                                         } else
14081                                                 NOT_IMPLEMENTED;
14082                                 } else if (cfg->gsharedvt && gsharedvt_vreg_to_idx [var->dreg] < 0) {
14083                                         /* gsharedvt arg passed by ref */
14084                                         g_assert (var->opcode == OP_GSHAREDVT_ARG_REGOFFSET);
14085
14086                                         ins->opcode = OP_LOAD_MEMBASE;
14087                                         ins->inst_basereg = var->inst_basereg;
14088                                         ins->inst_offset = var->inst_offset;
14089                                 } else if (cfg->gsharedvt && gsharedvt_vreg_to_idx [var->dreg]) {
14090                                         MonoInst *load, *load2, *load3;
14091                                         int idx = gsharedvt_vreg_to_idx [var->dreg] - 1;
14092                                         int reg1, reg2, reg3;
14093                                         MonoInst *info_var = cfg->gsharedvt_info_var;
14094                                         MonoInst *locals_var = cfg->gsharedvt_locals_var;
14095
14096                                         /*
14097                                          * gsharedvt local.
14098                                          * Compute the address of the local as gsharedvt_locals_var + gsharedvt_info_var->locals_offsets [idx].
14099                                          */
14100
14101                                         g_assert (var->opcode == OP_GSHAREDVT_LOCAL);
14102
14103                                         g_assert (info_var);
14104                                         g_assert (locals_var);
14105
14106                                         /* Mark the instruction used to compute the locals var as used */
14107                                         cfg->gsharedvt_locals_var_ins = NULL;
14108
14109                                         /* Load the offset */
14110                                         if (info_var->opcode == OP_REGOFFSET) {
14111                                                 reg1 = alloc_ireg (cfg);
14112                                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, reg1, info_var->inst_basereg, info_var->inst_offset);
14113                                         } else if (info_var->opcode == OP_REGVAR) {
14114                                                 load = NULL;
14115                                                 reg1 = info_var->dreg;
14116                                         } else {
14117                                                 g_assert_not_reached ();
14118                                         }
14119                                         reg2 = alloc_ireg (cfg);
14120                                         NEW_LOAD_MEMBASE (cfg, load2, OP_LOADI4_MEMBASE, reg2, reg1, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
14121                                         /* Load the locals area address */
14122                                         reg3 = alloc_ireg (cfg);
14123                                         if (locals_var->opcode == OP_REGOFFSET) {
14124                                                 NEW_LOAD_MEMBASE (cfg, load3, OP_LOAD_MEMBASE, reg3, locals_var->inst_basereg, locals_var->inst_offset);
14125                                         } else if (locals_var->opcode == OP_REGVAR) {
14126                                                 NEW_UNALU (cfg, load3, OP_MOVE, reg3, locals_var->dreg);
14127                                         } else {
14128                                                 g_assert_not_reached ();
14129                                         }
14130                                         /* Compute the address */
14131                                         ins->opcode = OP_PADD;
14132                                         ins->sreg1 = reg3;
14133                                         ins->sreg2 = reg2;
14134
14135                                         mono_bblock_insert_before_ins (bb, ins, load3);
14136                                         mono_bblock_insert_before_ins (bb, load3, load2);
14137                                         if (load)
14138                                                 mono_bblock_insert_before_ins (bb, load2, load);
14139                                 } else {
14140                                         g_assert (var->opcode == OP_REGOFFSET);
14141
14142                                         ins->opcode = OP_ADD_IMM;
14143                                         ins->sreg1 = var->inst_basereg;
14144                                         ins->inst_imm = var->inst_offset;
14145                                 }
14146
14147                                 *need_local_opts = TRUE;
14148                                 spec = INS_INFO (ins->opcode);
14149                         }
14150
14151                         if (ins->opcode < MONO_CEE_LAST) {
14152                                 mono_print_ins (ins);
14153                                 g_assert_not_reached ();
14154                         }
14155
14156                         /*
14157                          * Store opcodes have destbasereg in the dreg, but in reality, it is an
14158                          * src register.
14159                          * FIXME:
14160                          */
14161                         if (MONO_IS_STORE_MEMBASE (ins)) {
14162                                 tmp_reg = ins->dreg;
14163                                 ins->dreg = ins->sreg2;
14164                                 ins->sreg2 = tmp_reg;
14165                                 store = TRUE;
14166
14167                                 spec2 [MONO_INST_DEST] = ' ';
14168                                 spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14169                                 spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14170                                 spec2 [MONO_INST_SRC3] = ' ';
14171                                 spec = spec2;
14172                         } else if (MONO_IS_STORE_MEMINDEX (ins))
14173                                 g_assert_not_reached ();
14174                         else
14175                                 store = FALSE;
14176                         no_lvreg = FALSE;
14177
14178                         if (G_UNLIKELY (cfg->verbose_level > 2)) {
14179                                 printf ("\t %.3s %d", spec, ins->dreg);
14180                                 num_sregs = mono_inst_get_src_registers (ins, sregs);
14181                                 for (srcindex = 0; srcindex < num_sregs; ++srcindex)
14182                                         printf (" %d", sregs [srcindex]);
14183                                 printf ("\n");
14184                         }
14185
14186                         /***************/
14187                         /*    DREG     */
14188                         /***************/
14189                         regtype = spec [MONO_INST_DEST];
14190                         g_assert (((ins->dreg == -1) && (regtype == ' ')) || ((ins->dreg != -1) && (regtype != ' ')));
14191                         prev_dreg = -1;
14192
14193                         if ((ins->dreg != -1) && get_vreg_to_inst (cfg, ins->dreg)) {
14194                                 MonoInst *var = get_vreg_to_inst (cfg, ins->dreg);
14195                                 MonoInst *store_ins;
14196                                 int store_opcode;
14197                                 MonoInst *def_ins = ins;
14198                                 int dreg = ins->dreg; /* The original vreg */
14199
14200                                 store_opcode = mono_type_to_store_membase (cfg, var->inst_vtype);
14201
14202                                 if (var->opcode == OP_REGVAR) {
14203                                         ins->dreg = var->dreg;
14204                                 } 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)) {
14205                                         /* 
14206                                          * Instead of emitting a load+store, use a _membase opcode.
14207                                          */
14208                                         g_assert (var->opcode == OP_REGOFFSET);
14209                                         if (ins->opcode == OP_MOVE) {
14210                                                 NULLIFY_INS (ins);
14211                                                 def_ins = NULL;
14212                                         } else {
14213                                                 ins->opcode = op_to_op_dest_membase (store_opcode, ins->opcode);
14214                                                 ins->inst_basereg = var->inst_basereg;
14215                                                 ins->inst_offset = var->inst_offset;
14216                                                 ins->dreg = -1;
14217                                         }
14218                                         spec = INS_INFO (ins->opcode);
14219                                 } else {
14220                                         guint32 lvreg;
14221
14222                                         g_assert (var->opcode == OP_REGOFFSET);
14223
14224                                         prev_dreg = ins->dreg;
14225
14226                                         /* Invalidate any previous lvreg for this vreg */
14227                                         vreg_to_lvreg [ins->dreg] = 0;
14228
14229                                         lvreg = 0;
14230
14231                                         if (COMPILE_SOFT_FLOAT (cfg) && store_opcode == OP_STORER8_MEMBASE_REG) {
14232                                                 regtype = 'l';
14233                                                 store_opcode = OP_STOREI8_MEMBASE_REG;
14234                                         }
14235
14236                                         ins->dreg = alloc_dreg (cfg, stacktypes [regtype]);
14237
14238 #if SIZEOF_REGISTER != 8
14239                                         if (regtype == 'l') {
14240                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET, ins->dreg + 1);
14241                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14242                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET, ins->dreg + 2);
14243                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14244                                                 def_ins = store_ins;
14245                                         }
14246                                         else
14247 #endif
14248                                         {
14249                                                 g_assert (store_opcode != OP_STOREV_MEMBASE);
14250
14251                                                 /* Try to fuse the store into the instruction itself */
14252                                                 /* FIXME: Add more instructions */
14253                                                 if (!lvreg && ((ins->opcode == OP_ICONST) || ((ins->opcode == OP_I8CONST) && (ins->inst_c0 == 0)))) {
14254                                                         ins->opcode = store_membase_reg_to_store_membase_imm (store_opcode);
14255                                                         ins->inst_imm = ins->inst_c0;
14256                                                         ins->inst_destbasereg = var->inst_basereg;
14257                                                         ins->inst_offset = var->inst_offset;
14258                                                         spec = INS_INFO (ins->opcode);
14259                                                 } else if (!lvreg && ((ins->opcode == OP_MOVE) || (ins->opcode == OP_FMOVE) || (ins->opcode == OP_LMOVE) || (ins->opcode == OP_RMOVE))) {
14260                                                         ins->opcode = store_opcode;
14261                                                         ins->inst_destbasereg = var->inst_basereg;
14262                                                         ins->inst_offset = var->inst_offset;
14263
14264                                                         no_lvreg = TRUE;
14265
14266                                                         tmp_reg = ins->dreg;
14267                                                         ins->dreg = ins->sreg2;
14268                                                         ins->sreg2 = tmp_reg;
14269                                                         store = TRUE;
14270
14271                                                         spec2 [MONO_INST_DEST] = ' ';
14272                                                         spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14273                                                         spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14274                                                         spec2 [MONO_INST_SRC3] = ' ';
14275                                                         spec = spec2;
14276                                                 } else if (!lvreg && (op_to_op_store_membase (store_opcode, ins->opcode) != -1)) {
14277                                                         // FIXME: The backends expect the base reg to be in inst_basereg
14278                                                         ins->opcode = op_to_op_store_membase (store_opcode, ins->opcode);
14279                                                         ins->dreg = -1;
14280                                                         ins->inst_basereg = var->inst_basereg;
14281                                                         ins->inst_offset = var->inst_offset;
14282                                                         spec = INS_INFO (ins->opcode);
14283                                                 } else {
14284                                                         /* printf ("INS: "); mono_print_ins (ins); */
14285                                                         /* Create a store instruction */
14286                                                         NEW_STORE_MEMBASE (cfg, store_ins, store_opcode, var->inst_basereg, var->inst_offset, ins->dreg);
14287
14288                                                         /* Insert it after the instruction */
14289                                                         mono_bblock_insert_after_ins (bb, ins, store_ins);
14290
14291                                                         def_ins = store_ins;
14292
14293                                                         /* 
14294                                                          * We can't assign ins->dreg to var->dreg here, since the
14295                                                          * sregs could use it. So set a flag, and do it after
14296                                                          * the sregs.
14297                                                          */
14298                                                         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)))
14299                                                                 dest_has_lvreg = TRUE;
14300                                                 }
14301                                         }
14302                                 }
14303
14304                                 if (def_ins && !live_range_start [dreg]) {
14305                                         live_range_start [dreg] = def_ins;
14306                                         live_range_start_bb [dreg] = bb;
14307                                 }
14308
14309                                 if (cfg->compute_gc_maps && def_ins && (var->flags & MONO_INST_GC_TRACK)) {
14310                                         MonoInst *tmp;
14311
14312                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
14313                                         tmp->inst_c1 = dreg;
14314                                         mono_bblock_insert_after_ins (bb, def_ins, tmp);
14315                                 }
14316                         }
14317
14318                         /************/
14319                         /*  SREGS   */
14320                         /************/
14321                         num_sregs = mono_inst_get_src_registers (ins, sregs);
14322                         for (srcindex = 0; srcindex < 3; ++srcindex) {
14323                                 regtype = spec [MONO_INST_SRC1 + srcindex];
14324                                 sreg = sregs [srcindex];
14325
14326                                 g_assert (((sreg == -1) && (regtype == ' ')) || ((sreg != -1) && (regtype != ' ')));
14327                                 if ((sreg != -1) && get_vreg_to_inst (cfg, sreg)) {
14328                                         MonoInst *var = get_vreg_to_inst (cfg, sreg);
14329                                         MonoInst *use_ins = ins;
14330                                         MonoInst *load_ins;
14331                                         guint32 load_opcode;
14332
14333                                         if (var->opcode == OP_REGVAR) {
14334                                                 sregs [srcindex] = var->dreg;
14335                                                 //mono_inst_set_src_registers (ins, sregs);
14336                                                 live_range_end [sreg] = use_ins;
14337                                                 live_range_end_bb [sreg] = bb;
14338
14339                                                 if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14340                                                         MonoInst *tmp;
14341
14342                                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14343                                                         /* var->dreg is a hreg */
14344                                                         tmp->inst_c1 = sreg;
14345                                                         mono_bblock_insert_after_ins (bb, ins, tmp);
14346                                                 }
14347
14348                                                 continue;
14349                                         }
14350
14351                                         g_assert (var->opcode == OP_REGOFFSET);
14352                                                 
14353                                         load_opcode = mono_type_to_load_membase (cfg, var->inst_vtype);
14354
14355                                         g_assert (load_opcode != OP_LOADV_MEMBASE);
14356
14357                                         if (vreg_to_lvreg [sreg]) {
14358                                                 g_assert (vreg_to_lvreg [sreg] != -1);
14359
14360                                                 /* The variable is already loaded to an lvreg */
14361                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
14362                                                         printf ("\t\tUse lvreg R%d for R%d.\n", vreg_to_lvreg [sreg], sreg);
14363                                                 sregs [srcindex] = vreg_to_lvreg [sreg];
14364                                                 //mono_inst_set_src_registers (ins, sregs);
14365                                                 continue;
14366                                         }
14367
14368                                         /* Try to fuse the load into the instruction */
14369                                         if ((srcindex == 0) && (op_to_op_src1_membase (load_opcode, ins->opcode) != -1)) {
14370                                                 ins->opcode = op_to_op_src1_membase (load_opcode, ins->opcode);
14371                                                 sregs [0] = var->inst_basereg;
14372                                                 //mono_inst_set_src_registers (ins, sregs);
14373                                                 ins->inst_offset = var->inst_offset;
14374                                         } else if ((srcindex == 1) && (op_to_op_src2_membase (load_opcode, ins->opcode) != -1)) {
14375                                                 ins->opcode = op_to_op_src2_membase (load_opcode, ins->opcode);
14376                                                 sregs [1] = var->inst_basereg;
14377                                                 //mono_inst_set_src_registers (ins, sregs);
14378                                                 ins->inst_offset = var->inst_offset;
14379                                         } else {
14380                                                 if (MONO_IS_REAL_MOVE (ins)) {
14381                                                         ins->opcode = OP_NOP;
14382                                                         sreg = ins->dreg;
14383                                                 } else {
14384                                                         //printf ("%d ", srcindex); mono_print_ins (ins);
14385
14386                                                         sreg = alloc_dreg (cfg, stacktypes [regtype]);
14387
14388                                                         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) {
14389                                                                 if (var->dreg == prev_dreg) {
14390                                                                         /*
14391                                                                          * sreg refers to the value loaded by the load
14392                                                                          * emitted below, but we need to use ins->dreg
14393                                                                          * since it refers to the store emitted earlier.
14394                                                                          */
14395                                                                         sreg = ins->dreg;
14396                                                                 }
14397                                                                 g_assert (sreg != -1);
14398                                                                 vreg_to_lvreg [var->dreg] = sreg;
14399                                                                 g_assert (lvregs_len < 1024);
14400                                                                 lvregs [lvregs_len ++] = var->dreg;
14401                                                         }
14402                                                 }
14403
14404                                                 sregs [srcindex] = sreg;
14405                                                 //mono_inst_set_src_registers (ins, sregs);
14406
14407 #if SIZEOF_REGISTER != 8
14408                                                 if (regtype == 'l') {
14409                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 2, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET);
14410                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14411                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 1, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET);
14412                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14413                                                         use_ins = load_ins;
14414                                                 }
14415                                                 else
14416 #endif
14417                                                 {
14418 #if SIZEOF_REGISTER == 4
14419                                                         g_assert (load_opcode != OP_LOADI8_MEMBASE);
14420 #endif
14421                                                         NEW_LOAD_MEMBASE (cfg, load_ins, load_opcode, sreg, var->inst_basereg, var->inst_offset);
14422                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14423                                                         use_ins = load_ins;
14424                                                 }
14425                                         }
14426
14427                                         if (var->dreg < orig_next_vreg) {
14428                                                 live_range_end [var->dreg] = use_ins;
14429                                                 live_range_end_bb [var->dreg] = bb;
14430                                         }
14431
14432                                         if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14433                                                 MonoInst *tmp;
14434
14435                                                 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14436                                                 tmp->inst_c1 = var->dreg;
14437                                                 mono_bblock_insert_after_ins (bb, ins, tmp);
14438                                         }
14439                                 }
14440                         }
14441                         mono_inst_set_src_registers (ins, sregs);
14442
14443                         if (dest_has_lvreg) {
14444                                 g_assert (ins->dreg != -1);
14445                                 vreg_to_lvreg [prev_dreg] = ins->dreg;
14446                                 g_assert (lvregs_len < 1024);
14447                                 lvregs [lvregs_len ++] = prev_dreg;
14448                                 dest_has_lvreg = FALSE;
14449                         }
14450
14451                         if (store) {
14452                                 tmp_reg = ins->dreg;
14453                                 ins->dreg = ins->sreg2;
14454                                 ins->sreg2 = tmp_reg;
14455                         }
14456
14457                         if (MONO_IS_CALL (ins)) {
14458                                 /* Clear vreg_to_lvreg array */
14459                                 for (i = 0; i < lvregs_len; i++)
14460                                         vreg_to_lvreg [lvregs [i]] = 0;
14461                                 lvregs_len = 0;
14462                         } else if (ins->opcode == OP_NOP) {
14463                                 ins->dreg = -1;
14464                                 MONO_INST_NULLIFY_SREGS (ins);
14465                         }
14466
14467                         if (cfg->verbose_level > 2)
14468                                 mono_print_ins_index (1, ins);
14469                 }
14470
14471                 /* Extend the live range based on the liveness info */
14472                 if (cfg->compute_precise_live_ranges && bb->live_out_set && bb->code) {
14473                         for (i = 0; i < cfg->num_varinfo; i ++) {
14474                                 MonoMethodVar *vi = MONO_VARINFO (cfg, i);
14475
14476                                 if (vreg_is_volatile (cfg, vi->vreg))
14477                                         /* The liveness info is incomplete */
14478                                         continue;
14479
14480                                 if (mono_bitset_test_fast (bb->live_in_set, i) && !live_range_start [vi->vreg]) {
14481                                         /* Live from at least the first ins of this bb */
14482                                         live_range_start [vi->vreg] = bb->code;
14483                                         live_range_start_bb [vi->vreg] = bb;
14484                                 }
14485
14486                                 if (mono_bitset_test_fast (bb->live_out_set, i)) {
14487                                         /* Live at least until the last ins of this bb */
14488                                         live_range_end [vi->vreg] = bb->last_ins;
14489                                         live_range_end_bb [vi->vreg] = bb;
14490                                 }
14491                         }
14492                 }
14493         }
14494         
14495 #ifdef MONO_ARCH_HAVE_LIVERANGE_OPS
14496         /*
14497          * Emit LIVERANGE_START/LIVERANGE_END opcodes, the backend will implement them
14498          * by storing the current native offset into MonoMethodVar->live_range_start/end.
14499          */
14500         if (cfg->compute_precise_live_ranges && cfg->comp_done & MONO_COMP_LIVENESS) {
14501                 for (i = 0; i < cfg->num_varinfo; ++i) {
14502                         int vreg = MONO_VARINFO (cfg, i)->vreg;
14503                         MonoInst *ins;
14504
14505                         if (live_range_start [vreg]) {
14506                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_START);
14507                                 ins->inst_c0 = i;
14508                                 ins->inst_c1 = vreg;
14509                                 mono_bblock_insert_after_ins (live_range_start_bb [vreg], live_range_start [vreg], ins);
14510                         }
14511                         if (live_range_end [vreg]) {
14512                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_END);
14513                                 ins->inst_c0 = i;
14514                                 ins->inst_c1 = vreg;
14515                                 if (live_range_end [vreg] == live_range_end_bb [vreg]->last_ins)
14516                                         mono_add_ins_to_end (live_range_end_bb [vreg], ins);
14517                                 else
14518                                         mono_bblock_insert_after_ins (live_range_end_bb [vreg], live_range_end [vreg], ins);
14519                         }
14520                 }
14521         }
14522 #endif
14523
14524         if (cfg->gsharedvt_locals_var_ins) {
14525                 /* Nullify if unused */
14526                 cfg->gsharedvt_locals_var_ins->opcode = OP_PCONST;
14527                 cfg->gsharedvt_locals_var_ins->inst_imm = 0;
14528         }
14529
14530         g_free (live_range_start);
14531         g_free (live_range_end);
14532         g_free (live_range_start_bb);
14533         g_free (live_range_end_bb);
14534 }
14535
14536 /**
14537  * FIXME:
14538  * - use 'iadd' instead of 'int_add'
14539  * - handling ovf opcodes: decompose in method_to_ir.
14540  * - unify iregs/fregs
14541  *   -> partly done, the missing parts are:
14542  *   - a more complete unification would involve unifying the hregs as well, so
14543  *     code wouldn't need if (fp) all over the place. but that would mean the hregs
14544  *     would no longer map to the machine hregs, so the code generators would need to
14545  *     be modified. Also, on ia64 for example, niregs + nfregs > 256 -> bitmasks
14546  *     wouldn't work any more. Duplicating the code in mono_local_regalloc () into
14547  *     fp/non-fp branches speeds it up by about 15%.
14548  * - use sext/zext opcodes instead of shifts
14549  * - add OP_ICALL
14550  * - get rid of TEMPLOADs if possible and use vregs instead
14551  * - clean up usage of OP_P/OP_ opcodes
14552  * - cleanup usage of DUMMY_USE
14553  * - cleanup the setting of ins->type for MonoInst's which are pushed on the 
14554  *   stack
14555  * - set the stack type and allocate a dreg in the EMIT_NEW macros
14556  * - get rid of all the <foo>2 stuff when the new JIT is ready.
14557  * - make sure handle_stack_args () is called before the branch is emitted
14558  * - when the new IR is done, get rid of all unused stuff
14559  * - COMPARE/BEQ as separate instructions or unify them ?
14560  *   - keeping them separate allows specialized compare instructions like
14561  *     compare_imm, compare_membase
14562  *   - most back ends unify fp compare+branch, fp compare+ceq
14563  * - integrate mono_save_args into inline_method
14564  * - get rid of the empty bblocks created by MONO_EMIT_NEW_BRACH_BLOCK2
14565  * - handle long shift opts on 32 bit platforms somehow: they require 
14566  *   3 sregs (2 for arg1 and 1 for arg2)
14567  * - make byref a 'normal' type.
14568  * - use vregs for bb->out_stacks if possible, handle_global_vreg will make them a
14569  *   variable if needed.
14570  * - do not start a new IL level bblock when cfg->cbb is changed by a function call
14571  *   like inline_method.
14572  * - remove inlining restrictions
14573  * - fix LNEG and enable cfold of INEG
14574  * - generalize x86 optimizations like ldelema as a peephole optimization
14575  * - add store_mem_imm for amd64
14576  * - optimize the loading of the interruption flag in the managed->native wrappers
14577  * - avoid special handling of OP_NOP in passes
14578  * - move code inserting instructions into one function/macro.
14579  * - try a coalescing phase after liveness analysis
14580  * - add float -> vreg conversion + local optimizations on !x86
14581  * - figure out how to handle decomposed branches during optimizations, ie.
14582  *   compare+branch, op_jump_table+op_br etc.
14583  * - promote RuntimeXHandles to vregs
14584  * - vtype cleanups:
14585  *   - add a NEW_VARLOADA_VREG macro
14586  * - the vtype optimizations are blocked by the LDADDR opcodes generated for 
14587  *   accessing vtype fields.
14588  * - get rid of I8CONST on 64 bit platforms
14589  * - dealing with the increase in code size due to branches created during opcode
14590  *   decomposition:
14591  *   - use extended basic blocks
14592  *     - all parts of the JIT
14593  *     - handle_global_vregs () && local regalloc
14594  *   - avoid introducing global vregs during decomposition, like 'vtable' in isinst
14595  * - sources of increase in code size:
14596  *   - vtypes
14597  *   - long compares
14598  *   - isinst and castclass
14599  *   - lvregs not allocated to global registers even if used multiple times
14600  * - call cctors outside the JIT, to make -v output more readable and JIT timings more
14601  *   meaningful.
14602  * - check for fp stack leakage in other opcodes too. (-> 'exceptions' optimization)
14603  * - add all micro optimizations from the old JIT
14604  * - put tree optimizations into the deadce pass
14605  * - decompose op_start_handler/op_endfilter/op_endfinally earlier using an arch
14606  *   specific function.
14607  * - unify the float comparison opcodes with the other comparison opcodes, i.e.
14608  *   fcompare + branchCC.
14609  * - create a helper function for allocating a stack slot, taking into account 
14610  *   MONO_CFG_HAS_SPILLUP.
14611  * - merge r68207.
14612  * - merge the ia64 switch changes.
14613  * - optimize mono_regstate2_alloc_int/float.
14614  * - fix the pessimistic handling of variables accessed in exception handler blocks.
14615  * - need to write a tree optimization pass, but the creation of trees is difficult, i.e.
14616  *   parts of the tree could be separated by other instructions, killing the tree
14617  *   arguments, or stores killing loads etc. Also, should we fold loads into other
14618  *   instructions if the result of the load is used multiple times ?
14619  * - make the REM_IMM optimization in mini-x86.c arch-independent.
14620  * - LAST MERGE: 108395.
14621  * - when returning vtypes in registers, generate IR and append it to the end of the
14622  *   last bb instead of doing it in the epilog.
14623  * - change the store opcodes so they use sreg1 instead of dreg to store the base register.
14624  */
14625
14626 /*
14627
14628 NOTES
14629 -----
14630
14631 - When to decompose opcodes:
14632   - earlier: this makes some optimizations hard to implement, since the low level IR
14633   no longer contains the neccessary information. But it is easier to do.
14634   - later: harder to implement, enables more optimizations.
14635 - Branches inside bblocks:
14636   - created when decomposing complex opcodes. 
14637     - branches to another bblock: harmless, but not tracked by the branch 
14638       optimizations, so need to branch to a label at the start of the bblock.
14639     - branches to inside the same bblock: very problematic, trips up the local
14640       reg allocator. Can be fixed by spitting the current bblock, but that is a
14641       complex operation, since some local vregs can become global vregs etc.
14642 - Local/global vregs:
14643   - local vregs: temporary vregs used inside one bblock. Assigned to hregs by the
14644     local register allocator.
14645   - global vregs: used in more than one bblock. Have an associated MonoMethodVar
14646     structure, created by mono_create_var (). Assigned to hregs or the stack by
14647     the global register allocator.
14648 - When to do optimizations like alu->alu_imm:
14649   - earlier -> saves work later on since the IR will be smaller/simpler
14650   - later -> can work on more instructions
14651 - Handling of valuetypes:
14652   - When a vtype is pushed on the stack, a new temporary is created, an 
14653     instruction computing its address (LDADDR) is emitted and pushed on
14654     the stack. Need to optimize cases when the vtype is used immediately as in
14655     argument passing, stloc etc.
14656 - Instead of the to_end stuff in the old JIT, simply call the function handling
14657   the values on the stack before emitting the last instruction of the bb.
14658 */
14659
14660 #endif /* DISABLE_JIT */