Merge pull request #2236 from akoeplinger/add-dataflow
[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-internals.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 #include "aot-compiler.h"
73
74 #define BRANCH_COST 10
75 #define INLINE_LENGTH_LIMIT 20
76
77 /* These have 'cfg' as an implicit argument */
78 #define INLINE_FAILURE(msg) do {                                                                        \
79         if ((cfg->method != cfg->current_method) && (cfg->current_method->wrapper_type == MONO_WRAPPER_NONE)) { \
80                 inline_failure (cfg, msg);                                                                              \
81                 goto exception_exit;                                                                                    \
82         } \
83         } while (0)
84 #define CHECK_CFG_EXCEPTION do {\
85                 if (cfg->exception_type != MONO_EXCEPTION_NONE) \
86                         goto exception_exit;                                            \
87         } while (0)
88 #define METHOD_ACCESS_FAILURE(method, cmethod) do {                     \
89                 method_access_failure ((cfg), (method), (cmethod));                     \
90                 goto exception_exit;                                                                            \
91         } while (0)
92 #define FIELD_ACCESS_FAILURE(method, field) do {                                        \
93                 field_access_failure ((cfg), (method), (field));                        \
94                 goto exception_exit;    \
95         } while (0)
96 #define GENERIC_SHARING_FAILURE(opcode) do {            \
97                 if (cfg->gshared) {                                                                     \
98                         gshared_failure (cfg, opcode, __FILE__, __LINE__);      \
99                         goto exception_exit;    \
100                 }                       \
101         } while (0)
102 #define GSHAREDVT_FAILURE(opcode) do {          \
103         if (cfg->gsharedvt) {                                                                                           \
104                 gsharedvt_failure (cfg, opcode, __FILE__, __LINE__);                    \
105                 goto exception_exit;                                                                                    \
106         }                                                                                                                                       \
107         } while (0)
108 #define OUT_OF_MEMORY_FAILURE do {      \
109                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_OUT_OF_MEMORY);             \
110                 goto exception_exit;    \
111         } while (0)
112 #define DISABLE_AOT(cfg) do { \
113                 if ((cfg)->verbose_level >= 2)                                            \
114                         printf ("AOT disabled: %s:%d\n", __FILE__, __LINE__);   \
115                 (cfg)->disable_aot = TRUE;                                                        \
116         } while (0)
117 #define LOAD_ERROR do { \
118                 break_on_unverified ();                                                         \
119                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD); \
120                 goto exception_exit;                                                                    \
121         } while (0)
122
123 #define TYPE_LOAD_ERROR(klass) do { \
124                 cfg->exception_ptr = klass; \
125                 LOAD_ERROR;                                     \
126         } while (0)
127
128 #define CHECK_CFG_ERROR do {\
129                 if (!mono_error_ok (&cfg->error)) { \
130                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);        \
131                         goto mono_error_exit; \
132                 } \
133         } while (0)
134
135 /* Determine whenever 'ins' represents a load of the 'this' argument */
136 #define MONO_CHECK_THIS(ins) (mono_method_signature (cfg->method)->hasthis && ((ins)->opcode == OP_MOVE) && ((ins)->sreg1 == cfg->args [0]->dreg))
137
138 static int ldind_to_load_membase (int opcode);
139 static int stind_to_store_membase (int opcode);
140
141 int mono_op_to_op_imm (int opcode);
142 int mono_op_to_op_imm_noemul (int opcode);
143
144 MONO_API MonoInst* mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig, MonoInst **args);
145
146 static int inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
147                                                   guchar *ip, guint real_offset, gboolean inline_always);
148
149 /* helper methods signatures */
150 static MonoMethodSignature *helper_sig_domain_get;
151 static MonoMethodSignature *helper_sig_rgctx_lazy_fetch_trampoline;
152
153 /*
154  * Instruction metadata
155  */
156 #ifdef MINI_OP
157 #undef MINI_OP
158 #endif
159 #ifdef MINI_OP3
160 #undef MINI_OP3
161 #endif
162 #define MINI_OP(a,b,dest,src1,src2) dest, src1, src2, ' ',
163 #define MINI_OP3(a,b,dest,src1,src2,src3) dest, src1, src2, src3,
164 #define NONE ' '
165 #define IREG 'i'
166 #define FREG 'f'
167 #define VREG 'v'
168 #define XREG 'x'
169 #if SIZEOF_REGISTER == 8 && SIZEOF_REGISTER == SIZEOF_VOID_P
170 #define LREG IREG
171 #else
172 #define LREG 'l'
173 #endif
174 /* keep in sync with the enum in mini.h */
175 const char
176 ins_info[] = {
177 #include "mini-ops.h"
178 };
179 #undef MINI_OP
180 #undef MINI_OP3
181
182 #define MINI_OP(a,b,dest,src1,src2) ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0)),
183 #define MINI_OP3(a,b,dest,src1,src2,src3) ((src3) != NONE ? 3 : ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0))),
184 /* 
185  * This should contain the index of the last sreg + 1. This is not the same
186  * as the number of sregs for opcodes like IA64_CMP_EQ_IMM.
187  */
188 const gint8 ins_sreg_counts[] = {
189 #include "mini-ops.h"
190 };
191 #undef MINI_OP
192 #undef MINI_OP3
193
194 #define MONO_INIT_VARINFO(vi,id) do { \
195         (vi)->range.first_use.pos.bid = 0xffff; \
196         (vi)->reg = -1; \
197         (vi)->idx = (id); \
198 } while (0)
199
200 guint32
201 mono_alloc_ireg (MonoCompile *cfg)
202 {
203         return alloc_ireg (cfg);
204 }
205
206 guint32
207 mono_alloc_lreg (MonoCompile *cfg)
208 {
209         return alloc_lreg (cfg);
210 }
211
212 guint32
213 mono_alloc_freg (MonoCompile *cfg)
214 {
215         return alloc_freg (cfg);
216 }
217
218 guint32
219 mono_alloc_preg (MonoCompile *cfg)
220 {
221         return alloc_preg (cfg);
222 }
223
224 guint32
225 mono_alloc_dreg (MonoCompile *cfg, MonoStackType stack_type)
226 {
227         return alloc_dreg (cfg, stack_type);
228 }
229
230 /*
231  * mono_alloc_ireg_ref:
232  *
233  *   Allocate an IREG, and mark it as holding a GC ref.
234  */
235 guint32
236 mono_alloc_ireg_ref (MonoCompile *cfg)
237 {
238         return alloc_ireg_ref (cfg);
239 }
240
241 /*
242  * mono_alloc_ireg_mp:
243  *
244  *   Allocate an IREG, and mark it as holding a managed pointer.
245  */
246 guint32
247 mono_alloc_ireg_mp (MonoCompile *cfg)
248 {
249         return alloc_ireg_mp (cfg);
250 }
251
252 /*
253  * mono_alloc_ireg_copy:
254  *
255  *   Allocate an IREG with the same GC type as VREG.
256  */
257 guint32
258 mono_alloc_ireg_copy (MonoCompile *cfg, guint32 vreg)
259 {
260         if (vreg_is_ref (cfg, vreg))
261                 return alloc_ireg_ref (cfg);
262         else if (vreg_is_mp (cfg, vreg))
263                 return alloc_ireg_mp (cfg);
264         else
265                 return alloc_ireg (cfg);
266 }
267
268 guint
269 mono_type_to_regmove (MonoCompile *cfg, MonoType *type)
270 {
271         if (type->byref)
272                 return OP_MOVE;
273
274         type = mini_get_underlying_type (type);
275 handle_enum:
276         switch (type->type) {
277         case MONO_TYPE_I1:
278         case MONO_TYPE_U1:
279                 return OP_MOVE;
280         case MONO_TYPE_I2:
281         case MONO_TYPE_U2:
282                 return OP_MOVE;
283         case MONO_TYPE_I4:
284         case MONO_TYPE_U4:
285                 return OP_MOVE;
286         case MONO_TYPE_I:
287         case MONO_TYPE_U:
288         case MONO_TYPE_PTR:
289         case MONO_TYPE_FNPTR:
290                 return OP_MOVE;
291         case MONO_TYPE_CLASS:
292         case MONO_TYPE_STRING:
293         case MONO_TYPE_OBJECT:
294         case MONO_TYPE_SZARRAY:
295         case MONO_TYPE_ARRAY:    
296                 return OP_MOVE;
297         case MONO_TYPE_I8:
298         case MONO_TYPE_U8:
299 #if SIZEOF_REGISTER == 8
300                 return OP_MOVE;
301 #else
302                 return OP_LMOVE;
303 #endif
304         case MONO_TYPE_R4:
305                 return cfg->r4fp ? OP_RMOVE : OP_FMOVE;
306         case MONO_TYPE_R8:
307                 return OP_FMOVE;
308         case MONO_TYPE_VALUETYPE:
309                 if (type->data.klass->enumtype) {
310                         type = mono_class_enum_basetype (type->data.klass);
311                         goto handle_enum;
312                 }
313                 if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (type)))
314                         return OP_XMOVE;
315                 return OP_VMOVE;
316         case MONO_TYPE_TYPEDBYREF:
317                 return OP_VMOVE;
318         case MONO_TYPE_GENERICINST:
319                 type = &type->data.generic_class->container_class->byval_arg;
320                 goto handle_enum;
321         case MONO_TYPE_VAR:
322         case MONO_TYPE_MVAR:
323                 g_assert (cfg->gshared);
324                 if (mini_type_var_is_vt (type))
325                         return OP_VMOVE;
326                 else
327                         return mono_type_to_regmove (cfg, mini_get_underlying_type (type));
328         default:
329                 g_error ("unknown type 0x%02x in type_to_regstore", type->type);
330         }
331         return -1;
332 }
333
334 void
335 mono_print_bb (MonoBasicBlock *bb, const char *msg)
336 {
337         int i;
338         MonoInst *tree;
339
340         printf ("\n%s %d: [IN: ", msg, bb->block_num);
341         for (i = 0; i < bb->in_count; ++i)
342                 printf (" BB%d(%d)", bb->in_bb [i]->block_num, bb->in_bb [i]->dfn);
343         printf (", OUT: ");
344         for (i = 0; i < bb->out_count; ++i)
345                 printf (" BB%d(%d)", bb->out_bb [i]->block_num, bb->out_bb [i]->dfn);
346         printf (" ]\n");
347         for (tree = bb->code; tree; tree = tree->next)
348                 mono_print_ins_index (-1, tree);
349 }
350
351 void
352 mono_create_helper_signatures (void)
353 {
354         helper_sig_domain_get = mono_create_icall_signature ("ptr");
355         helper_sig_rgctx_lazy_fetch_trampoline = mono_create_icall_signature ("ptr ptr");
356 }
357
358 static MONO_NEVER_INLINE void
359 break_on_unverified (void)
360 {
361         if (mini_get_debug_options ()->break_on_unverified)
362                 G_BREAKPOINT ();
363 }
364
365 static MONO_NEVER_INLINE void
366 method_access_failure (MonoCompile *cfg, MonoMethod *method, MonoMethod *cil_method)
367 {
368         char *method_fname = mono_method_full_name (method, TRUE);
369         char *cil_method_fname = mono_method_full_name (cil_method, TRUE);
370         mono_cfg_set_exception (cfg, MONO_EXCEPTION_METHOD_ACCESS);
371         cfg->exception_message = g_strdup_printf ("Method `%s' is inaccessible from method `%s'\n", cil_method_fname, method_fname);
372         g_free (method_fname);
373         g_free (cil_method_fname);
374 }
375
376 static MONO_NEVER_INLINE void
377 field_access_failure (MonoCompile *cfg, MonoMethod *method, MonoClassField *field)
378 {
379         char *method_fname = mono_method_full_name (method, TRUE);
380         char *field_fname = mono_field_full_name (field);
381         mono_cfg_set_exception (cfg, MONO_EXCEPTION_FIELD_ACCESS);
382         cfg->exception_message = g_strdup_printf ("Field `%s' is inaccessible from method `%s'\n", field_fname, method_fname);
383         g_free (method_fname);
384         g_free (field_fname);
385 }
386
387 static MONO_NEVER_INLINE void
388 inline_failure (MonoCompile *cfg, const char *msg)
389 {
390         if (cfg->verbose_level >= 2)
391                 printf ("inline failed: %s\n", msg);
392         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INLINE_FAILED);
393 }
394
395 static MONO_NEVER_INLINE void
396 gshared_failure (MonoCompile *cfg, int opcode, const char *file, int line)
397 {
398         if (cfg->verbose_level > 2)                                                                                     \
399                 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);
400         mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED);
401 }
402
403 static MONO_NEVER_INLINE void
404 gsharedvt_failure (MonoCompile *cfg, int opcode, const char *file, int line)
405 {
406         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);
407         if (cfg->verbose_level >= 2)
408                 printf ("%s\n", cfg->exception_message);
409         mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED);
410 }
411
412 /*
413  * When using gsharedvt, some instatiations might be verifiable, and some might be not. i.e. 
414  * foo<T> (int i) { ldarg.0; box T; }
415  */
416 #define UNVERIFIED do { \
417         if (cfg->gsharedvt) { \
418                 if (cfg->verbose_level > 2)                                                                     \
419                         printf ("gsharedvt method failed to verify, falling back to instantiation.\n"); \
420                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED); \
421                 goto exception_exit;                                                                                    \
422         }                                                                                                                                       \
423         break_on_unverified ();                                                                                         \
424         goto unverified;                                                                                                        \
425 } while (0)
426
427 #define GET_BBLOCK(cfg,tblock,ip) do {  \
428                 (tblock) = cfg->cil_offset_to_bb [(ip) - cfg->cil_start]; \
429                 if (!(tblock)) {        \
430                         if ((ip) >= end || (ip) < header->code) UNVERIFIED; \
431             NEW_BBLOCK (cfg, (tblock)); \
432                         (tblock)->cil_code = (ip);      \
433                         ADD_BBLOCK (cfg, (tblock));     \
434                 } \
435         } while (0)
436
437 #if defined(TARGET_X86) || defined(TARGET_AMD64)
438 #define EMIT_NEW_X86_LEA(cfg,dest,sr1,sr2,shift,imm) do { \
439                 MONO_INST_NEW (cfg, dest, OP_X86_LEA); \
440                 (dest)->dreg = alloc_ireg_mp ((cfg)); \
441                 (dest)->sreg1 = (sr1); \
442                 (dest)->sreg2 = (sr2); \
443                 (dest)->inst_imm = (imm); \
444                 (dest)->backend.shift_amount = (shift); \
445                 MONO_ADD_INS ((cfg)->cbb, (dest)); \
446         } while (0)
447 #endif
448
449 /* Emit conversions so both operands of a binary opcode are of the same type */
450 static void
451 add_widen_op (MonoCompile *cfg, MonoInst *ins, MonoInst **arg1_ref, MonoInst **arg2_ref)
452 {
453         MonoInst *arg1 = *arg1_ref;
454         MonoInst *arg2 = *arg2_ref;
455
456         if (cfg->r4fp &&
457                 ((arg1->type == STACK_R4 && arg2->type == STACK_R8) ||
458                  (arg1->type == STACK_R8 && arg2->type == STACK_R4))) {
459                 MonoInst *conv;
460
461                 /* Mixing r4/r8 is allowed by the spec */
462                 if (arg1->type == STACK_R4) {
463                         int dreg = alloc_freg (cfg);
464
465                         EMIT_NEW_UNALU (cfg, conv, OP_RCONV_TO_R8, dreg, arg1->dreg);
466                         conv->type = STACK_R8;
467                         ins->sreg1 = dreg;
468                         *arg1_ref = conv;
469                 }
470                 if (arg2->type == STACK_R4) {
471                         int dreg = alloc_freg (cfg);
472
473                         EMIT_NEW_UNALU (cfg, conv, OP_RCONV_TO_R8, dreg, arg2->dreg);
474                         conv->type = STACK_R8;
475                         ins->sreg2 = dreg;
476                         *arg2_ref = conv;
477                 }
478         }
479
480 #if SIZEOF_REGISTER == 8
481         /* FIXME: Need to add many more cases */
482         if ((arg1)->type == STACK_PTR && (arg2)->type == STACK_I4) {
483                 MonoInst *widen;
484
485                 int dr = alloc_preg (cfg);
486                 EMIT_NEW_UNALU (cfg, widen, OP_SEXT_I4, dr, (arg2)->dreg);
487                 (ins)->sreg2 = widen->dreg;
488         }
489 #endif
490 }
491
492 #define ADD_BINOP(op) do {      \
493                 MONO_INST_NEW (cfg, ins, (op)); \
494                 sp -= 2;        \
495                 ins->sreg1 = sp [0]->dreg;      \
496                 ins->sreg2 = sp [1]->dreg;      \
497                 type_from_op (cfg, ins, sp [0], sp [1]);        \
498                 CHECK_TYPE (ins);       \
499                 /* Have to insert a widening op */               \
500         add_widen_op (cfg, ins, &sp [0], &sp [1]);               \
501         ins->dreg = alloc_dreg ((cfg), (ins)->type); \
502         MONO_ADD_INS ((cfg)->cbb, (ins)); \
503         *sp++ = mono_decompose_opcode ((cfg), (ins));   \
504         } while (0)
505
506 #define ADD_UNOP(op) do {       \
507                 MONO_INST_NEW (cfg, ins, (op)); \
508                 sp--;   \
509                 ins->sreg1 = sp [0]->dreg;      \
510                 type_from_op (cfg, ins, sp [0], NULL);  \
511                 CHECK_TYPE (ins);       \
512         (ins)->dreg = alloc_dreg ((cfg), (ins)->type); \
513         MONO_ADD_INS ((cfg)->cbb, (ins)); \
514                 *sp++ = mono_decompose_opcode (cfg, ins);       \
515         } while (0)
516
517 #define ADD_BINCOND(next_block) do {    \
518                 MonoInst *cmp;  \
519                 sp -= 2; \
520                 MONO_INST_NEW(cfg, cmp, OP_COMPARE);    \
521                 cmp->sreg1 = sp [0]->dreg;      \
522                 cmp->sreg2 = sp [1]->dreg;      \
523                 type_from_op (cfg, cmp, sp [0], sp [1]);        \
524                 CHECK_TYPE (cmp);       \
525                 add_widen_op (cfg, cmp, &sp [0], &sp [1]);                                              \
526                 type_from_op (cfg, ins, sp [0], sp [1]);                                                        \
527                 ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);      \
528                 GET_BBLOCK (cfg, tblock, target);               \
529                 link_bblock (cfg, cfg->cbb, tblock);    \
530                 ins->inst_true_bb = tblock;     \
531                 if ((next_block)) {     \
532                         link_bblock (cfg, cfg->cbb, (next_block));      \
533                         ins->inst_false_bb = (next_block);      \
534                         start_new_bblock = 1;   \
535                 } else {        \
536                         GET_BBLOCK (cfg, tblock, ip);           \
537                         link_bblock (cfg, cfg->cbb, tblock);    \
538                         ins->inst_false_bb = tblock;    \
539                         start_new_bblock = 2;   \
540                 }       \
541                 if (sp != stack_start) {                                                                        \
542                     handle_stack_args (cfg, stack_start, sp - stack_start); \
543                         CHECK_UNVERIFIABLE (cfg); \
544                 } \
545         MONO_ADD_INS (cfg->cbb, cmp); \
546                 MONO_ADD_INS (cfg->cbb, ins);   \
547         } while (0)
548
549 /* *
550  * link_bblock: Links two basic blocks
551  *
552  * links two basic blocks in the control flow graph, the 'from'
553  * argument is the starting block and the 'to' argument is the block
554  * the control flow ends to after 'from'.
555  */
556 static void
557 link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
558 {
559         MonoBasicBlock **newa;
560         int i, found;
561
562 #if 0
563         if (from->cil_code) {
564                 if (to->cil_code)
565                         printf ("edge from IL%04x to IL_%04x\n", from->cil_code - cfg->cil_code, to->cil_code - cfg->cil_code);
566                 else
567                         printf ("edge from IL%04x to exit\n", from->cil_code - cfg->cil_code);
568         } else {
569                 if (to->cil_code)
570                         printf ("edge from entry to IL_%04x\n", to->cil_code - cfg->cil_code);
571                 else
572                         printf ("edge from entry to exit\n");
573         }
574 #endif
575
576         found = FALSE;
577         for (i = 0; i < from->out_count; ++i) {
578                 if (to == from->out_bb [i]) {
579                         found = TRUE;
580                         break;
581                 }
582         }
583         if (!found) {
584                 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (from->out_count + 1));
585                 for (i = 0; i < from->out_count; ++i) {
586                         newa [i] = from->out_bb [i];
587                 }
588                 newa [i] = to;
589                 from->out_count++;
590                 from->out_bb = newa;
591         }
592
593         found = FALSE;
594         for (i = 0; i < to->in_count; ++i) {
595                 if (from == to->in_bb [i]) {
596                         found = TRUE;
597                         break;
598                 }
599         }
600         if (!found) {
601                 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (to->in_count + 1));
602                 for (i = 0; i < to->in_count; ++i) {
603                         newa [i] = to->in_bb [i];
604                 }
605                 newa [i] = from;
606                 to->in_count++;
607                 to->in_bb = newa;
608         }
609 }
610
611 void
612 mono_link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
613 {
614         link_bblock (cfg, from, to);
615 }
616
617 /**
618  * mono_find_block_region:
619  *
620  *   We mark each basic block with a region ID. We use that to avoid BB
621  *   optimizations when blocks are in different regions.
622  *
623  * Returns:
624  *   A region token that encodes where this region is, and information
625  *   about the clause owner for this block.
626  *
627  *   The region encodes the try/catch/filter clause that owns this block
628  *   as well as the type.  -1 is a special value that represents a block
629  *   that is in none of try/catch/filter.
630  */
631 static int
632 mono_find_block_region (MonoCompile *cfg, int offset)
633 {
634         MonoMethodHeader *header = cfg->header;
635         MonoExceptionClause *clause;
636         int i;
637
638         for (i = 0; i < header->num_clauses; ++i) {
639                 clause = &header->clauses [i];
640                 if ((clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) && (offset >= clause->data.filter_offset) &&
641                     (offset < (clause->handler_offset)))
642                         return ((i + 1) << 8) | MONO_REGION_FILTER | clause->flags;
643                            
644                 if (MONO_OFFSET_IN_HANDLER (clause, offset)) {
645                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY)
646                                 return ((i + 1) << 8) | MONO_REGION_FINALLY | clause->flags;
647                         else if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
648                                 return ((i + 1) << 8) | MONO_REGION_FAULT | clause->flags;
649                         else
650                                 return ((i + 1) << 8) | MONO_REGION_CATCH | clause->flags;
651                 }
652         }
653         for (i = 0; i < header->num_clauses; ++i) {
654                 clause = &header->clauses [i];
655
656                 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
657                         return ((i + 1) << 8) | clause->flags;
658         }
659
660         return -1;
661 }
662
663 static GList*
664 mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *target, int type)
665 {
666         MonoMethodHeader *header = cfg->header;
667         MonoExceptionClause *clause;
668         int i;
669         GList *res = NULL;
670
671         for (i = 0; i < header->num_clauses; ++i) {
672                 clause = &header->clauses [i];
673                 if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) && 
674                     (!MONO_OFFSET_IN_CLAUSE (clause, (target - header->code)))) {
675                         if (clause->flags == type)
676                                 res = g_list_append (res, clause);
677                 }
678         }
679         return res;
680 }
681
682 static void
683 mono_create_spvar_for_region (MonoCompile *cfg, int region)
684 {
685         MonoInst *var;
686
687         var = g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
688         if (var)
689                 return;
690
691         var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
692         /* prevent it from being register allocated */
693         var->flags |= MONO_INST_VOLATILE;
694
695         g_hash_table_insert (cfg->spvars, GINT_TO_POINTER (region), var);
696 }
697
698 MonoInst *
699 mono_find_exvar_for_offset (MonoCompile *cfg, int offset)
700 {
701         return g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
702 }
703
704 static MonoInst*
705 mono_create_exvar_for_offset (MonoCompile *cfg, int offset)
706 {
707         MonoInst *var;
708
709         var = g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
710         if (var)
711                 return var;
712
713         var = mono_compile_create_var (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL);
714         /* prevent it from being register allocated */
715         var->flags |= MONO_INST_VOLATILE;
716
717         g_hash_table_insert (cfg->exvars, GINT_TO_POINTER (offset), var);
718
719         return var;
720 }
721
722 /*
723  * Returns the type used in the eval stack when @type is loaded.
724  * FIXME: return a MonoType/MonoClass for the byref and VALUETYPE cases.
725  */
726 void
727 type_to_eval_stack_type (MonoCompile *cfg, MonoType *type, MonoInst *inst)
728 {
729         MonoClass *klass;
730
731         type = mini_get_underlying_type (type);
732         inst->klass = klass = mono_class_from_mono_type (type);
733         if (type->byref) {
734                 inst->type = STACK_MP;
735                 return;
736         }
737
738 handle_enum:
739         switch (type->type) {
740         case MONO_TYPE_VOID:
741                 inst->type = STACK_INV;
742                 return;
743         case MONO_TYPE_I1:
744         case MONO_TYPE_U1:
745         case MONO_TYPE_I2:
746         case MONO_TYPE_U2:
747         case MONO_TYPE_I4:
748         case MONO_TYPE_U4:
749                 inst->type = STACK_I4;
750                 return;
751         case MONO_TYPE_I:
752         case MONO_TYPE_U:
753         case MONO_TYPE_PTR:
754         case MONO_TYPE_FNPTR:
755                 inst->type = STACK_PTR;
756                 return;
757         case MONO_TYPE_CLASS:
758         case MONO_TYPE_STRING:
759         case MONO_TYPE_OBJECT:
760         case MONO_TYPE_SZARRAY:
761         case MONO_TYPE_ARRAY:    
762                 inst->type = STACK_OBJ;
763                 return;
764         case MONO_TYPE_I8:
765         case MONO_TYPE_U8:
766                 inst->type = STACK_I8;
767                 return;
768         case MONO_TYPE_R4:
769                 inst->type = cfg->r4_stack_type;
770                 break;
771         case MONO_TYPE_R8:
772                 inst->type = STACK_R8;
773                 return;
774         case MONO_TYPE_VALUETYPE:
775                 if (type->data.klass->enumtype) {
776                         type = mono_class_enum_basetype (type->data.klass);
777                         goto handle_enum;
778                 } else {
779                         inst->klass = klass;
780                         inst->type = STACK_VTYPE;
781                         return;
782                 }
783         case MONO_TYPE_TYPEDBYREF:
784                 inst->klass = mono_defaults.typed_reference_class;
785                 inst->type = STACK_VTYPE;
786                 return;
787         case MONO_TYPE_GENERICINST:
788                 type = &type->data.generic_class->container_class->byval_arg;
789                 goto handle_enum;
790         case MONO_TYPE_VAR:
791         case MONO_TYPE_MVAR:
792                 g_assert (cfg->gshared);
793                 if (mini_is_gsharedvt_type (type)) {
794                         g_assert (cfg->gsharedvt);
795                         inst->type = STACK_VTYPE;
796                 } else {
797                         type_to_eval_stack_type (cfg, mini_get_underlying_type (type), inst);
798                 }
799                 return;
800         default:
801                 g_error ("unknown type 0x%02x in eval stack type", type->type);
802         }
803 }
804
805 /*
806  * The following tables are used to quickly validate the IL code in type_from_op ().
807  */
808 static const char
809 bin_num_table [STACK_MAX] [STACK_MAX] = {
810         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
811         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
812         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
813         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
814         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8,  STACK_INV, STACK_INV, STACK_INV, STACK_R8},
815         {STACK_INV, STACK_MP,  STACK_INV, STACK_MP,  STACK_INV, STACK_PTR, 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_INV, STACK_INV, STACK_INV, STACK_INV},
818         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8, STACK_INV, STACK_INV, STACK_INV, STACK_R4}
819 };
820
821 static const char 
822 neg_table [] = {
823         STACK_INV, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_INV, STACK_INV, STACK_INV, STACK_R4
824 };
825
826 /* reduce the size of this table */
827 static const char
828 bin_int_table [STACK_MAX] [STACK_MAX] = {
829         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
830         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
831         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
832         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, 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         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
837 };
838
839 static const char
840 bin_comp_table [STACK_MAX] [STACK_MAX] = {
841 /*      Inv i  L  p  F  &  O  vt r4 */
842         {0},
843         {0, 1, 0, 1, 0, 0, 0, 0}, /* i, int32 */
844         {0, 0, 1, 0, 0, 0, 0, 0}, /* L, int64 */
845         {0, 1, 0, 1, 0, 2, 4, 0}, /* p, ptr */
846         {0, 0, 0, 0, 1, 0, 0, 0, 1}, /* F, R8 */
847         {0, 0, 0, 2, 0, 1, 0, 0}, /* &, managed pointer */
848         {0, 0, 0, 4, 0, 0, 3, 0}, /* O, reference */
849         {0, 0, 0, 0, 0, 0, 0, 0}, /* vt value type */
850         {0, 0, 0, 0, 1, 0, 0, 0, 1}, /* r, r4 */
851 };
852
853 /* reduce the size of this table */
854 static const char
855 shift_table [STACK_MAX] [STACK_MAX] = {
856         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
857         {STACK_INV, STACK_I4,  STACK_INV, STACK_I4,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
858         {STACK_INV, STACK_I8,  STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
859         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, 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         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
864 };
865
866 /*
867  * Tables to map from the non-specific opcode to the matching
868  * type-specific opcode.
869  */
870 /* handles from CEE_ADD to CEE_SHR_UN (CEE_REM_UN for floats) */
871 static const guint16
872 binops_op_map [STACK_MAX] = {
873         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
874 };
875
876 /* handles from CEE_NEG to CEE_CONV_U8 */
877 static const guint16
878 unops_op_map [STACK_MAX] = {
879         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
880 };
881
882 /* handles from CEE_CONV_U2 to CEE_SUB_OVF_UN */
883 static const guint16
884 ovfops_op_map [STACK_MAX] = {
885         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
886 };
887
888 /* handles from CEE_CONV_OVF_I1_UN to CEE_CONV_OVF_U_UN */
889 static const guint16
890 ovf2ops_op_map [STACK_MAX] = {
891         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
892 };
893
894 /* handles from CEE_CONV_OVF_I1 to CEE_CONV_OVF_U8 */
895 static const guint16
896 ovf3ops_op_map [STACK_MAX] = {
897         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
898 };
899
900 /* handles from CEE_BEQ to CEE_BLT_UN */
901 static const guint16
902 beqops_op_map [STACK_MAX] = {
903         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
904 };
905
906 /* handles from CEE_CEQ to CEE_CLT_UN */
907 static const guint16
908 ceqops_op_map [STACK_MAX] = {
909         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
910 };
911
912 /*
913  * Sets ins->type (the type on the eval stack) according to the
914  * type of the opcode and the arguments to it.
915  * Invalid IL code is marked by setting ins->type to the invalid value STACK_INV.
916  *
917  * FIXME: this function sets ins->type unconditionally in some cases, but
918  * it should set it to invalid for some types (a conv.x on an object)
919  */
920 static void
921 type_from_op (MonoCompile *cfg, MonoInst *ins, MonoInst *src1, MonoInst *src2)
922 {
923         switch (ins->opcode) {
924         /* binops */
925         case CEE_ADD:
926         case CEE_SUB:
927         case CEE_MUL:
928         case CEE_DIV:
929         case CEE_REM:
930                 /* FIXME: check unverifiable args for STACK_MP */
931                 ins->type = bin_num_table [src1->type] [src2->type];
932                 ins->opcode += binops_op_map [ins->type];
933                 break;
934         case CEE_DIV_UN:
935         case CEE_REM_UN:
936         case CEE_AND:
937         case CEE_OR:
938         case CEE_XOR:
939                 ins->type = bin_int_table [src1->type] [src2->type];
940                 ins->opcode += binops_op_map [ins->type];
941                 break;
942         case CEE_SHL:
943         case CEE_SHR:
944         case CEE_SHR_UN:
945                 ins->type = shift_table [src1->type] [src2->type];
946                 ins->opcode += binops_op_map [ins->type];
947                 break;
948         case OP_COMPARE:
949         case OP_LCOMPARE:
950         case OP_ICOMPARE:
951                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
952                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
953                         ins->opcode = OP_LCOMPARE;
954                 else if (src1->type == STACK_R4)
955                         ins->opcode = OP_RCOMPARE;
956                 else if (src1->type == STACK_R8)
957                         ins->opcode = OP_FCOMPARE;
958                 else
959                         ins->opcode = OP_ICOMPARE;
960                 break;
961         case OP_ICOMPARE_IMM:
962                 ins->type = bin_comp_table [src1->type] [src1->type] ? STACK_I4 : STACK_INV;
963                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
964                         ins->opcode = OP_LCOMPARE_IMM;          
965                 break;
966         case CEE_BEQ:
967         case CEE_BGE:
968         case CEE_BGT:
969         case CEE_BLE:
970         case CEE_BLT:
971         case CEE_BNE_UN:
972         case CEE_BGE_UN:
973         case CEE_BGT_UN:
974         case CEE_BLE_UN:
975         case CEE_BLT_UN:
976                 ins->opcode += beqops_op_map [src1->type];
977                 break;
978         case OP_CEQ:
979                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
980                 ins->opcode += ceqops_op_map [src1->type];
981                 break;
982         case OP_CGT:
983         case OP_CGT_UN:
984         case OP_CLT:
985         case OP_CLT_UN:
986                 ins->type = (bin_comp_table [src1->type] [src2->type] & 1) ? STACK_I4: STACK_INV;
987                 ins->opcode += ceqops_op_map [src1->type];
988                 break;
989         /* unops */
990         case CEE_NEG:
991                 ins->type = neg_table [src1->type];
992                 ins->opcode += unops_op_map [ins->type];
993                 break;
994         case CEE_NOT:
995                 if (src1->type >= STACK_I4 && src1->type <= STACK_PTR)
996                         ins->type = src1->type;
997                 else
998                         ins->type = STACK_INV;
999                 ins->opcode += unops_op_map [ins->type];
1000                 break;
1001         case CEE_CONV_I1:
1002         case CEE_CONV_I2:
1003         case CEE_CONV_I4:
1004         case CEE_CONV_U4:
1005                 ins->type = STACK_I4;
1006                 ins->opcode += unops_op_map [src1->type];
1007                 break;
1008         case CEE_CONV_R_UN:
1009                 ins->type = STACK_R8;
1010                 switch (src1->type) {
1011                 case STACK_I4:
1012                 case STACK_PTR:
1013                         ins->opcode = OP_ICONV_TO_R_UN;
1014                         break;
1015                 case STACK_I8:
1016                         ins->opcode = OP_LCONV_TO_R_UN; 
1017                         break;
1018                 }
1019                 break;
1020         case CEE_CONV_OVF_I1:
1021         case CEE_CONV_OVF_U1:
1022         case CEE_CONV_OVF_I2:
1023         case CEE_CONV_OVF_U2:
1024         case CEE_CONV_OVF_I4:
1025         case CEE_CONV_OVF_U4:
1026                 ins->type = STACK_I4;
1027                 ins->opcode += ovf3ops_op_map [src1->type];
1028                 break;
1029         case CEE_CONV_OVF_I_UN:
1030         case CEE_CONV_OVF_U_UN:
1031                 ins->type = STACK_PTR;
1032                 ins->opcode += ovf2ops_op_map [src1->type];
1033                 break;
1034         case CEE_CONV_OVF_I1_UN:
1035         case CEE_CONV_OVF_I2_UN:
1036         case CEE_CONV_OVF_I4_UN:
1037         case CEE_CONV_OVF_U1_UN:
1038         case CEE_CONV_OVF_U2_UN:
1039         case CEE_CONV_OVF_U4_UN:
1040                 ins->type = STACK_I4;
1041                 ins->opcode += ovf2ops_op_map [src1->type];
1042                 break;
1043         case CEE_CONV_U:
1044                 ins->type = STACK_PTR;
1045                 switch (src1->type) {
1046                 case STACK_I4:
1047                         ins->opcode = OP_ICONV_TO_U;
1048                         break;
1049                 case STACK_PTR:
1050                 case STACK_MP:
1051 #if SIZEOF_VOID_P == 8
1052                         ins->opcode = OP_LCONV_TO_U;
1053 #else
1054                         ins->opcode = OP_MOVE;
1055 #endif
1056                         break;
1057                 case STACK_I8:
1058                         ins->opcode = OP_LCONV_TO_U;
1059                         break;
1060                 case STACK_R8:
1061                         ins->opcode = OP_FCONV_TO_U;
1062                         break;
1063                 }
1064                 break;
1065         case CEE_CONV_I8:
1066         case CEE_CONV_U8:
1067                 ins->type = STACK_I8;
1068                 ins->opcode += unops_op_map [src1->type];
1069                 break;
1070         case CEE_CONV_OVF_I8:
1071         case CEE_CONV_OVF_U8:
1072                 ins->type = STACK_I8;
1073                 ins->opcode += ovf3ops_op_map [src1->type];
1074                 break;
1075         case CEE_CONV_OVF_U8_UN:
1076         case CEE_CONV_OVF_I8_UN:
1077                 ins->type = STACK_I8;
1078                 ins->opcode += ovf2ops_op_map [src1->type];
1079                 break;
1080         case CEE_CONV_R4:
1081                 ins->type = cfg->r4_stack_type;
1082                 ins->opcode += unops_op_map [src1->type];
1083                 break;
1084         case CEE_CONV_R8:
1085                 ins->type = STACK_R8;
1086                 ins->opcode += unops_op_map [src1->type];
1087                 break;
1088         case OP_CKFINITE:
1089                 ins->type = STACK_R8;           
1090                 break;
1091         case CEE_CONV_U2:
1092         case CEE_CONV_U1:
1093                 ins->type = STACK_I4;
1094                 ins->opcode += ovfops_op_map [src1->type];
1095                 break;
1096         case CEE_CONV_I:
1097         case CEE_CONV_OVF_I:
1098         case CEE_CONV_OVF_U:
1099                 ins->type = STACK_PTR;
1100                 ins->opcode += ovfops_op_map [src1->type];
1101                 break;
1102         case CEE_ADD_OVF:
1103         case CEE_ADD_OVF_UN:
1104         case CEE_MUL_OVF:
1105         case CEE_MUL_OVF_UN:
1106         case CEE_SUB_OVF:
1107         case CEE_SUB_OVF_UN:
1108                 ins->type = bin_num_table [src1->type] [src2->type];
1109                 ins->opcode += ovfops_op_map [src1->type];
1110                 if (ins->type == STACK_R8)
1111                         ins->type = STACK_INV;
1112                 break;
1113         case OP_LOAD_MEMBASE:
1114                 ins->type = STACK_PTR;
1115                 break;
1116         case OP_LOADI1_MEMBASE:
1117         case OP_LOADU1_MEMBASE:
1118         case OP_LOADI2_MEMBASE:
1119         case OP_LOADU2_MEMBASE:
1120         case OP_LOADI4_MEMBASE:
1121         case OP_LOADU4_MEMBASE:
1122                 ins->type = STACK_PTR;
1123                 break;
1124         case OP_LOADI8_MEMBASE:
1125                 ins->type = STACK_I8;
1126                 break;
1127         case OP_LOADR4_MEMBASE:
1128                 ins->type = cfg->r4_stack_type;
1129                 break;
1130         case OP_LOADR8_MEMBASE:
1131                 ins->type = STACK_R8;
1132                 break;
1133         default:
1134                 g_error ("opcode 0x%04x not handled in type from op", ins->opcode);
1135                 break;
1136         }
1137
1138         if (ins->type == STACK_MP)
1139                 ins->klass = mono_defaults.object_class;
1140 }
1141
1142 static const char 
1143 ldind_type [] = {
1144         STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_R8, STACK_OBJ
1145 };
1146
1147 #if 0
1148
1149 static const char
1150 param_table [STACK_MAX] [STACK_MAX] = {
1151         {0},
1152 };
1153
1154 static int
1155 check_values_to_signature (MonoInst *args, MonoType *this_ins, MonoMethodSignature *sig)
1156 {
1157         int i;
1158
1159         if (sig->hasthis) {
1160                 switch (args->type) {
1161                 case STACK_I4:
1162                 case STACK_I8:
1163                 case STACK_R8:
1164                 case STACK_VTYPE:
1165                 case STACK_INV:
1166                         return 0;
1167                 }
1168                 args++;
1169         }
1170         for (i = 0; i < sig->param_count; ++i) {
1171                 switch (args [i].type) {
1172                 case STACK_INV:
1173                         return 0;
1174                 case STACK_MP:
1175                         if (!sig->params [i]->byref)
1176                                 return 0;
1177                         continue;
1178                 case STACK_OBJ:
1179                         if (sig->params [i]->byref)
1180                                 return 0;
1181                         switch (sig->params [i]->type) {
1182                         case MONO_TYPE_CLASS:
1183                         case MONO_TYPE_STRING:
1184                         case MONO_TYPE_OBJECT:
1185                         case MONO_TYPE_SZARRAY:
1186                         case MONO_TYPE_ARRAY:
1187                                 break;
1188                         default:
1189                                 return 0;
1190                         }
1191                         continue;
1192                 case STACK_R8:
1193                         if (sig->params [i]->byref)
1194                                 return 0;
1195                         if (sig->params [i]->type != MONO_TYPE_R4 && sig->params [i]->type != MONO_TYPE_R8)
1196                                 return 0;
1197                         continue;
1198                 case STACK_PTR:
1199                 case STACK_I4:
1200                 case STACK_I8:
1201                 case STACK_VTYPE:
1202                         break;
1203                 }
1204                 /*if (!param_table [args [i].type] [sig->params [i]->type])
1205                         return 0;*/
1206         }
1207         return 1;
1208 }
1209 #endif
1210
1211 /*
1212  * When we need a pointer to the current domain many times in a method, we
1213  * call mono_domain_get() once and we store the result in a local variable.
1214  * This function returns the variable that represents the MonoDomain*.
1215  */
1216 inline static MonoInst *
1217 mono_get_domainvar (MonoCompile *cfg)
1218 {
1219         if (!cfg->domainvar)
1220                 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1221         return cfg->domainvar;
1222 }
1223
1224 /*
1225  * The got_var contains the address of the Global Offset Table when AOT 
1226  * compiling.
1227  */
1228 MonoInst *
1229 mono_get_got_var (MonoCompile *cfg)
1230 {
1231         if (!cfg->compile_aot || !cfg->backend->need_got_var)
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 }
1238
1239 static MonoInst *
1240 mono_get_vtable_var (MonoCompile *cfg)
1241 {
1242         g_assert (cfg->gshared);
1243
1244         if (!cfg->rgctx_var) {
1245                 cfg->rgctx_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1246                 /* force the var to be stack allocated */
1247                 cfg->rgctx_var->flags |= MONO_INST_VOLATILE;
1248         }
1249
1250         return cfg->rgctx_var;
1251 }
1252
1253 static MonoType*
1254 type_from_stack_type (MonoInst *ins) {
1255         switch (ins->type) {
1256         case STACK_I4: return &mono_defaults.int32_class->byval_arg;
1257         case STACK_I8: return &mono_defaults.int64_class->byval_arg;
1258         case STACK_PTR: return &mono_defaults.int_class->byval_arg;
1259         case STACK_R4: return &mono_defaults.single_class->byval_arg;
1260         case STACK_R8: return &mono_defaults.double_class->byval_arg;
1261         case STACK_MP:
1262                 return &ins->klass->this_arg;
1263         case STACK_OBJ: return &mono_defaults.object_class->byval_arg;
1264         case STACK_VTYPE: return &ins->klass->byval_arg;
1265         default:
1266                 g_error ("stack type %d to monotype not handled\n", ins->type);
1267         }
1268         return NULL;
1269 }
1270
1271 static G_GNUC_UNUSED int
1272 type_to_stack_type (MonoCompile *cfg, MonoType *t)
1273 {
1274         t = mono_type_get_underlying_type (t);
1275         switch (t->type) {
1276         case MONO_TYPE_I1:
1277         case MONO_TYPE_U1:
1278         case MONO_TYPE_I2:
1279         case MONO_TYPE_U2:
1280         case MONO_TYPE_I4:
1281         case MONO_TYPE_U4:
1282                 return STACK_I4;
1283         case MONO_TYPE_I:
1284         case MONO_TYPE_U:
1285         case MONO_TYPE_PTR:
1286         case MONO_TYPE_FNPTR:
1287                 return STACK_PTR;
1288         case MONO_TYPE_CLASS:
1289         case MONO_TYPE_STRING:
1290         case MONO_TYPE_OBJECT:
1291         case MONO_TYPE_SZARRAY:
1292         case MONO_TYPE_ARRAY:    
1293                 return STACK_OBJ;
1294         case MONO_TYPE_I8:
1295         case MONO_TYPE_U8:
1296                 return STACK_I8;
1297         case MONO_TYPE_R4:
1298                 return cfg->r4_stack_type;
1299         case MONO_TYPE_R8:
1300                 return STACK_R8;
1301         case MONO_TYPE_VALUETYPE:
1302         case MONO_TYPE_TYPEDBYREF:
1303                 return STACK_VTYPE;
1304         case MONO_TYPE_GENERICINST:
1305                 if (mono_type_generic_inst_is_valuetype (t))
1306                         return STACK_VTYPE;
1307                 else
1308                         return STACK_OBJ;
1309                 break;
1310         default:
1311                 g_assert_not_reached ();
1312         }
1313
1314         return -1;
1315 }
1316
1317 static MonoClass*
1318 array_access_to_klass (int opcode)
1319 {
1320         switch (opcode) {
1321         case CEE_LDELEM_U1:
1322                 return mono_defaults.byte_class;
1323         case CEE_LDELEM_U2:
1324                 return mono_defaults.uint16_class;
1325         case CEE_LDELEM_I:
1326         case CEE_STELEM_I:
1327                 return mono_defaults.int_class;
1328         case CEE_LDELEM_I1:
1329         case CEE_STELEM_I1:
1330                 return mono_defaults.sbyte_class;
1331         case CEE_LDELEM_I2:
1332         case CEE_STELEM_I2:
1333                 return mono_defaults.int16_class;
1334         case CEE_LDELEM_I4:
1335         case CEE_STELEM_I4:
1336                 return mono_defaults.int32_class;
1337         case CEE_LDELEM_U4:
1338                 return mono_defaults.uint32_class;
1339         case CEE_LDELEM_I8:
1340         case CEE_STELEM_I8:
1341                 return mono_defaults.int64_class;
1342         case CEE_LDELEM_R4:
1343         case CEE_STELEM_R4:
1344                 return mono_defaults.single_class;
1345         case CEE_LDELEM_R8:
1346         case CEE_STELEM_R8:
1347                 return mono_defaults.double_class;
1348         case CEE_LDELEM_REF:
1349         case CEE_STELEM_REF:
1350                 return mono_defaults.object_class;
1351         default:
1352                 g_assert_not_reached ();
1353         }
1354         return NULL;
1355 }
1356
1357 /*
1358  * We try to share variables when possible
1359  */
1360 static MonoInst *
1361 mono_compile_get_interface_var (MonoCompile *cfg, int slot, MonoInst *ins)
1362 {
1363         MonoInst *res;
1364         int pos, vnum;
1365
1366         /* inlining can result in deeper stacks */ 
1367         if (slot >= cfg->header->max_stack)
1368                 return mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1369
1370         pos = ins->type - 1 + slot * STACK_MAX;
1371
1372         switch (ins->type) {
1373         case STACK_I4:
1374         case STACK_I8:
1375         case STACK_R8:
1376         case STACK_PTR:
1377         case STACK_MP:
1378         case STACK_OBJ:
1379                 if ((vnum = cfg->intvars [pos]))
1380                         return cfg->varinfo [vnum];
1381                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1382                 cfg->intvars [pos] = res->inst_c0;
1383                 break;
1384         default:
1385                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1386         }
1387         return res;
1388 }
1389
1390 static void
1391 mono_save_token_info (MonoCompile *cfg, MonoImage *image, guint32 token, gpointer key)
1392 {
1393         /* 
1394          * Don't use this if a generic_context is set, since that means AOT can't
1395          * look up the method using just the image+token.
1396          * table == 0 means this is a reference made from a wrapper.
1397          */
1398         if (cfg->compile_aot && !cfg->generic_context && (mono_metadata_token_table (token) > 0)) {
1399                 MonoJumpInfoToken *jump_info_token = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoToken));
1400                 jump_info_token->image = image;
1401                 jump_info_token->token = token;
1402                 g_hash_table_insert (cfg->token_info_hash, key, jump_info_token);
1403         }
1404 }
1405
1406 /*
1407  * This function is called to handle items that are left on the evaluation stack
1408  * at basic block boundaries. What happens is that we save the values to local variables
1409  * and we reload them later when first entering the target basic block (with the
1410  * handle_loaded_temps () function).
1411  * A single joint point will use the same variables (stored in the array bb->out_stack or
1412  * bb->in_stack, if the basic block is before or after the joint point).
1413  *
1414  * This function needs to be called _before_ emitting the last instruction of
1415  * the bb (i.e. before emitting a branch).
1416  * If the stack merge fails at a join point, cfg->unverifiable is set.
1417  */
1418 static void
1419 handle_stack_args (MonoCompile *cfg, MonoInst **sp, int count)
1420 {
1421         int i, bindex;
1422         MonoBasicBlock *bb = cfg->cbb;
1423         MonoBasicBlock *outb;
1424         MonoInst *inst, **locals;
1425         gboolean found;
1426
1427         if (!count)
1428                 return;
1429         if (cfg->verbose_level > 3)
1430                 printf ("%d item(s) on exit from B%d\n", count, bb->block_num);
1431         if (!bb->out_scount) {
1432                 bb->out_scount = count;
1433                 //printf ("bblock %d has out:", bb->block_num);
1434                 found = FALSE;
1435                 for (i = 0; i < bb->out_count; ++i) {
1436                         outb = bb->out_bb [i];
1437                         /* exception handlers are linked, but they should not be considered for stack args */
1438                         if (outb->flags & BB_EXCEPTION_HANDLER)
1439                                 continue;
1440                         //printf (" %d", outb->block_num);
1441                         if (outb->in_stack) {
1442                                 found = TRUE;
1443                                 bb->out_stack = outb->in_stack;
1444                                 break;
1445                         }
1446                 }
1447                 //printf ("\n");
1448                 if (!found) {
1449                         bb->out_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * count);
1450                         for (i = 0; i < count; ++i) {
1451                                 /* 
1452                                  * try to reuse temps already allocated for this purpouse, if they occupy the same
1453                                  * stack slot and if they are of the same type.
1454                                  * This won't cause conflicts since if 'local' is used to 
1455                                  * store one of the values in the in_stack of a bblock, then
1456                                  * the same variable will be used for the same outgoing stack 
1457                                  * slot as well. 
1458                                  * This doesn't work when inlining methods, since the bblocks
1459                                  * in the inlined methods do not inherit their in_stack from
1460                                  * the bblock they are inlined to. See bug #58863 for an
1461                                  * example.
1462                                  */
1463                                 if (cfg->inlined_method)
1464                                         bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
1465                                 else
1466                                         bb->out_stack [i] = mono_compile_get_interface_var (cfg, i, sp [i]);
1467                         }
1468                 }
1469         }
1470
1471         for (i = 0; i < bb->out_count; ++i) {
1472                 outb = bb->out_bb [i];
1473                 /* exception handlers are linked, but they should not be considered for stack args */
1474                 if (outb->flags & BB_EXCEPTION_HANDLER)
1475                         continue;
1476                 if (outb->in_scount) {
1477                         if (outb->in_scount != bb->out_scount) {
1478                                 cfg->unverifiable = TRUE;
1479                                 return;
1480                         }
1481                         continue; /* check they are the same locals */
1482                 }
1483                 outb->in_scount = count;
1484                 outb->in_stack = bb->out_stack;
1485         }
1486
1487         locals = bb->out_stack;
1488         cfg->cbb = bb;
1489         for (i = 0; i < count; ++i) {
1490                 EMIT_NEW_TEMPSTORE (cfg, inst, locals [i]->inst_c0, sp [i]);
1491                 inst->cil_code = sp [i]->cil_code;
1492                 sp [i] = locals [i];
1493                 if (cfg->verbose_level > 3)
1494                         printf ("storing %d to temp %d\n", i, (int)locals [i]->inst_c0);
1495         }
1496
1497         /*
1498          * It is possible that the out bblocks already have in_stack assigned, and
1499          * the in_stacks differ. In this case, we will store to all the different 
1500          * in_stacks.
1501          */
1502
1503         found = TRUE;
1504         bindex = 0;
1505         while (found) {
1506                 /* Find a bblock which has a different in_stack */
1507                 found = FALSE;
1508                 while (bindex < bb->out_count) {
1509                         outb = bb->out_bb [bindex];
1510                         /* exception handlers are linked, but they should not be considered for stack args */
1511                         if (outb->flags & BB_EXCEPTION_HANDLER) {
1512                                 bindex++;
1513                                 continue;
1514                         }
1515                         if (outb->in_stack != locals) {
1516                                 for (i = 0; i < count; ++i) {
1517                                         EMIT_NEW_TEMPSTORE (cfg, inst, outb->in_stack [i]->inst_c0, sp [i]);
1518                                         inst->cil_code = sp [i]->cil_code;
1519                                         sp [i] = locals [i];
1520                                         if (cfg->verbose_level > 3)
1521                                                 printf ("storing %d to temp %d\n", i, (int)outb->in_stack [i]->inst_c0);
1522                                 }
1523                                 locals = outb->in_stack;
1524                                 found = TRUE;
1525                                 break;
1526                         }
1527                         bindex ++;
1528                 }
1529         }
1530 }
1531
1532 static MonoInst*
1533 emit_runtime_constant (MonoCompile *cfg, MonoJumpInfoType patch_type, gpointer data)
1534 {
1535         MonoInst *ins;
1536
1537         if (cfg->compile_aot) {
1538                 EMIT_NEW_AOTCONST (cfg, ins, patch_type, data);
1539         } else {
1540                 MonoJumpInfo ji;
1541                 gpointer target;
1542
1543                 ji.type = patch_type;
1544                 ji.data.target = data;
1545                 target = mono_resolve_patch_target (NULL, cfg->domain, NULL, &ji, FALSE);
1546
1547                 EMIT_NEW_PCONST (cfg, ins, target);
1548         }
1549         return ins;
1550 }
1551
1552 static void
1553 mini_emit_interface_bitmap_check (MonoCompile *cfg, int intf_bit_reg, int base_reg, int offset, MonoClass *klass)
1554 {
1555         int ibitmap_reg = alloc_preg (cfg);
1556 #ifdef COMPRESSED_INTERFACE_BITMAP
1557         MonoInst *args [2];
1558         MonoInst *res, *ins;
1559         NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, ibitmap_reg, base_reg, offset);
1560         MONO_ADD_INS (cfg->cbb, ins);
1561         args [0] = ins;
1562         args [1] = emit_runtime_constant (cfg, MONO_PATCH_INFO_IID, klass);
1563         res = mono_emit_jit_icall (cfg, mono_class_interface_match, args);
1564         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, intf_bit_reg, res->dreg);
1565 #else
1566         int ibitmap_byte_reg = alloc_preg (cfg);
1567
1568         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, ibitmap_reg, base_reg, offset);
1569
1570         if (cfg->compile_aot) {
1571                 int iid_reg = alloc_preg (cfg);
1572                 int shifted_iid_reg = alloc_preg (cfg);
1573                 int ibitmap_byte_address_reg = alloc_preg (cfg);
1574                 int masked_iid_reg = alloc_preg (cfg);
1575                 int iid_one_bit_reg = alloc_preg (cfg);
1576                 int iid_bit_reg = alloc_preg (cfg);
1577                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1578                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, shifted_iid_reg, iid_reg, 3);
1579                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, ibitmap_byte_address_reg, ibitmap_reg, shifted_iid_reg);
1580                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, ibitmap_byte_reg, ibitmap_byte_address_reg, 0);
1581                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, masked_iid_reg, iid_reg, 7);
1582                 MONO_EMIT_NEW_ICONST (cfg, iid_one_bit_reg, 1);
1583                 MONO_EMIT_NEW_BIALU (cfg, OP_ISHL, iid_bit_reg, iid_one_bit_reg, masked_iid_reg);
1584                 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, intf_bit_reg, ibitmap_byte_reg, iid_bit_reg);
1585         } else {
1586                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, ibitmap_byte_reg, ibitmap_reg, klass->interface_id >> 3);
1587                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, intf_bit_reg, ibitmap_byte_reg, 1 << (klass->interface_id & 7));
1588         }
1589 #endif
1590 }
1591
1592 /* 
1593  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoClass
1594  * stored in "klass_reg" implements the interface "klass".
1595  */
1596 static void
1597 mini_emit_load_intf_bit_reg_class (MonoCompile *cfg, int intf_bit_reg, int klass_reg, MonoClass *klass)
1598 {
1599         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, interface_bitmap), klass);
1600 }
1601
1602 /* 
1603  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoVTable
1604  * stored in "vtable_reg" implements the interface "klass".
1605  */
1606 static void
1607 mini_emit_load_intf_bit_reg_vtable (MonoCompile *cfg, int intf_bit_reg, int vtable_reg, MonoClass *klass)
1608 {
1609         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, interface_bitmap), klass);
1610 }
1611
1612 /* 
1613  * Emit code which checks whenever the interface id of @klass is smaller than
1614  * than the value given by max_iid_reg.
1615 */
1616 static void
1617 mini_emit_max_iid_check (MonoCompile *cfg, int max_iid_reg, MonoClass *klass,
1618                                                  MonoBasicBlock *false_target)
1619 {
1620         if (cfg->compile_aot) {
1621                 int iid_reg = alloc_preg (cfg);
1622                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1623                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, max_iid_reg, iid_reg);
1624         }
1625         else
1626                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, max_iid_reg, klass->interface_id);
1627         if (false_target)
1628                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1629         else
1630                 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1631 }
1632
1633 /* Same as above, but obtains max_iid from a vtable */
1634 static void
1635 mini_emit_max_iid_check_vtable (MonoCompile *cfg, int vtable_reg, MonoClass *klass,
1636                                                                  MonoBasicBlock *false_target)
1637 {
1638         int max_iid_reg = alloc_preg (cfg);
1639                 
1640         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, max_interface_id));
1641         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1642 }
1643
1644 /* Same as above, but obtains max_iid from a klass */
1645 static void
1646 mini_emit_max_iid_check_class (MonoCompile *cfg, int klass_reg, MonoClass *klass,
1647                                                                  MonoBasicBlock *false_target)
1648 {
1649         int max_iid_reg = alloc_preg (cfg);
1650
1651         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, max_interface_id));
1652         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1653 }
1654
1655 static void
1656 mini_emit_isninst_cast_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_ins, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1657 {
1658         int idepth_reg = alloc_preg (cfg);
1659         int stypes_reg = alloc_preg (cfg);
1660         int stype = alloc_preg (cfg);
1661
1662         mono_class_setup_supertypes (klass);
1663
1664         if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1665                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth));
1666                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1667                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1668         }
1669         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes));
1670         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1671         if (klass_ins) {
1672                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, klass_ins->dreg);
1673         } else if (cfg->compile_aot) {
1674                 int const_reg = alloc_preg (cfg);
1675                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1676                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, const_reg);
1677         } else {
1678                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, stype, klass);
1679         }
1680         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, true_target);
1681 }
1682
1683 static void
1684 mini_emit_isninst_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1685 {
1686         mini_emit_isninst_cast_inst (cfg, klass_reg, klass, NULL, false_target, true_target);
1687 }
1688
1689 static void
1690 mini_emit_iface_cast (MonoCompile *cfg, int vtable_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1691 {
1692         int intf_reg = alloc_preg (cfg);
1693
1694         mini_emit_max_iid_check_vtable (cfg, vtable_reg, klass, false_target);
1695         mini_emit_load_intf_bit_reg_vtable (cfg, intf_reg, vtable_reg, klass);
1696         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_reg, 0);
1697         if (true_target)
1698                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1699         else
1700                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");               
1701 }
1702
1703 /*
1704  * Variant of the above that takes a register to the class, not the vtable.
1705  */
1706 static void
1707 mini_emit_iface_class_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1708 {
1709         int intf_bit_reg = alloc_preg (cfg);
1710
1711         mini_emit_max_iid_check_class (cfg, klass_reg, klass, false_target);
1712         mini_emit_load_intf_bit_reg_class (cfg, intf_bit_reg, klass_reg, klass);
1713         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_bit_reg, 0);
1714         if (true_target)
1715                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1716         else
1717                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
1718 }
1719
1720 static inline void
1721 mini_emit_class_check_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_inst)
1722 {
1723         if (klass_inst) {
1724                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_inst->dreg);
1725         } else {
1726                 MonoInst *ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, klass);
1727                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, ins->dreg);
1728         }
1729         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1730 }
1731
1732 static inline void
1733 mini_emit_class_check (MonoCompile *cfg, int klass_reg, MonoClass *klass)
1734 {
1735         mini_emit_class_check_inst (cfg, klass_reg, klass, NULL);
1736 }
1737
1738 static inline void
1739 mini_emit_class_check_branch (MonoCompile *cfg, int klass_reg, MonoClass *klass, int branch_op, MonoBasicBlock *target)
1740 {
1741         if (cfg->compile_aot) {
1742                 int const_reg = alloc_preg (cfg);
1743                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1744                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, const_reg);
1745         } else {
1746                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
1747         }
1748         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, branch_op, target);
1749 }
1750
1751 static void
1752 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null);
1753         
1754 static void
1755 mini_emit_castclass_inst (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoInst *klass_inst, MonoBasicBlock *object_is_null)
1756 {
1757         if (klass->rank) {
1758                 int rank_reg = alloc_preg (cfg);
1759                 int eclass_reg = alloc_preg (cfg);
1760
1761                 g_assert (!klass_inst);
1762                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, rank));
1763                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
1764                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1765                 //              MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
1766                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
1767                 if (klass->cast_class == mono_defaults.object_class) {
1768                         int parent_reg = alloc_preg (cfg);
1769                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
1770                         mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, object_is_null);
1771                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1772                 } else if (klass->cast_class == mono_defaults.enum_class->parent) {
1773                         mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, object_is_null);
1774                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1775                 } else if (klass->cast_class == mono_defaults.enum_class) {
1776                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1777                 } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1778                         mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, NULL, NULL);
1779                 } else {
1780                         // Pass -1 as obj_reg to skip the check below for arrays of arrays
1781                         mini_emit_castclass (cfg, -1, eclass_reg, klass->cast_class, object_is_null);
1782                 }
1783
1784                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY) && (obj_reg != -1)) {
1785                         /* Check that the object is a vector too */
1786                         int bounds_reg = alloc_preg (cfg);
1787                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
1788                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
1789                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1790                 }
1791         } else {
1792                 int idepth_reg = alloc_preg (cfg);
1793                 int stypes_reg = alloc_preg (cfg);
1794                 int stype = alloc_preg (cfg);
1795
1796                 mono_class_setup_supertypes (klass);
1797
1798                 if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1799                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth));
1800                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1801                         MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1802                 }
1803                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes));
1804                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1805                 mini_emit_class_check_inst (cfg, stype, klass, klass_inst);
1806         }
1807 }
1808
1809 static void
1810 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null)
1811 {
1812         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, NULL, object_is_null);
1813 }
1814
1815 static void 
1816 mini_emit_memset (MonoCompile *cfg, int destreg, int offset, int size, int val, int align)
1817 {
1818         int val_reg;
1819
1820         g_assert (val == 0);
1821
1822         if (align == 0)
1823                 align = 4;
1824
1825         if ((size <= SIZEOF_REGISTER) && (size <= align)) {
1826                 switch (size) {
1827                 case 1:
1828                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, destreg, offset, val);
1829                         return;
1830                 case 2:
1831                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI2_MEMBASE_IMM, destreg, offset, val);
1832                         return;
1833                 case 4:
1834                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI4_MEMBASE_IMM, destreg, offset, val);
1835                         return;
1836 #if SIZEOF_REGISTER == 8
1837                 case 8:
1838                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI8_MEMBASE_IMM, destreg, offset, val);
1839                         return;
1840 #endif
1841                 }
1842         }
1843
1844         val_reg = alloc_preg (cfg);
1845
1846         if (SIZEOF_REGISTER == 8)
1847                 MONO_EMIT_NEW_I8CONST (cfg, val_reg, val);
1848         else
1849                 MONO_EMIT_NEW_ICONST (cfg, val_reg, val);
1850
1851         if (align < 4) {
1852                 /* This could be optimized further if neccesary */
1853                 while (size >= 1) {
1854                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1855                         offset += 1;
1856                         size -= 1;
1857                 }
1858                 return;
1859         }       
1860
1861         if (!cfg->backend->no_unaligned_access && SIZEOF_REGISTER == 8) {
1862                 if (offset % 8) {
1863                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1864                         offset += 4;
1865                         size -= 4;
1866                 }
1867                 while (size >= 8) {
1868                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, offset, val_reg);
1869                         offset += 8;
1870                         size -= 8;
1871                 }
1872         }       
1873
1874         while (size >= 4) {
1875                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1876                 offset += 4;
1877                 size -= 4;
1878         }
1879         while (size >= 2) {
1880                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, val_reg);
1881                 offset += 2;
1882                 size -= 2;
1883         }
1884         while (size >= 1) {
1885                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1886                 offset += 1;
1887                 size -= 1;
1888         }
1889 }
1890
1891 void 
1892 mini_emit_memcpy (MonoCompile *cfg, int destreg, int doffset, int srcreg, int soffset, int size, int align)
1893 {
1894         int cur_reg;
1895
1896         if (align == 0)
1897                 align = 4;
1898
1899         /*FIXME arbitrary hack to avoid unbound code expansion.*/
1900         g_assert (size < 10000);
1901
1902         if (align < 4) {
1903                 /* This could be optimized further if neccesary */
1904                 while (size >= 1) {
1905                         cur_reg = alloc_preg (cfg);
1906                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1907                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1908                         doffset += 1;
1909                         soffset += 1;
1910                         size -= 1;
1911                 }
1912         }
1913
1914         if (!cfg->backend->no_unaligned_access && SIZEOF_REGISTER == 8) {
1915                 while (size >= 8) {
1916                         cur_reg = alloc_preg (cfg);
1917                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI8_MEMBASE, cur_reg, srcreg, soffset);
1918                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, doffset, cur_reg);
1919                         doffset += 8;
1920                         soffset += 8;
1921                         size -= 8;
1922                 }
1923         }       
1924
1925         while (size >= 4) {
1926                 cur_reg = alloc_preg (cfg);
1927                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, cur_reg, srcreg, soffset);
1928                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, doffset, cur_reg);
1929                 doffset += 4;
1930                 soffset += 4;
1931                 size -= 4;
1932         }
1933         while (size >= 2) {
1934                 cur_reg = alloc_preg (cfg);
1935                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, cur_reg, srcreg, soffset);
1936                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, doffset, cur_reg);
1937                 doffset += 2;
1938                 soffset += 2;
1939                 size -= 2;
1940         }
1941         while (size >= 1) {
1942                 cur_reg = alloc_preg (cfg);
1943                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1944                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1945                 doffset += 1;
1946                 soffset += 1;
1947                 size -= 1;
1948         }
1949 }
1950
1951 static void
1952 emit_tls_set (MonoCompile *cfg, int sreg1, int tls_key)
1953 {
1954         MonoInst *ins, *c;
1955
1956         if (cfg->compile_aot) {
1957                 EMIT_NEW_TLS_OFFSETCONST (cfg, c, tls_key);
1958                 MONO_INST_NEW (cfg, ins, OP_TLS_SET_REG);
1959                 ins->sreg1 = sreg1;
1960                 ins->sreg2 = c->dreg;
1961                 MONO_ADD_INS (cfg->cbb, ins);
1962         } else {
1963                 MONO_INST_NEW (cfg, ins, OP_TLS_SET);
1964                 ins->sreg1 = sreg1;
1965                 ins->inst_offset = mini_get_tls_offset (tls_key);
1966                 MONO_ADD_INS (cfg->cbb, ins);
1967         }
1968 }
1969
1970 /*
1971  * emit_push_lmf:
1972  *
1973  *   Emit IR to push the current LMF onto the LMF stack.
1974  */
1975 static void
1976 emit_push_lmf (MonoCompile *cfg)
1977 {
1978         /*
1979          * Emit IR to push the LMF:
1980          * lmf_addr = <lmf_addr from tls>
1981          * lmf->lmf_addr = lmf_addr
1982          * lmf->prev_lmf = *lmf_addr
1983          * *lmf_addr = lmf
1984          */
1985         int lmf_reg, prev_lmf_reg;
1986         MonoInst *ins, *lmf_ins;
1987
1988         if (!cfg->lmf_ir)
1989                 return;
1990
1991         if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
1992                 /* Load current lmf */
1993                 lmf_ins = mono_get_lmf_intrinsic (cfg);
1994                 g_assert (lmf_ins);
1995                 MONO_ADD_INS (cfg->cbb, lmf_ins);
1996                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
1997                 lmf_reg = ins->dreg;
1998                 /* Save previous_lmf */
1999                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), lmf_ins->dreg);
2000                 /* Set new LMF */
2001                 emit_tls_set (cfg, lmf_reg, TLS_KEY_LMF);
2002         } else {
2003                 /*
2004                  * Store lmf_addr in a variable, so it can be allocated to a global register.
2005                  */
2006                 if (!cfg->lmf_addr_var)
2007                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2008
2009 #ifdef HOST_WIN32
2010                 ins = mono_get_jit_tls_intrinsic (cfg);
2011                 if (ins) {
2012                         int jit_tls_dreg = ins->dreg;
2013
2014                         MONO_ADD_INS (cfg->cbb, ins);
2015                         lmf_reg = alloc_preg (cfg);
2016                         EMIT_NEW_BIALU_IMM (cfg, lmf_ins, OP_PADD_IMM, lmf_reg, jit_tls_dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, lmf));
2017                 } else {
2018                         lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
2019                 }
2020 #else
2021                 lmf_ins = mono_get_lmf_addr_intrinsic (cfg);
2022                 if (lmf_ins) {
2023                         MONO_ADD_INS (cfg->cbb, lmf_ins);
2024                 } else {
2025 #ifdef TARGET_IOS
2026                         MonoInst *args [16], *jit_tls_ins, *ins;
2027
2028                         /* Inline mono_get_lmf_addr () */
2029                         /* jit_tls = pthread_getspecific (mono_jit_tls_id); lmf_addr = &jit_tls->lmf; */
2030
2031                         /* Load mono_jit_tls_id */
2032                         if (cfg->compile_aot)
2033                                 EMIT_NEW_AOTCONST (cfg, args [0], MONO_PATCH_INFO_JIT_TLS_ID, NULL);
2034                         else
2035                                 EMIT_NEW_ICONST (cfg, args [0], mono_jit_tls_id);
2036                         /* call pthread_getspecific () */
2037                         jit_tls_ins = mono_emit_jit_icall (cfg, pthread_getspecific, args);
2038                         /* lmf_addr = &jit_tls->lmf */
2039                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, cfg->lmf_addr_var->dreg, jit_tls_ins->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, lmf));
2040                         lmf_ins = ins;
2041 #else
2042                         lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
2043 #endif
2044                 }
2045 #endif
2046                 lmf_ins->dreg = cfg->lmf_addr_var->dreg;
2047
2048                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2049                 lmf_reg = ins->dreg;
2050
2051                 prev_lmf_reg = alloc_preg (cfg);
2052                 /* Save previous_lmf */
2053                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, cfg->lmf_addr_var->dreg, 0);
2054                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), prev_lmf_reg);
2055                 /* Set new lmf */
2056                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, cfg->lmf_addr_var->dreg, 0, lmf_reg);
2057         }
2058 }
2059
2060 /*
2061  * emit_pop_lmf:
2062  *
2063  *   Emit IR to pop the current LMF from the LMF stack.
2064  */
2065 static void
2066 emit_pop_lmf (MonoCompile *cfg)
2067 {
2068         int lmf_reg, lmf_addr_reg, prev_lmf_reg;
2069         MonoInst *ins;
2070
2071         if (!cfg->lmf_ir)
2072                 return;
2073
2074         EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2075         lmf_reg = ins->dreg;
2076
2077         if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
2078                 /* Load previous_lmf */
2079                 prev_lmf_reg = alloc_preg (cfg);
2080                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
2081                 /* Set new LMF */
2082                 emit_tls_set (cfg, prev_lmf_reg, TLS_KEY_LMF);
2083         } else {
2084                 /*
2085                  * Emit IR to pop the LMF:
2086                  * *(lmf->lmf_addr) = lmf->prev_lmf
2087                  */
2088                 /* This could be called before emit_push_lmf () */
2089                 if (!cfg->lmf_addr_var)
2090                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2091                 lmf_addr_reg = cfg->lmf_addr_var->dreg;
2092
2093                 prev_lmf_reg = alloc_preg (cfg);
2094                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
2095                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_addr_reg, 0, prev_lmf_reg);
2096         }
2097 }
2098
2099 static void
2100 emit_instrumentation_call (MonoCompile *cfg, void *func)
2101 {
2102         MonoInst *iargs [1];
2103
2104         /*
2105          * Avoid instrumenting inlined methods since it can
2106          * distort profiling results.
2107          */
2108         if (cfg->method != cfg->current_method)
2109                 return;
2110
2111         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE) {
2112                 EMIT_NEW_METHODCONST (cfg, iargs [0], cfg->method);
2113                 mono_emit_jit_icall (cfg, func, iargs);
2114         }
2115 }
2116
2117 static int
2118 ret_type_to_call_opcode (MonoCompile *cfg, MonoType *type, int calli, int virt)
2119 {
2120 handle_enum:
2121         type = mini_get_underlying_type (type);
2122         switch (type->type) {
2123         case MONO_TYPE_VOID:
2124                 return calli? OP_VOIDCALL_REG: virt? OP_VOIDCALL_MEMBASE: OP_VOIDCALL;
2125         case MONO_TYPE_I1:
2126         case MONO_TYPE_U1:
2127         case MONO_TYPE_I2:
2128         case MONO_TYPE_U2:
2129         case MONO_TYPE_I4:
2130         case MONO_TYPE_U4:
2131                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2132         case MONO_TYPE_I:
2133         case MONO_TYPE_U:
2134         case MONO_TYPE_PTR:
2135         case MONO_TYPE_FNPTR:
2136                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2137         case MONO_TYPE_CLASS:
2138         case MONO_TYPE_STRING:
2139         case MONO_TYPE_OBJECT:
2140         case MONO_TYPE_SZARRAY:
2141         case MONO_TYPE_ARRAY:    
2142                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2143         case MONO_TYPE_I8:
2144         case MONO_TYPE_U8:
2145                 return calli? OP_LCALL_REG: virt? OP_LCALL_MEMBASE: OP_LCALL;
2146         case MONO_TYPE_R4:
2147                 if (cfg->r4fp)
2148                         return calli? OP_RCALL_REG: virt? OP_RCALL_MEMBASE: OP_RCALL;
2149                 else
2150                         return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
2151         case MONO_TYPE_R8:
2152                 return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
2153         case MONO_TYPE_VALUETYPE:
2154                 if (type->data.klass->enumtype) {
2155                         type = mono_class_enum_basetype (type->data.klass);
2156                         goto handle_enum;
2157                 } else
2158                         return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2159         case MONO_TYPE_TYPEDBYREF:
2160                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2161         case MONO_TYPE_GENERICINST:
2162                 type = &type->data.generic_class->container_class->byval_arg;
2163                 goto handle_enum;
2164         case MONO_TYPE_VAR:
2165         case MONO_TYPE_MVAR:
2166                 /* gsharedvt */
2167                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2168         default:
2169                 g_error ("unknown type 0x%02x in ret_type_to_call_opcode", type->type);
2170         }
2171         return -1;
2172 }
2173
2174 /*
2175  * target_type_is_incompatible:
2176  * @cfg: MonoCompile context
2177  *
2178  * Check that the item @arg on the evaluation stack can be stored
2179  * in the target type (can be a local, or field, etc).
2180  * The cfg arg can be used to check if we need verification or just
2181  * validity checks.
2182  *
2183  * Returns: non-0 value if arg can't be stored on a target.
2184  */
2185 static int
2186 target_type_is_incompatible (MonoCompile *cfg, MonoType *target, MonoInst *arg)
2187 {
2188         MonoType *simple_type;
2189         MonoClass *klass;
2190
2191         if (target->byref) {
2192                 /* FIXME: check that the pointed to types match */
2193                 if (arg->type == STACK_MP)
2194                         return target->type != MONO_TYPE_I && arg->klass != mono_class_from_mono_type (target);
2195                 if (arg->type == STACK_PTR)
2196                         return 0;
2197                 return 1;
2198         }
2199
2200         simple_type = mini_get_underlying_type (target);
2201         switch (simple_type->type) {
2202         case MONO_TYPE_VOID:
2203                 return 1;
2204         case MONO_TYPE_I1:
2205         case MONO_TYPE_U1:
2206         case MONO_TYPE_I2:
2207         case MONO_TYPE_U2:
2208         case MONO_TYPE_I4:
2209         case MONO_TYPE_U4:
2210                 if (arg->type != STACK_I4 && arg->type != STACK_PTR)
2211                         return 1;
2212                 return 0;
2213         case MONO_TYPE_PTR:
2214                 /* STACK_MP is needed when setting pinned locals */
2215                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2216                         return 1;
2217                 return 0;
2218         case MONO_TYPE_I:
2219         case MONO_TYPE_U:
2220         case MONO_TYPE_FNPTR:
2221                 /* 
2222                  * Some opcodes like ldloca returns 'transient pointers' which can be stored in
2223                  * in native int. (#688008).
2224                  */
2225                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2226                         return 1;
2227                 return 0;
2228         case MONO_TYPE_CLASS:
2229         case MONO_TYPE_STRING:
2230         case MONO_TYPE_OBJECT:
2231         case MONO_TYPE_SZARRAY:
2232         case MONO_TYPE_ARRAY:    
2233                 if (arg->type != STACK_OBJ)
2234                         return 1;
2235                 /* FIXME: check type compatibility */
2236                 return 0;
2237         case MONO_TYPE_I8:
2238         case MONO_TYPE_U8:
2239                 if (arg->type != STACK_I8)
2240                         return 1;
2241                 return 0;
2242         case MONO_TYPE_R4:
2243                 if (arg->type != cfg->r4_stack_type)
2244                         return 1;
2245                 return 0;
2246         case MONO_TYPE_R8:
2247                 if (arg->type != STACK_R8)
2248                         return 1;
2249                 return 0;
2250         case MONO_TYPE_VALUETYPE:
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_TYPEDBYREF:
2258                 if (arg->type != STACK_VTYPE)
2259                         return 1;
2260                 klass = mono_class_from_mono_type (simple_type);
2261                 if (klass != arg->klass)
2262                         return 1;
2263                 return 0;
2264         case MONO_TYPE_GENERICINST:
2265                 if (mono_type_generic_inst_is_valuetype (simple_type)) {
2266                         if (arg->type != STACK_VTYPE)
2267                                 return 1;
2268                         klass = mono_class_from_mono_type (simple_type);
2269                         /* The second cases is needed when doing partial sharing */
2270                         if (klass != arg->klass && mono_class_from_mono_type (target) != arg->klass)
2271                                 return 1;
2272                         return 0;
2273                 } else {
2274                         if (arg->type != STACK_OBJ)
2275                                 return 1;
2276                         /* FIXME: check type compatibility */
2277                         return 0;
2278                 }
2279         case MONO_TYPE_VAR:
2280         case MONO_TYPE_MVAR:
2281                 g_assert (cfg->gshared);
2282                 if (mini_type_var_is_vt (simple_type)) {
2283                         if (arg->type != STACK_VTYPE)
2284                                 return 1;
2285                 } else {
2286                         if (arg->type != STACK_OBJ)
2287                                 return 1;
2288                 }
2289                 return 0;
2290         default:
2291                 g_error ("unknown type 0x%02x in target_type_is_incompatible", simple_type->type);
2292         }
2293         return 1;
2294 }
2295
2296 /*
2297  * Prepare arguments for passing to a function call.
2298  * Return a non-zero value if the arguments can't be passed to the given
2299  * signature.
2300  * The type checks are not yet complete and some conversions may need
2301  * casts on 32 or 64 bit architectures.
2302  *
2303  * FIXME: implement this using target_type_is_incompatible ()
2304  */
2305 static int
2306 check_call_signature (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args)
2307 {
2308         MonoType *simple_type;
2309         int i;
2310
2311         if (sig->hasthis) {
2312                 if (args [0]->type != STACK_OBJ && args [0]->type != STACK_MP && args [0]->type != STACK_PTR)
2313                         return 1;
2314                 args++;
2315         }
2316         for (i = 0; i < sig->param_count; ++i) {
2317                 if (sig->params [i]->byref) {
2318                         if (args [i]->type != STACK_MP && args [i]->type != STACK_PTR)
2319                                 return 1;
2320                         continue;
2321                 }
2322                 simple_type = mini_get_underlying_type (sig->params [i]);
2323 handle_enum:
2324                 switch (simple_type->type) {
2325                 case MONO_TYPE_VOID:
2326                         return 1;
2327                         continue;
2328                 case MONO_TYPE_I1:
2329                 case MONO_TYPE_U1:
2330                 case MONO_TYPE_I2:
2331                 case MONO_TYPE_U2:
2332                 case MONO_TYPE_I4:
2333                 case MONO_TYPE_U4:
2334                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR)
2335                                 return 1;
2336                         continue;
2337                 case MONO_TYPE_I:
2338                 case MONO_TYPE_U:
2339                 case MONO_TYPE_PTR:
2340                 case MONO_TYPE_FNPTR:
2341                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR && args [i]->type != STACK_MP && args [i]->type != STACK_OBJ)
2342                                 return 1;
2343                         continue;
2344                 case MONO_TYPE_CLASS:
2345                 case MONO_TYPE_STRING:
2346                 case MONO_TYPE_OBJECT:
2347                 case MONO_TYPE_SZARRAY:
2348                 case MONO_TYPE_ARRAY:    
2349                         if (args [i]->type != STACK_OBJ)
2350                                 return 1;
2351                         continue;
2352                 case MONO_TYPE_I8:
2353                 case MONO_TYPE_U8:
2354                         if (args [i]->type != STACK_I8)
2355                                 return 1;
2356                         continue;
2357                 case MONO_TYPE_R4:
2358                         if (args [i]->type != cfg->r4_stack_type)
2359                                 return 1;
2360                         continue;
2361                 case MONO_TYPE_R8:
2362                         if (args [i]->type != STACK_R8)
2363                                 return 1;
2364                         continue;
2365                 case MONO_TYPE_VALUETYPE:
2366                         if (simple_type->data.klass->enumtype) {
2367                                 simple_type = mono_class_enum_basetype (simple_type->data.klass);
2368                                 goto handle_enum;
2369                         }
2370                         if (args [i]->type != STACK_VTYPE)
2371                                 return 1;
2372                         continue;
2373                 case MONO_TYPE_TYPEDBYREF:
2374                         if (args [i]->type != STACK_VTYPE)
2375                                 return 1;
2376                         continue;
2377                 case MONO_TYPE_GENERICINST:
2378                         simple_type = &simple_type->data.generic_class->container_class->byval_arg;
2379                         goto handle_enum;
2380                 case MONO_TYPE_VAR:
2381                 case MONO_TYPE_MVAR:
2382                         /* gsharedvt */
2383                         if (args [i]->type != STACK_VTYPE)
2384                                 return 1;
2385                         continue;
2386                 default:
2387                         g_error ("unknown type 0x%02x in check_call_signature",
2388                                  simple_type->type);
2389                 }
2390         }
2391         return 0;
2392 }
2393
2394 static int
2395 callvirt_to_call (int opcode)
2396 {
2397         switch (opcode) {
2398         case OP_CALL_MEMBASE:
2399                 return OP_CALL;
2400         case OP_VOIDCALL_MEMBASE:
2401                 return OP_VOIDCALL;
2402         case OP_FCALL_MEMBASE:
2403                 return OP_FCALL;
2404         case OP_RCALL_MEMBASE:
2405                 return OP_RCALL;
2406         case OP_VCALL_MEMBASE:
2407                 return OP_VCALL;
2408         case OP_LCALL_MEMBASE:
2409                 return OP_LCALL;
2410         default:
2411                 g_assert_not_reached ();
2412         }
2413
2414         return -1;
2415 }
2416
2417 static int
2418 callvirt_to_call_reg (int opcode)
2419 {
2420         switch (opcode) {
2421         case OP_CALL_MEMBASE:
2422                 return OP_CALL_REG;
2423         case OP_VOIDCALL_MEMBASE:
2424                 return OP_VOIDCALL_REG;
2425         case OP_FCALL_MEMBASE:
2426                 return OP_FCALL_REG;
2427         case OP_RCALL_MEMBASE:
2428                 return OP_RCALL_REG;
2429         case OP_VCALL_MEMBASE:
2430                 return OP_VCALL_REG;
2431         case OP_LCALL_MEMBASE:
2432                 return OP_LCALL_REG;
2433         default:
2434                 g_assert_not_reached ();
2435         }
2436
2437         return -1;
2438 }
2439
2440 /* Either METHOD or IMT_ARG needs to be set */
2441 static void
2442 emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoMethod *method, MonoInst *imt_arg)
2443 {
2444         int method_reg;
2445
2446         if (COMPILE_LLVM (cfg)) {
2447                 if (imt_arg) {
2448                         method_reg = alloc_preg (cfg);
2449                         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2450                 } else {
2451                         MonoInst *ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_METHODCONST, method);
2452                         method_reg = ins->dreg;
2453                 }
2454
2455 #ifdef ENABLE_LLVM
2456                 call->imt_arg_reg = method_reg;
2457 #endif
2458                 mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2459                 return;
2460         }
2461
2462         if (imt_arg) {
2463                 method_reg = alloc_preg (cfg);
2464                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2465         } else {
2466                 MonoInst *ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_METHODCONST, method);
2467                 method_reg = ins->dreg;
2468         }
2469
2470         mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2471 }
2472
2473 static MonoJumpInfo *
2474 mono_patch_info_new (MonoMemPool *mp, int ip, MonoJumpInfoType type, gconstpointer target)
2475 {
2476         MonoJumpInfo *ji = mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
2477
2478         ji->ip.i = ip;
2479         ji->type = type;
2480         ji->data.target = target;
2481
2482         return ji;
2483 }
2484
2485 static int
2486 mini_class_check_context_used (MonoCompile *cfg, MonoClass *klass)
2487 {
2488         if (cfg->gshared)
2489                 return mono_class_check_context_used (klass);
2490         else
2491                 return 0;
2492 }
2493
2494 static int
2495 mini_method_check_context_used (MonoCompile *cfg, MonoMethod *method)
2496 {
2497         if (cfg->gshared)
2498                 return mono_method_check_context_used (method);
2499         else
2500                 return 0;
2501 }
2502
2503 /*
2504  * check_method_sharing:
2505  *
2506  *   Check whenever the vtable or an mrgctx needs to be passed when calling CMETHOD.
2507  */
2508 static void
2509 check_method_sharing (MonoCompile *cfg, MonoMethod *cmethod, gboolean *out_pass_vtable, gboolean *out_pass_mrgctx)
2510 {
2511         gboolean pass_vtable = FALSE;
2512         gboolean pass_mrgctx = FALSE;
2513
2514         if (((cmethod->flags & METHOD_ATTRIBUTE_STATIC) || cmethod->klass->valuetype) &&
2515                 (cmethod->klass->generic_class || cmethod->klass->generic_container)) {
2516                 gboolean sharable = FALSE;
2517
2518                 if (mono_method_is_generic_sharable_full (cmethod, TRUE, TRUE, TRUE))
2519                         sharable = TRUE;
2520
2521                 /*
2522                  * Pass vtable iff target method might
2523                  * be shared, which means that sharing
2524                  * is enabled for its class and its
2525                  * context is sharable (and it's not a
2526                  * generic method).
2527                  */
2528                 if (sharable && !(mini_method_get_context (cmethod) && mini_method_get_context (cmethod)->method_inst))
2529                         pass_vtable = TRUE;
2530         }
2531
2532         if (mini_method_get_context (cmethod) &&
2533                 mini_method_get_context (cmethod)->method_inst) {
2534                 g_assert (!pass_vtable);
2535
2536                 if (mono_method_is_generic_sharable_full (cmethod, TRUE, TRUE, TRUE)) {
2537                         pass_mrgctx = TRUE;
2538                 } else {
2539                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (mono_method_signature (cmethod)))
2540                                 pass_mrgctx = TRUE;
2541                 }
2542         }
2543
2544         if (out_pass_vtable)
2545                 *out_pass_vtable = pass_vtable;
2546         if (out_pass_mrgctx)
2547                 *out_pass_mrgctx = pass_mrgctx;
2548 }
2549
2550 inline static MonoCallInst *
2551 mono_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig, 
2552                                          MonoInst **args, int calli, int virtual, int tail, int rgctx, int unbox_trampoline)
2553 {
2554         MonoType *sig_ret;
2555         MonoCallInst *call;
2556 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2557         int i;
2558 #endif
2559
2560         if (cfg->llvm_only)
2561                 tail = FALSE;
2562
2563         if (tail) {
2564                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
2565
2566                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
2567         } else
2568                 MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (cfg, sig->ret, calli, virtual));
2569
2570         call->args = args;
2571         call->signature = sig;
2572         call->rgctx_reg = rgctx;
2573         sig_ret = mini_get_underlying_type (sig->ret);
2574
2575         type_to_eval_stack_type ((cfg), sig_ret, &call->inst);
2576
2577         if (tail) {
2578                 if (mini_type_is_vtype (sig_ret)) {
2579                         call->vret_var = cfg->vret_addr;
2580                         //g_assert_not_reached ();
2581                 }
2582         } else if (mini_type_is_vtype (sig_ret)) {
2583                 MonoInst *temp = mono_compile_create_var (cfg, sig_ret, OP_LOCAL);
2584                 MonoInst *loada;
2585
2586                 temp->backend.is_pinvoke = sig->pinvoke;
2587
2588                 /*
2589                  * We use a new opcode OP_OUTARG_VTRETADDR instead of LDADDR for emitting the
2590                  * address of return value to increase optimization opportunities.
2591                  * Before vtype decomposition, the dreg of the call ins itself represents the
2592                  * fact the call modifies the return value. After decomposition, the call will
2593                  * be transformed into one of the OP_VOIDCALL opcodes, and the VTRETADDR opcode
2594                  * will be transformed into an LDADDR.
2595                  */
2596                 MONO_INST_NEW (cfg, loada, OP_OUTARG_VTRETADDR);
2597                 loada->dreg = alloc_preg (cfg);
2598                 loada->inst_p0 = temp;
2599                 /* We reference the call too since call->dreg could change during optimization */
2600                 loada->inst_p1 = call;
2601                 MONO_ADD_INS (cfg->cbb, loada);
2602
2603                 call->inst.dreg = temp->dreg;
2604
2605                 call->vret_var = loada;
2606         } else if (!MONO_TYPE_IS_VOID (sig_ret))
2607                 call->inst.dreg = alloc_dreg (cfg, call->inst.type);
2608
2609 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2610         if (COMPILE_SOFT_FLOAT (cfg)) {
2611                 /* 
2612                  * If the call has a float argument, we would need to do an r8->r4 conversion using 
2613                  * an icall, but that cannot be done during the call sequence since it would clobber
2614                  * the call registers + the stack. So we do it before emitting the call.
2615                  */
2616                 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2617                         MonoType *t;
2618                         MonoInst *in = call->args [i];
2619
2620                         if (i >= sig->hasthis)
2621                                 t = sig->params [i - sig->hasthis];
2622                         else
2623                                 t = &mono_defaults.int_class->byval_arg;
2624                         t = mono_type_get_underlying_type (t);
2625
2626                         if (!t->byref && t->type == MONO_TYPE_R4) {
2627                                 MonoInst *iargs [1];
2628                                 MonoInst *conv;
2629
2630                                 iargs [0] = in;
2631                                 conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
2632
2633                                 /* The result will be in an int vreg */
2634                                 call->args [i] = conv;
2635                         }
2636                 }
2637         }
2638 #endif
2639
2640         call->need_unbox_trampoline = unbox_trampoline;
2641
2642 #ifdef ENABLE_LLVM
2643         if (COMPILE_LLVM (cfg))
2644                 mono_llvm_emit_call (cfg, call);
2645         else
2646                 mono_arch_emit_call (cfg, call);
2647 #else
2648         mono_arch_emit_call (cfg, call);
2649 #endif
2650
2651         cfg->param_area = MAX (cfg->param_area, call->stack_usage);
2652         cfg->flags |= MONO_CFG_HAS_CALLS;
2653         
2654         return call;
2655 }
2656
2657 static void
2658 set_rgctx_arg (MonoCompile *cfg, MonoCallInst *call, int rgctx_reg, MonoInst *rgctx_arg)
2659 {
2660         mono_call_inst_add_outarg_reg (cfg, call, rgctx_reg, MONO_ARCH_RGCTX_REG, FALSE);
2661         cfg->uses_rgctx_reg = TRUE;
2662         call->rgctx_reg = TRUE;
2663 #ifdef ENABLE_LLVM
2664         call->rgctx_arg_reg = rgctx_reg;
2665 #endif
2666 }       
2667
2668 inline static MonoInst*
2669 mono_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr, MonoInst *imt_arg, MonoInst *rgctx_arg)
2670 {
2671         MonoCallInst *call;
2672         MonoInst *ins;
2673         int rgctx_reg = -1;
2674         gboolean check_sp = FALSE;
2675
2676         if (cfg->check_pinvoke_callconv && cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
2677                 WrapperInfo *info = mono_marshal_get_wrapper_info (cfg->method);
2678
2679                 if (info && info->subtype == WRAPPER_SUBTYPE_PINVOKE)
2680                         check_sp = TRUE;
2681         }
2682
2683         if (rgctx_arg) {
2684                 rgctx_reg = mono_alloc_preg (cfg);
2685                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2686         }
2687
2688         if (check_sp) {
2689                 if (!cfg->stack_inbalance_var)
2690                         cfg->stack_inbalance_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2691
2692                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2693                 ins->dreg = cfg->stack_inbalance_var->dreg;
2694                 MONO_ADD_INS (cfg->cbb, ins);
2695         }
2696
2697         call = mono_emit_call_args (cfg, sig, args, TRUE, FALSE, FALSE, rgctx_arg ? TRUE : FALSE, FALSE);
2698
2699         call->inst.sreg1 = addr->dreg;
2700
2701         if (imt_arg)
2702                 emit_imt_argument (cfg, call, NULL, imt_arg);
2703
2704         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2705
2706         if (check_sp) {
2707                 int sp_reg;
2708
2709                 sp_reg = mono_alloc_preg (cfg);
2710
2711                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2712                 ins->dreg = sp_reg;
2713                 MONO_ADD_INS (cfg->cbb, ins);
2714
2715                 /* Restore the stack so we don't crash when throwing the exception */
2716                 MONO_INST_NEW (cfg, ins, OP_SET_SP);
2717                 ins->sreg1 = cfg->stack_inbalance_var->dreg;
2718                 MONO_ADD_INS (cfg->cbb, ins);
2719
2720                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, cfg->stack_inbalance_var->dreg, sp_reg);
2721                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ExecutionEngineException");
2722         }
2723
2724         if (rgctx_arg)
2725                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2726
2727         return (MonoInst*)call;
2728 }
2729
2730 static MonoInst*
2731 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2732
2733 static MonoInst*
2734 emit_get_rgctx_method (MonoCompile *cfg, int context_used, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type);
2735 static MonoInst*
2736 emit_get_rgctx_klass (MonoCompile *cfg, int context_used, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2737
2738 static MonoInst*
2739 mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSignature *sig, gboolean tail,
2740                                                         MonoInst **args, MonoInst *this_ins, MonoInst *imt_arg, MonoInst *rgctx_arg)
2741 {
2742 #ifndef DISABLE_REMOTING
2743         gboolean might_be_remote = FALSE;
2744 #endif
2745         gboolean virtual = this_ins != NULL;
2746         gboolean enable_for_aot = TRUE;
2747         int context_used;
2748         MonoCallInst *call;
2749         MonoInst *call_target = NULL;
2750         int rgctx_reg = 0;
2751         gboolean need_unbox_trampoline;
2752
2753         if (!sig)
2754                 sig = mono_method_signature (method);
2755
2756         if (cfg->llvm_only && (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2757                 MonoInst *icall_args [16];
2758                 MonoInst *ins;
2759
2760                 // FIXME: Optimize this
2761
2762                 guint32 imt_slot = mono_method_get_imt_slot (method);
2763
2764                 icall_args [0] = this_ins;
2765                 EMIT_NEW_ICONST (cfg, icall_args [1], imt_slot);
2766                 if (imt_arg) {
2767                         icall_args [2] = imt_arg;
2768                 } else {
2769                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_METHODCONST, method);
2770                         icall_args [2] = ins;
2771                 }
2772                 EMIT_NEW_PCONST (cfg, icall_args [3], NULL);
2773
2774                 call_target = mono_emit_jit_icall (cfg, mono_resolve_iface_call, icall_args);
2775         }
2776
2777         if (rgctx_arg) {
2778                 rgctx_reg = mono_alloc_preg (cfg);
2779                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2780         }
2781
2782         if (method->string_ctor) {
2783                 /* Create the real signature */
2784                 /* FIXME: Cache these */
2785                 MonoMethodSignature *ctor_sig = mono_metadata_signature_dup_mempool (cfg->mempool, sig);
2786                 ctor_sig->ret = &mono_defaults.string_class->byval_arg;
2787
2788                 sig = ctor_sig;
2789         }
2790
2791         context_used = mini_method_check_context_used (cfg, method);
2792
2793 #ifndef DISABLE_REMOTING
2794         might_be_remote = this_ins && sig->hasthis &&
2795                 (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) &&
2796                 !(method->flags & METHOD_ATTRIBUTE_VIRTUAL) && (!MONO_CHECK_THIS (this_ins) || context_used);
2797
2798         if (might_be_remote && context_used) {
2799                 MonoInst *addr;
2800
2801                 g_assert (cfg->gshared);
2802
2803                 addr = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK);
2804
2805                 return mono_emit_calli (cfg, sig, args, addr, NULL, NULL);
2806         }
2807 #endif
2808
2809         if (cfg->llvm_only && !call_target && virtual && (method->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
2810                 // FIXME: Vcall optimizations below
2811                 MonoInst *icall_args [16];
2812                 MonoInst *ins;
2813
2814                 if (sig->generic_param_count) {
2815                         /*
2816                          * Generic virtual call, pass the concrete method as the imt argument.
2817                          */
2818                         imt_arg = emit_get_rgctx_method (cfg, context_used,
2819                                                                                          method, MONO_RGCTX_INFO_METHOD);
2820                 }
2821
2822                 // FIXME: Optimize this
2823
2824                 int slot = mono_method_get_vtable_index (method);
2825
2826                 icall_args [0] = this_ins;
2827                 EMIT_NEW_ICONST (cfg, icall_args [1], slot);
2828                 if (imt_arg) {
2829                         icall_args [2] = imt_arg;
2830                 } else {
2831                         EMIT_NEW_PCONST (cfg, ins, NULL);
2832                         icall_args [2] = ins;
2833                 }
2834                 call_target = mono_emit_jit_icall (cfg, mono_resolve_vcall, icall_args);
2835         }
2836
2837         need_unbox_trampoline = method->klass == mono_defaults.object_class || (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE);
2838
2839         call = mono_emit_call_args (cfg, sig, args, FALSE, virtual, tail, rgctx_arg ? TRUE : FALSE, need_unbox_trampoline);
2840
2841 #ifndef DISABLE_REMOTING
2842         if (might_be_remote)
2843                 call->method = mono_marshal_get_remoting_invoke_with_check (method);
2844         else
2845 #endif
2846                 call->method = method;
2847         call->inst.flags |= MONO_INST_HAS_METHOD;
2848         call->inst.inst_left = this_ins;
2849         call->tail_call = tail;
2850
2851         if (virtual) {
2852                 int vtable_reg, slot_reg, this_reg;
2853                 int offset;
2854
2855                 this_reg = this_ins->dreg;
2856
2857                 if (!cfg->llvm_only && (method->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (method->name, "Invoke")) {
2858                         MonoInst *dummy_use;
2859
2860                         MONO_EMIT_NULL_CHECK (cfg, this_reg);
2861
2862                         /* Make a call to delegate->invoke_impl */
2863                         call->inst.inst_basereg = this_reg;
2864                         call->inst.inst_offset = MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl);
2865                         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2866
2867                         /* We must emit a dummy use here because the delegate trampoline will
2868                         replace the 'this' argument with the delegate target making this activation
2869                         no longer a root for the delegate.
2870                         This is an issue for delegates that target collectible code such as dynamic
2871                         methods of GC'able assemblies.
2872
2873                         For a test case look into #667921.
2874
2875                         FIXME: a dummy use is not the best way to do it as the local register allocator
2876                         will put it on a caller save register and spil it around the call. 
2877                         Ideally, we would either put it on a callee save register or only do the store part.  
2878                          */
2879                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, args [0]);
2880
2881                         return (MonoInst*)call;
2882                 }
2883
2884                 if ((!cfg->compile_aot || enable_for_aot) && 
2885                         (!(method->flags & METHOD_ATTRIBUTE_VIRTUAL) || 
2886                          (MONO_METHOD_IS_FINAL (method) &&
2887                           method->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)) &&
2888                         !(mono_class_is_marshalbyref (method->klass) && context_used)) {
2889                         /* 
2890                          * the method is not virtual, we just need to ensure this is not null
2891                          * and then we can call the method directly.
2892                          */
2893 #ifndef DISABLE_REMOTING
2894                         if (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) {
2895                                 /* 
2896                                  * The check above ensures method is not gshared, this is needed since
2897                                  * gshared methods can't have wrappers.
2898                                  */
2899                                 method = call->method = mono_marshal_get_remoting_invoke_with_check (method);
2900                         }
2901 #endif
2902
2903                         if (!method->string_ctor)
2904                                 MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2905
2906                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2907                 } else if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && MONO_METHOD_IS_FINAL (method)) {
2908                         /*
2909                          * the method is virtual, but we can statically dispatch since either
2910                          * it's class or the method itself are sealed.
2911                          * But first we need to ensure it's not a null reference.
2912                          */
2913                         MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2914
2915                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2916                 } else if (call_target) {
2917                         vtable_reg = alloc_preg (cfg);
2918                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
2919
2920                         call->inst.opcode = callvirt_to_call_reg (call->inst.opcode);
2921                         call->inst.sreg1 = call_target->dreg;
2922                         call->inst.flags &= !MONO_INST_HAS_METHOD;
2923                 } else {
2924                         vtable_reg = alloc_preg (cfg);
2925                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
2926                         if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2927                                 guint32 imt_slot = mono_method_get_imt_slot (method);
2928                                 emit_imt_argument (cfg, call, call->method, imt_arg);
2929                                 slot_reg = vtable_reg;
2930                                 offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
2931                         } else {
2932                                 slot_reg = vtable_reg;
2933                                 offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) +
2934                                         ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
2935                                 if (imt_arg) {
2936                                         g_assert (mono_method_signature (method)->generic_param_count);
2937                                         emit_imt_argument (cfg, call, call->method, imt_arg);
2938                                 }
2939                         }
2940
2941                         call->inst.sreg1 = slot_reg;
2942                         call->inst.inst_offset = offset;
2943                         call->is_virtual = TRUE;
2944                 }
2945         }
2946
2947         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2948
2949         if (rgctx_arg)
2950                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2951
2952         return (MonoInst*)call;
2953 }
2954
2955 MonoInst*
2956 mono_emit_method_call (MonoCompile *cfg, MonoMethod *method, MonoInst **args, MonoInst *this_ins)
2957 {
2958         return mono_emit_method_call_full (cfg, method, mono_method_signature (method), FALSE, args, this_ins, NULL, NULL);
2959 }
2960
2961 MonoInst*
2962 mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig,
2963                                            MonoInst **args)
2964 {
2965         MonoCallInst *call;
2966
2967         g_assert (sig);
2968
2969         call = mono_emit_call_args (cfg, sig, args, FALSE, FALSE, FALSE, FALSE, FALSE);
2970         call->fptr = func;
2971
2972         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2973
2974         return (MonoInst*)call;
2975 }
2976
2977 MonoInst*
2978 mono_emit_jit_icall (MonoCompile *cfg, gconstpointer func, MonoInst **args)
2979 {
2980         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (func);
2981
2982         g_assert (info);
2983
2984         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
2985 }
2986
2987 /*
2988  * mono_emit_abs_call:
2989  *
2990  *   Emit a call to the runtime function described by PATCH_TYPE and DATA.
2991  */
2992 inline static MonoInst*
2993 mono_emit_abs_call (MonoCompile *cfg, MonoJumpInfoType patch_type, gconstpointer data, 
2994                                         MonoMethodSignature *sig, MonoInst **args)
2995 {
2996         MonoJumpInfo *ji = mono_patch_info_new (cfg->mempool, 0, patch_type, data);
2997         MonoInst *ins;
2998
2999         /* 
3000          * We pass ji as the call address, the PATCH_INFO_ABS resolving code will
3001          * handle it.
3002          */
3003         if (cfg->abs_patches == NULL)
3004                 cfg->abs_patches = g_hash_table_new (NULL, NULL);
3005         g_hash_table_insert (cfg->abs_patches, ji, ji);
3006         ins = mono_emit_native_call (cfg, ji, sig, args);
3007         ((MonoCallInst*)ins)->fptr_is_patch = TRUE;
3008         return ins;
3009 }
3010
3011 static gboolean
3012 direct_icalls_enabled (MonoCompile *cfg)
3013 {
3014         /* LLVM on amd64 can't handle calls to non-32 bit addresses */
3015 #ifdef TARGET_AMD64
3016         if (cfg->compile_llvm)
3017                 return FALSE;
3018 #endif
3019         if (cfg->gen_sdb_seq_points || cfg->disable_direct_icalls)
3020                 return FALSE;
3021         return TRUE;
3022 }
3023
3024 MonoInst*
3025 mono_emit_jit_icall_by_info (MonoCompile *cfg, MonoJitICallInfo *info, MonoInst **args)
3026 {
3027         /*
3028          * Call the jit icall without a wrapper if possible.
3029          * The wrapper is needed for the following reasons:
3030          * - to handle exceptions thrown using mono_raise_exceptions () from the
3031          *   icall function. The EH code needs the lmf frame pushed by the
3032          *   wrapper to be able to unwind back to managed code.
3033          * - to be able to do stack walks for asynchronously suspended
3034          *   threads when debugging.
3035          */
3036         if (info->no_raise && direct_icalls_enabled (cfg)) {
3037                 char *name;
3038                 int costs;
3039
3040                 if (!info->wrapper_method) {
3041                         name = g_strdup_printf ("__icall_wrapper_%s", info->name);
3042                         info->wrapper_method = mono_marshal_get_icall_wrapper (info->sig, name, info->func, TRUE);
3043                         g_free (name);
3044                         mono_memory_barrier ();
3045                 }
3046
3047                 /*
3048                  * Inline the wrapper method, which is basically a call to the C icall, and
3049                  * an exception check.
3050                  */
3051                 costs = inline_method (cfg, info->wrapper_method, NULL,
3052                                                            args, NULL, cfg->real_offset, TRUE);
3053                 g_assert (costs > 0);
3054                 g_assert (!MONO_TYPE_IS_VOID (info->sig->ret));
3055
3056                 return args [0];
3057         } else {
3058                 return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
3059         }
3060 }
3061  
3062 static MonoInst*
3063 mono_emit_widen_call_res (MonoCompile *cfg, MonoInst *ins, MonoMethodSignature *fsig)
3064 {
3065         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
3066                 if ((fsig->pinvoke || LLVM_ENABLED) && !fsig->ret->byref) {
3067                         int widen_op = -1;
3068
3069                         /* 
3070                          * Native code might return non register sized integers 
3071                          * without initializing the upper bits.
3072                          */
3073                         switch (mono_type_to_load_membase (cfg, fsig->ret)) {
3074                         case OP_LOADI1_MEMBASE:
3075                                 widen_op = OP_ICONV_TO_I1;
3076                                 break;
3077                         case OP_LOADU1_MEMBASE:
3078                                 widen_op = OP_ICONV_TO_U1;
3079                                 break;
3080                         case OP_LOADI2_MEMBASE:
3081                                 widen_op = OP_ICONV_TO_I2;
3082                                 break;
3083                         case OP_LOADU2_MEMBASE:
3084                                 widen_op = OP_ICONV_TO_U2;
3085                                 break;
3086                         default:
3087                                 break;
3088                         }
3089
3090                         if (widen_op != -1) {
3091                                 int dreg = alloc_preg (cfg);
3092                                 MonoInst *widen;
3093
3094                                 EMIT_NEW_UNALU (cfg, widen, widen_op, dreg, ins->dreg);
3095                                 widen->type = ins->type;
3096                                 ins = widen;
3097                         }
3098                 }
3099         }
3100
3101         return ins;
3102 }
3103
3104 static MonoMethod*
3105 get_memcpy_method (void)
3106 {
3107         static MonoMethod *memcpy_method = NULL;
3108         if (!memcpy_method) {
3109                 memcpy_method = mono_class_get_method_from_name (mono_defaults.string_class, "memcpy", 3);
3110                 if (!memcpy_method)
3111                         g_error ("Old corlib found. Install a new one");
3112         }
3113         return memcpy_method;
3114 }
3115
3116 static void
3117 create_write_barrier_bitmap (MonoCompile *cfg, MonoClass *klass, unsigned *wb_bitmap, int offset)
3118 {
3119         MonoClassField *field;
3120         gpointer iter = NULL;
3121
3122         while ((field = mono_class_get_fields (klass, &iter))) {
3123                 int foffset;
3124
3125                 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
3126                         continue;
3127                 foffset = klass->valuetype ? field->offset - sizeof (MonoObject): field->offset;
3128                 if (mini_type_is_reference (mono_field_get_type (field))) {
3129                         g_assert ((foffset % SIZEOF_VOID_P) == 0);
3130                         *wb_bitmap |= 1 << ((offset + foffset) / SIZEOF_VOID_P);
3131                 } else {
3132                         MonoClass *field_class = mono_class_from_mono_type (field->type);
3133                         if (field_class->has_references)
3134                                 create_write_barrier_bitmap (cfg, field_class, wb_bitmap, offset + foffset);
3135                 }
3136         }
3137 }
3138
3139 static void
3140 emit_write_barrier (MonoCompile *cfg, MonoInst *ptr, MonoInst *value)
3141 {
3142         int card_table_shift_bits;
3143         gpointer card_table_mask;
3144         guint8 *card_table;
3145         MonoInst *dummy_use;
3146         int nursery_shift_bits;
3147         size_t nursery_size;
3148
3149         if (!cfg->gen_write_barriers)
3150                 return;
3151
3152         card_table = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
3153
3154         mono_gc_get_nursery (&nursery_shift_bits, &nursery_size);
3155
3156         if (cfg->backend->have_card_table_wb && !cfg->compile_aot && card_table && nursery_shift_bits > 0 && !COMPILE_LLVM (cfg)) {
3157                 MonoInst *wbarrier;
3158
3159                 MONO_INST_NEW (cfg, wbarrier, OP_CARD_TABLE_WBARRIER);
3160                 wbarrier->sreg1 = ptr->dreg;
3161                 wbarrier->sreg2 = value->dreg;
3162                 MONO_ADD_INS (cfg->cbb, wbarrier);
3163         } else if (card_table && !cfg->compile_aot && !mono_gc_card_table_nursery_check ()) {
3164                 int offset_reg = alloc_preg (cfg);
3165                 int card_reg;
3166                 MonoInst *ins;
3167
3168                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, offset_reg, ptr->dreg, card_table_shift_bits);
3169                 if (card_table_mask)
3170                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, offset_reg, offset_reg, card_table_mask);
3171
3172                 /*We can't use PADD_IMM since the cardtable might end up in high addresses and amd64 doesn't support
3173                  * IMM's larger than 32bits.
3174                  */
3175                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR, NULL);
3176                 card_reg = ins->dreg;
3177
3178                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, offset_reg, offset_reg, card_reg);
3179                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, offset_reg, 0, 1);
3180         } else {
3181                 MonoMethod *write_barrier = mono_gc_get_write_barrier ();
3182                 mono_emit_method_call (cfg, write_barrier, &ptr, NULL);
3183         }
3184
3185         EMIT_NEW_DUMMY_USE (cfg, dummy_use, value);
3186 }
3187
3188 static gboolean
3189 mono_emit_wb_aware_memcpy (MonoCompile *cfg, MonoClass *klass, MonoInst *iargs[4], int size, int align)
3190 {
3191         int dest_ptr_reg, tmp_reg, destreg, srcreg, offset;
3192         unsigned need_wb = 0;
3193
3194         if (align == 0)
3195                 align = 4;
3196
3197         /*types with references can't have alignment smaller than sizeof(void*) */
3198         if (align < SIZEOF_VOID_P)
3199                 return FALSE;
3200
3201         /*This value cannot be bigger than 32 due to the way we calculate the required wb bitmap.*/
3202         if (size > 32 * SIZEOF_VOID_P)
3203                 return FALSE;
3204
3205         create_write_barrier_bitmap (cfg, klass, &need_wb, 0);
3206
3207         /* We don't unroll more than 5 stores to avoid code bloat. */
3208         if (size > 5 * SIZEOF_VOID_P) {
3209                 /*This is harmless and simplify mono_gc_wbarrier_value_copy_bitmap */
3210                 size += (SIZEOF_VOID_P - 1);
3211                 size &= ~(SIZEOF_VOID_P - 1);
3212
3213                 EMIT_NEW_ICONST (cfg, iargs [2], size);
3214                 EMIT_NEW_ICONST (cfg, iargs [3], need_wb);
3215                 mono_emit_jit_icall (cfg, mono_gc_wbarrier_value_copy_bitmap, iargs);
3216                 return TRUE;
3217         }
3218
3219         destreg = iargs [0]->dreg;
3220         srcreg = iargs [1]->dreg;
3221         offset = 0;
3222
3223         dest_ptr_reg = alloc_preg (cfg);
3224         tmp_reg = alloc_preg (cfg);
3225
3226         /*tmp = dreg*/
3227         EMIT_NEW_UNALU (cfg, iargs [0], OP_MOVE, dest_ptr_reg, destreg);
3228
3229         while (size >= SIZEOF_VOID_P) {
3230                 MonoInst *load_inst;
3231                 MONO_INST_NEW (cfg, load_inst, OP_LOAD_MEMBASE);
3232                 load_inst->dreg = tmp_reg;
3233                 load_inst->inst_basereg = srcreg;
3234                 load_inst->inst_offset = offset;
3235                 MONO_ADD_INS (cfg->cbb, load_inst);
3236
3237                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, dest_ptr_reg, 0, tmp_reg);
3238
3239                 if (need_wb & 0x1)
3240                         emit_write_barrier (cfg, iargs [0], load_inst);
3241
3242                 offset += SIZEOF_VOID_P;
3243                 size -= SIZEOF_VOID_P;
3244                 need_wb >>= 1;
3245
3246                 /*tmp += sizeof (void*)*/
3247                 if (size >= SIZEOF_VOID_P) {
3248                         NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, dest_ptr_reg, dest_ptr_reg, SIZEOF_VOID_P);
3249                         MONO_ADD_INS (cfg->cbb, iargs [0]);
3250                 }
3251         }
3252
3253         /* Those cannot be references since size < sizeof (void*) */
3254         while (size >= 4) {
3255                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tmp_reg, srcreg, offset);
3256                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, tmp_reg);
3257                 offset += 4;
3258                 size -= 4;
3259         }
3260
3261         while (size >= 2) {
3262                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmp_reg, srcreg, offset);
3263                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, tmp_reg);
3264                 offset += 2;
3265                 size -= 2;
3266         }
3267
3268         while (size >= 1) {
3269                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmp_reg, srcreg, offset);
3270                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, tmp_reg);
3271                 offset += 1;
3272                 size -= 1;
3273         }
3274
3275         return TRUE;
3276 }
3277
3278 /*
3279  * Emit code to copy a valuetype of type @klass whose address is stored in
3280  * @src->dreg to memory whose address is stored at @dest->dreg.
3281  */
3282 void
3283 mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native)
3284 {
3285         MonoInst *iargs [4];
3286         int n;
3287         guint32 align = 0;
3288         MonoMethod *memcpy_method;
3289         MonoInst *size_ins = NULL;
3290         MonoInst *memcpy_ins = NULL;
3291
3292         g_assert (klass);
3293         if (cfg->gshared)
3294                 klass = mono_class_from_mono_type (mini_get_underlying_type (&klass->byval_arg));
3295
3296         /*
3297          * This check breaks with spilled vars... need to handle it during verification anyway.
3298          * g_assert (klass && klass == src->klass && klass == dest->klass);
3299          */
3300
3301         if (mini_is_gsharedvt_klass (klass)) {
3302                 g_assert (!native);
3303                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3304                 memcpy_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_MEMCPY);
3305         }
3306
3307         if (native)
3308                 n = mono_class_native_size (klass, &align);
3309         else
3310                 n = mono_class_value_size (klass, &align);
3311
3312         /* if native is true there should be no references in the struct */
3313         if (cfg->gen_write_barriers && (klass->has_references || size_ins) && !native) {
3314                 /* Avoid barriers when storing to the stack */
3315                 if (!((dest->opcode == OP_ADD_IMM && dest->sreg1 == cfg->frame_reg) ||
3316                           (dest->opcode == OP_LDADDR))) {
3317                         int context_used;
3318
3319                         iargs [0] = dest;
3320                         iargs [1] = src;
3321
3322                         context_used = mini_class_check_context_used (cfg, klass);
3323
3324                         /* It's ok to intrinsify under gsharing since shared code types are layout stable. */
3325                         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && mono_emit_wb_aware_memcpy (cfg, klass, iargs, n, align)) {
3326                                 return;
3327                         } else if (context_used) {
3328                                 iargs [2] = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3329                         }  else {
3330                                 iargs [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, klass);
3331                                 if (!cfg->compile_aot)
3332                                         mono_class_compute_gc_descriptor (klass);
3333                         }
3334
3335                         if (size_ins)
3336                                 mono_emit_jit_icall (cfg, mono_gsharedvt_value_copy, iargs);
3337                         else
3338                                 mono_emit_jit_icall (cfg, mono_value_copy, iargs);
3339                         return;
3340                 }
3341         }
3342
3343         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 8) {
3344                 /* FIXME: Optimize the case when src/dest is OP_LDADDR */
3345                 mini_emit_memcpy (cfg, dest->dreg, 0, src->dreg, 0, n, align);
3346         } else {
3347                 iargs [0] = dest;
3348                 iargs [1] = src;
3349                 if (size_ins)
3350                         iargs [2] = size_ins;
3351                 else
3352                         EMIT_NEW_ICONST (cfg, iargs [2], n);
3353                 
3354                 memcpy_method = get_memcpy_method ();
3355                 if (memcpy_ins)
3356                         mono_emit_calli (cfg, mono_method_signature (memcpy_method), iargs, memcpy_ins, NULL, NULL);
3357                 else
3358                         mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
3359         }
3360 }
3361
3362 static MonoMethod*
3363 get_memset_method (void)
3364 {
3365         static MonoMethod *memset_method = NULL;
3366         if (!memset_method) {
3367                 memset_method = mono_class_get_method_from_name (mono_defaults.string_class, "memset", 3);
3368                 if (!memset_method)
3369                         g_error ("Old corlib found. Install a new one");
3370         }
3371         return memset_method;
3372 }
3373
3374 void
3375 mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass)
3376 {
3377         MonoInst *iargs [3];
3378         int n;
3379         guint32 align;
3380         MonoMethod *memset_method;
3381         MonoInst *size_ins = NULL;
3382         MonoInst *bzero_ins = NULL;
3383         static MonoMethod *bzero_method;
3384
3385         /* FIXME: Optimize this for the case when dest is an LDADDR */
3386         mono_class_init (klass);
3387         if (mini_is_gsharedvt_klass (klass)) {
3388                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3389                 bzero_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_BZERO);
3390                 if (!bzero_method)
3391                         bzero_method = mono_class_get_method_from_name (mono_defaults.string_class, "bzero_aligned_1", 2);
3392                 g_assert (bzero_method);
3393                 iargs [0] = dest;
3394                 iargs [1] = size_ins;
3395                 mono_emit_calli (cfg, mono_method_signature (bzero_method), iargs, bzero_ins, NULL, NULL);
3396                 return;
3397         }
3398
3399         n = mono_class_value_size (klass, &align);
3400
3401         if (n <= sizeof (gpointer) * 8) {
3402                 mini_emit_memset (cfg, dest->dreg, 0, n, 0, align);
3403         }
3404         else {
3405                 memset_method = get_memset_method ();
3406                 iargs [0] = dest;
3407                 EMIT_NEW_ICONST (cfg, iargs [1], 0);
3408                 EMIT_NEW_ICONST (cfg, iargs [2], n);
3409                 mono_emit_method_call (cfg, memset_method, iargs, NULL);
3410         }
3411 }
3412
3413 /*
3414  * emit_get_rgctx:
3415  *
3416  *   Emit IR to return either the this pointer for instance method,
3417  * or the mrgctx for static methods.
3418  */
3419 static MonoInst*
3420 emit_get_rgctx (MonoCompile *cfg, MonoMethod *method, int context_used)
3421 {
3422         MonoInst *this_ins = NULL;
3423
3424         g_assert (cfg->gshared);
3425
3426         if (!(method->flags & METHOD_ATTRIBUTE_STATIC) &&
3427                         !(context_used & MONO_GENERIC_CONTEXT_USED_METHOD) &&
3428                         !method->klass->valuetype)
3429                 EMIT_NEW_ARGLOAD (cfg, this_ins, 0);
3430
3431         if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD) {
3432                 MonoInst *mrgctx_loc, *mrgctx_var;
3433
3434                 g_assert (!this_ins);
3435                 g_assert (method->is_inflated && mono_method_get_context (method)->method_inst);
3436
3437                 mrgctx_loc = mono_get_vtable_var (cfg);
3438                 EMIT_NEW_TEMPLOAD (cfg, mrgctx_var, mrgctx_loc->inst_c0);
3439
3440                 return mrgctx_var;
3441         } else if (method->flags & METHOD_ATTRIBUTE_STATIC || method->klass->valuetype) {
3442                 MonoInst *vtable_loc, *vtable_var;
3443
3444                 g_assert (!this_ins);
3445
3446                 vtable_loc = mono_get_vtable_var (cfg);
3447                 EMIT_NEW_TEMPLOAD (cfg, vtable_var, vtable_loc->inst_c0);
3448
3449                 if (method->is_inflated && mono_method_get_context (method)->method_inst) {
3450                         MonoInst *mrgctx_var = vtable_var;
3451                         int vtable_reg;
3452
3453                         vtable_reg = alloc_preg (cfg);
3454                         EMIT_NEW_LOAD_MEMBASE (cfg, vtable_var, OP_LOAD_MEMBASE, vtable_reg, mrgctx_var->dreg, MONO_STRUCT_OFFSET (MonoMethodRuntimeGenericContext, class_vtable));
3455                         vtable_var->type = STACK_PTR;
3456                 }
3457
3458                 return vtable_var;
3459         } else {
3460                 MonoInst *ins;
3461                 int vtable_reg;
3462         
3463                 vtable_reg = alloc_preg (cfg);
3464                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, vtable_reg, this_ins->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3465                 return ins;
3466         }
3467 }
3468
3469 static MonoJumpInfoRgctxEntry *
3470 mono_patch_info_rgctx_entry_new (MonoMemPool *mp, MonoMethod *method, gboolean in_mrgctx, MonoJumpInfoType patch_type, gconstpointer patch_data, MonoRgctxInfoType info_type)
3471 {
3472         MonoJumpInfoRgctxEntry *res = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoRgctxEntry));
3473         res->method = method;
3474         res->in_mrgctx = in_mrgctx;
3475         res->data = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo));
3476         res->data->type = patch_type;
3477         res->data->data.target = patch_data;
3478         res->info_type = info_type;
3479
3480         return res;
3481 }
3482
3483 static inline MonoInst*
3484 emit_rgctx_fetch_inline (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
3485 {
3486         MonoInst *args [16];
3487         MonoInst *call;
3488
3489         // FIXME: No fastpath since the slot is not a compile time constant
3490         args [0] = rgctx;
3491         EMIT_NEW_AOTCONST (cfg, args [1], MONO_PATCH_INFO_RGCTX_SLOT_INDEX, entry);
3492         if (entry->in_mrgctx)
3493                 call = mono_emit_jit_icall (cfg, mono_fill_method_rgctx, args);
3494         else
3495                 call = mono_emit_jit_icall (cfg, mono_fill_class_rgctx, args);
3496         return call;
3497 #if 0
3498         /*
3499          * FIXME: This can be called during decompose, which is a problem since it creates
3500          * new bblocks.
3501          * Also, the fastpath doesn't work since the slot number is dynamically allocated.
3502          */
3503         int i, slot, depth, index, rgctx_reg, val_reg, res_reg;
3504         gboolean mrgctx;
3505         MonoBasicBlock *is_null_bb, *end_bb;
3506         MonoInst *res, *ins, *call;
3507         MonoInst *args[16];
3508
3509         slot = mini_get_rgctx_entry_slot (entry);
3510
3511         mrgctx = MONO_RGCTX_SLOT_IS_MRGCTX (slot);
3512         index = MONO_RGCTX_SLOT_INDEX (slot);
3513         if (mrgctx)
3514                 index += MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
3515         for (depth = 0; ; ++depth) {
3516                 int size = mono_class_rgctx_get_array_size (depth, mrgctx);
3517
3518                 if (index < size - 1)
3519                         break;
3520                 index -= size - 1;
3521         }
3522
3523         NEW_BBLOCK (cfg, end_bb);
3524         NEW_BBLOCK (cfg, is_null_bb);
3525
3526         if (mrgctx) {
3527                 rgctx_reg = rgctx->dreg;
3528         } else {
3529                 rgctx_reg = alloc_preg (cfg);
3530
3531                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, rgctx_reg, rgctx->dreg, MONO_STRUCT_OFFSET (MonoVTable, runtime_generic_context));
3532                 // FIXME: Avoid this check by allocating the table when the vtable is created etc.
3533                 NEW_BBLOCK (cfg, is_null_bb);
3534
3535                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rgctx_reg, 0);
3536                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3537         }
3538
3539         for (i = 0; i < depth; ++i) {
3540                 int array_reg = alloc_preg (cfg);
3541
3542                 /* load ptr to next array */
3543                 if (mrgctx && i == 0)
3544                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, rgctx_reg, MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT);
3545                 else
3546                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, rgctx_reg, 0);
3547                 rgctx_reg = array_reg;
3548                 /* is the ptr null? */
3549                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rgctx_reg, 0);
3550                 /* if yes, jump to actual trampoline */
3551                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3552         }
3553
3554         /* fetch slot */
3555         val_reg = alloc_preg (cfg);
3556         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, val_reg, rgctx_reg, (index + 1) * sizeof (gpointer));
3557         /* is the slot null? */
3558         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, val_reg, 0);
3559         /* if yes, jump to actual trampoline */
3560         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3561
3562         /* Fastpath */
3563         res_reg = alloc_preg (cfg);
3564         MONO_INST_NEW (cfg, ins, OP_MOVE);
3565         ins->dreg = res_reg;
3566         ins->sreg1 = val_reg;
3567         MONO_ADD_INS (cfg->cbb, ins);
3568         res = ins;
3569         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3570
3571         /* Slowpath */
3572         MONO_START_BB (cfg, is_null_bb);
3573         args [0] = rgctx;
3574         EMIT_NEW_ICONST (cfg, args [1], index);
3575         if (mrgctx)
3576                 call = mono_emit_jit_icall (cfg, mono_fill_method_rgctx, args);
3577         else
3578                 call = mono_emit_jit_icall (cfg, mono_fill_class_rgctx, args);
3579         MONO_INST_NEW (cfg, ins, OP_MOVE);
3580         ins->dreg = res_reg;
3581         ins->sreg1 = call->dreg;
3582         MONO_ADD_INS (cfg->cbb, ins);
3583         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3584
3585         MONO_START_BB (cfg, end_bb);
3586
3587         return res;
3588 #endif
3589 }
3590
3591 /*
3592  * emit_rgctx_fetch:
3593  *
3594  *   Emit IR to load the value of the rgctx entry ENTRY from the rgctx
3595  * given by RGCTX.
3596  */
3597 static inline MonoInst*
3598 emit_rgctx_fetch (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
3599 {
3600         if (cfg->llvm_only)
3601                 return emit_rgctx_fetch_inline (cfg, rgctx, entry);
3602         else
3603                 return mono_emit_abs_call (cfg, MONO_PATCH_INFO_RGCTX_FETCH, entry, helper_sig_rgctx_lazy_fetch_trampoline, &rgctx);
3604 }
3605
3606 static MonoInst*
3607 emit_get_rgctx_klass (MonoCompile *cfg, int context_used,
3608                                           MonoClass *klass, MonoRgctxInfoType rgctx_type)
3609 {
3610         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);
3611         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3612
3613         return emit_rgctx_fetch (cfg, rgctx, entry);
3614 }
3615
3616 static MonoInst*
3617 emit_get_rgctx_sig (MonoCompile *cfg, int context_used,
3618                                         MonoMethodSignature *sig, MonoRgctxInfoType rgctx_type)
3619 {
3620         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);
3621         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3622
3623         return emit_rgctx_fetch (cfg, rgctx, entry);
3624 }
3625
3626 static MonoInst*
3627 emit_get_rgctx_gsharedvt_call (MonoCompile *cfg, int context_used,
3628                                                            MonoMethodSignature *sig, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3629 {
3630         MonoJumpInfoGSharedVtCall *call_info;
3631         MonoJumpInfoRgctxEntry *entry;
3632         MonoInst *rgctx;
3633
3634         call_info = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoGSharedVtCall));
3635         call_info->sig = sig;
3636         call_info->method = cmethod;
3637
3638         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);
3639         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3640
3641         return emit_rgctx_fetch (cfg, rgctx, entry);
3642 }
3643
3644 /*
3645  * emit_get_rgctx_virt_method:
3646  *
3647  *   Return data for method VIRT_METHOD for a receiver of type KLASS.
3648  */
3649 static MonoInst*
3650 emit_get_rgctx_virt_method (MonoCompile *cfg, int context_used,
3651                                                         MonoClass *klass, MonoMethod *virt_method, MonoRgctxInfoType rgctx_type)
3652 {
3653         MonoJumpInfoVirtMethod *info;
3654         MonoJumpInfoRgctxEntry *entry;
3655         MonoInst *rgctx;
3656
3657         info = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoVirtMethod));
3658         info->klass = klass;
3659         info->method = virt_method;
3660
3661         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);
3662         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3663
3664         return emit_rgctx_fetch (cfg, rgctx, entry);
3665 }
3666
3667 static MonoInst*
3668 emit_get_rgctx_gsharedvt_method (MonoCompile *cfg, int context_used,
3669                                                                  MonoMethod *cmethod, MonoGSharedVtMethodInfo *info)
3670 {
3671         MonoJumpInfoRgctxEntry *entry;
3672         MonoInst *rgctx;
3673
3674         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);
3675         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3676
3677         return emit_rgctx_fetch (cfg, rgctx, entry);
3678 }
3679
3680 /*
3681  * emit_get_rgctx_method:
3682  *
3683  *   Emit IR to load the property RGCTX_TYPE of CMETHOD. If context_used is 0, emit
3684  * normal constants, else emit a load from the rgctx.
3685  */
3686 static MonoInst*
3687 emit_get_rgctx_method (MonoCompile *cfg, int context_used,
3688                                            MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3689 {
3690         if (!context_used) {
3691                 MonoInst *ins;
3692
3693                 switch (rgctx_type) {
3694                 case MONO_RGCTX_INFO_METHOD:
3695                         EMIT_NEW_METHODCONST (cfg, ins, cmethod);
3696                         return ins;
3697                 case MONO_RGCTX_INFO_METHOD_RGCTX:
3698                         EMIT_NEW_METHOD_RGCTX_CONST (cfg, ins, cmethod);
3699                         return ins;
3700                 default:
3701                         g_assert_not_reached ();
3702                 }
3703         } else {
3704                 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);
3705                 MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3706
3707                 return emit_rgctx_fetch (cfg, rgctx, entry);
3708         }
3709 }
3710
3711 static MonoInst*
3712 emit_get_rgctx_field (MonoCompile *cfg, int context_used,
3713                                           MonoClassField *field, MonoRgctxInfoType rgctx_type)
3714 {
3715         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);
3716         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3717
3718         return emit_rgctx_fetch (cfg, rgctx, entry);
3719 }
3720
3721 static int
3722 get_gsharedvt_info_slot (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3723 {
3724         MonoGSharedVtMethodInfo *info = cfg->gsharedvt_info;
3725         MonoRuntimeGenericContextInfoTemplate *template;
3726         int i, idx;
3727
3728         g_assert (info);
3729
3730         for (i = 0; i < info->num_entries; ++i) {
3731                 MonoRuntimeGenericContextInfoTemplate *otemplate = &info->entries [i];
3732
3733                 if (otemplate->info_type == rgctx_type && otemplate->data == data && rgctx_type != MONO_RGCTX_INFO_LOCAL_OFFSET)
3734                         return i;
3735         }
3736
3737         if (info->num_entries == info->count_entries) {
3738                 MonoRuntimeGenericContextInfoTemplate *new_entries;
3739                 int new_count_entries = info->count_entries ? info->count_entries * 2 : 16;
3740
3741                 new_entries = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * new_count_entries);
3742
3743                 memcpy (new_entries, info->entries, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
3744                 info->entries = new_entries;
3745                 info->count_entries = new_count_entries;
3746         }
3747
3748         idx = info->num_entries;
3749         template = &info->entries [idx];
3750         template->info_type = rgctx_type;
3751         template->data = data;
3752
3753         info->num_entries ++;
3754
3755         return idx;
3756 }
3757
3758 /*
3759  * emit_get_gsharedvt_info:
3760  *
3761  *   This is similar to emit_get_rgctx_.., but loads the data from the gsharedvt info var instead of calling an rgctx fetch trampoline.
3762  */
3763 static MonoInst*
3764 emit_get_gsharedvt_info (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3765 {
3766         MonoInst *ins;
3767         int idx, dreg;
3768
3769         idx = get_gsharedvt_info_slot (cfg, data, rgctx_type);
3770         /* Load info->entries [idx] */
3771         dreg = alloc_preg (cfg);
3772         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, cfg->gsharedvt_info_var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
3773
3774         return ins;
3775 }
3776
3777 static MonoInst*
3778 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type)
3779 {
3780         return emit_get_gsharedvt_info (cfg, &klass->byval_arg, rgctx_type);
3781 }
3782
3783 /*
3784  * On return the caller must check @klass for load errors.
3785  */
3786 static void
3787 emit_class_init (MonoCompile *cfg, MonoClass *klass)
3788 {
3789         MonoInst *vtable_arg;
3790         int context_used;
3791
3792         context_used = mini_class_check_context_used (cfg, klass);
3793
3794         if (context_used) {
3795                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
3796                                                                                    klass, MONO_RGCTX_INFO_VTABLE);
3797         } else {
3798                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
3799
3800                 if (!vtable)
3801                         return;
3802                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
3803         }
3804
3805         if (!COMPILE_LLVM (cfg) && cfg->backend->have_op_generic_class_init) {
3806                 MonoInst *ins;
3807
3808                 /*
3809                  * Using an opcode instead of emitting IR here allows the hiding of the call inside the opcode,
3810                  * so this doesn't have to clobber any regs and it doesn't break basic blocks.
3811                  */
3812                 MONO_INST_NEW (cfg, ins, OP_GENERIC_CLASS_INIT);
3813                 ins->sreg1 = vtable_arg->dreg;
3814                 MONO_ADD_INS (cfg->cbb, ins);
3815         } else {
3816                 static int byte_offset = -1;
3817                 static guint8 bitmask;
3818                 int bits_reg, inited_reg;
3819                 MonoBasicBlock *inited_bb;
3820                 MonoInst *args [16];
3821
3822                 if (byte_offset < 0)
3823                         mono_marshal_find_bitfield_offset (MonoVTable, initialized, &byte_offset, &bitmask);
3824
3825                 bits_reg = alloc_ireg (cfg);
3826                 inited_reg = alloc_ireg (cfg);
3827
3828                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, bits_reg, vtable_arg->dreg, byte_offset);
3829                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, inited_reg, bits_reg, bitmask);
3830
3831                 NEW_BBLOCK (cfg, inited_bb);
3832
3833                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, inited_reg, 0);
3834                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, inited_bb);
3835
3836                 args [0] = vtable_arg;
3837                 mono_emit_jit_icall (cfg, mono_generic_class_init, args);
3838
3839                 MONO_START_BB (cfg, inited_bb);
3840         }
3841 }
3842
3843 static void
3844 emit_seq_point (MonoCompile *cfg, MonoMethod *method, guint8* ip, gboolean intr_loc, gboolean nonempty_stack)
3845 {
3846         MonoInst *ins;
3847
3848         if (cfg->gen_seq_points && cfg->method == method) {
3849                 NEW_SEQ_POINT (cfg, ins, ip - cfg->header->code, intr_loc);
3850                 if (nonempty_stack)
3851                         ins->flags |= MONO_INST_NONEMPTY_STACK;
3852                 MONO_ADD_INS (cfg->cbb, ins);
3853         }
3854 }
3855
3856 static void
3857 save_cast_details (MonoCompile *cfg, MonoClass *klass, int obj_reg, gboolean null_check)
3858 {
3859         if (mini_get_debug_options ()->better_cast_details) {
3860                 int vtable_reg = alloc_preg (cfg);
3861                 int klass_reg = alloc_preg (cfg);
3862                 MonoBasicBlock *is_null_bb = NULL;
3863                 MonoInst *tls_get;
3864                 int to_klass_reg, context_used;
3865
3866                 if (null_check) {
3867                         NEW_BBLOCK (cfg, is_null_bb);
3868
3869                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
3870                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3871                 }
3872
3873                 tls_get = mono_get_jit_tls_intrinsic (cfg);
3874                 if (!tls_get) {
3875                         fprintf (stderr, "error: --debug=casts not supported on this platform.\n.");
3876                         exit (1);
3877                 }
3878
3879                 MONO_ADD_INS (cfg->cbb, tls_get);
3880                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3881                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3882
3883                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), klass_reg);
3884
3885                 context_used = mini_class_check_context_used (cfg, klass);
3886                 if (context_used) {
3887                         MonoInst *class_ins;
3888
3889                         class_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3890                         to_klass_reg = class_ins->dreg;
3891                 } else {
3892                         to_klass_reg = alloc_preg (cfg);
3893                         MONO_EMIT_NEW_CLASSCONST (cfg, to_klass_reg, klass);
3894                 }
3895                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_to), to_klass_reg);
3896
3897                 if (null_check)
3898                         MONO_START_BB (cfg, is_null_bb);
3899         }
3900 }
3901
3902 static void
3903 reset_cast_details (MonoCompile *cfg)
3904 {
3905         /* Reset the variables holding the cast details */
3906         if (mini_get_debug_options ()->better_cast_details) {
3907                 MonoInst *tls_get = mono_get_jit_tls_intrinsic (cfg);
3908
3909                 MONO_ADD_INS (cfg->cbb, tls_get);
3910                 /* It is enough to reset the from field */
3911                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), 0);
3912         }
3913 }
3914
3915 /*
3916  * On return the caller must check @array_class for load errors
3917  */
3918 static void
3919 mini_emit_check_array_type (MonoCompile *cfg, MonoInst *obj, MonoClass *array_class)
3920 {
3921         int vtable_reg = alloc_preg (cfg);
3922         int context_used;
3923
3924         context_used = mini_class_check_context_used (cfg, array_class);
3925
3926         save_cast_details (cfg, array_class, obj->dreg, FALSE);
3927
3928         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3929
3930         if (cfg->opt & MONO_OPT_SHARED) {
3931                 int class_reg = alloc_preg (cfg);
3932                 MonoInst *ins;
3933
3934                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, class_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3935                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, array_class);
3936                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, class_reg, ins->dreg);
3937         } else if (context_used) {
3938                 MonoInst *vtable_ins;
3939
3940                 vtable_ins = emit_get_rgctx_klass (cfg, context_used, array_class, MONO_RGCTX_INFO_VTABLE);
3941                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vtable_ins->dreg);
3942         } else {
3943                 if (cfg->compile_aot) {
3944                         int vt_reg;
3945                         MonoVTable *vtable;
3946
3947                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3948                                 return;
3949                         vt_reg = alloc_preg (cfg);
3950                         MONO_EMIT_NEW_VTABLECONST (cfg, vt_reg, vtable);
3951                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vt_reg);
3952                 } else {
3953                         MonoVTable *vtable;
3954                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3955                                 return;
3956                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vtable);
3957                 }
3958         }
3959         
3960         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ArrayTypeMismatchException");
3961
3962         reset_cast_details (cfg);
3963 }
3964
3965 /**
3966  * Handles unbox of a Nullable<T>. If context_used is non zero, then shared 
3967  * generic code is generated.
3968  */
3969 static MonoInst*
3970 handle_unbox_nullable (MonoCompile* cfg, MonoInst* val, MonoClass* klass, int context_used)
3971 {
3972         MonoMethod* method = mono_class_get_method_from_name (klass, "Unbox", 1);
3973
3974         if (context_used) {
3975                 MonoInst *rgctx, *addr;
3976
3977                 /* FIXME: What if the class is shared?  We might not
3978                    have to get the address of the method from the
3979                    RGCTX. */
3980                 addr = emit_get_rgctx_method (cfg, context_used, method,
3981                                                                           MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
3982
3983                 rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3984
3985                 return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
3986         } else {
3987                 gboolean pass_vtable, pass_mrgctx;
3988                 MonoInst *rgctx_arg = NULL;
3989
3990                 check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
3991                 g_assert (!pass_mrgctx);
3992
3993                 if (pass_vtable) {
3994                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
3995
3996                         g_assert (vtable);
3997                         EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
3998                 }
3999
4000                 return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
4001         }
4002 }
4003
4004 static MonoInst*
4005 handle_unbox (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, int context_used)
4006 {
4007         MonoInst *add;
4008         int obj_reg;
4009         int vtable_reg = alloc_dreg (cfg ,STACK_PTR);
4010         int klass_reg = alloc_dreg (cfg ,STACK_PTR);
4011         int eclass_reg = alloc_dreg (cfg ,STACK_PTR);
4012         int rank_reg = alloc_dreg (cfg ,STACK_I4);
4013
4014         obj_reg = sp [0]->dreg;
4015         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4016         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
4017
4018         /* FIXME: generics */
4019         g_assert (klass->rank == 0);
4020                         
4021         // Check rank == 0
4022         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, 0);
4023         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4024
4025         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4026         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, element_class));
4027
4028         if (context_used) {
4029                 MonoInst *element_class;
4030
4031                 /* This assertion is from the unboxcast insn */
4032                 g_assert (klass->rank == 0);
4033
4034                 element_class = emit_get_rgctx_klass (cfg, context_used,
4035                                 klass, MONO_RGCTX_INFO_ELEMENT_KLASS);
4036
4037                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, eclass_reg, element_class->dreg);
4038                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4039         } else {
4040                 save_cast_details (cfg, klass->element_class, obj_reg, FALSE);
4041                 mini_emit_class_check (cfg, eclass_reg, klass->element_class);
4042                 reset_cast_details (cfg);
4043         }
4044
4045         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), obj_reg, sizeof (MonoObject));
4046         MONO_ADD_INS (cfg->cbb, add);
4047         add->type = STACK_MP;
4048         add->klass = klass;
4049
4050         return add;
4051 }
4052
4053 static MonoInst*
4054 handle_unbox_gsharedvt (MonoCompile *cfg, MonoClass *klass, MonoInst *obj)
4055 {
4056         MonoInst *addr, *klass_inst, *is_ref, *args[16];
4057         MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
4058         MonoInst *ins;
4059         int dreg, addr_reg;
4060
4061         klass_inst = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_KLASS);
4062
4063         /* obj */
4064         args [0] = obj;
4065
4066         /* klass */
4067         args [1] = klass_inst;
4068
4069         /* CASTCLASS */
4070         obj = mono_emit_jit_icall (cfg, mono_object_castclass_unbox, args);
4071
4072         NEW_BBLOCK (cfg, is_ref_bb);
4073         NEW_BBLOCK (cfg, is_nullable_bb);
4074         NEW_BBLOCK (cfg, end_bb);
4075         is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
4076         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 1);
4077         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
4078
4079         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 2);
4080         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
4081
4082         /* This will contain either the address of the unboxed vtype, or an address of the temporary where the ref is stored */
4083         addr_reg = alloc_dreg (cfg, STACK_MP);
4084
4085         /* Non-ref case */
4086         /* UNBOX */
4087         NEW_BIALU_IMM (cfg, addr, OP_ADD_IMM, addr_reg, obj->dreg, sizeof (MonoObject));
4088         MONO_ADD_INS (cfg->cbb, addr);
4089
4090         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4091
4092         /* Ref case */
4093         MONO_START_BB (cfg, is_ref_bb);
4094
4095         /* Save the ref to a temporary */
4096         dreg = alloc_ireg (cfg);
4097         EMIT_NEW_VARLOADA_VREG (cfg, addr, dreg, &klass->byval_arg);
4098         addr->dreg = addr_reg;
4099         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, obj->dreg);
4100         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4101
4102         /* Nullable case */
4103         MONO_START_BB (cfg, is_nullable_bb);
4104
4105         {
4106                 MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX);
4107                 MonoInst *unbox_call;
4108                 MonoMethodSignature *unbox_sig;
4109
4110                 unbox_sig = mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
4111                 unbox_sig->ret = &klass->byval_arg;
4112                 unbox_sig->param_count = 1;
4113                 unbox_sig->params [0] = &mono_defaults.object_class->byval_arg;
4114                 unbox_call = mono_emit_calli (cfg, unbox_sig, &obj, addr, NULL, NULL);
4115
4116                 EMIT_NEW_VARLOADA_VREG (cfg, addr, unbox_call->dreg, &klass->byval_arg);
4117                 addr->dreg = addr_reg;
4118         }
4119
4120         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4121
4122         /* End */
4123         MONO_START_BB (cfg, end_bb);
4124
4125         /* LDOBJ */
4126         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr_reg, 0);
4127
4128         return ins;
4129 }
4130
4131 /*
4132  * Returns NULL and set the cfg exception on error.
4133  */
4134 static MonoInst*
4135 handle_alloc (MonoCompile *cfg, MonoClass *klass, gboolean for_box, int context_used)
4136 {
4137         MonoInst *iargs [2];
4138         void *alloc_ftn;
4139
4140         if (context_used) {
4141                 MonoInst *data;
4142                 int rgctx_info;
4143                 MonoInst *iargs [2];
4144                 gboolean known_instance_size = !mini_is_gsharedvt_klass (klass);
4145
4146                 MonoMethod *managed_alloc = mono_gc_get_managed_allocator (klass, for_box, known_instance_size);
4147
4148                 if (cfg->opt & MONO_OPT_SHARED)
4149                         rgctx_info = MONO_RGCTX_INFO_KLASS;
4150                 else
4151                         rgctx_info = MONO_RGCTX_INFO_VTABLE;
4152                 data = emit_get_rgctx_klass (cfg, context_used, klass, rgctx_info);
4153
4154                 if (cfg->opt & MONO_OPT_SHARED) {
4155                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
4156                         iargs [1] = data;
4157                         alloc_ftn = mono_object_new;
4158                 } else {
4159                         iargs [0] = data;
4160                         alloc_ftn = mono_object_new_specific;
4161                 }
4162
4163                 if (managed_alloc && !(cfg->opt & MONO_OPT_SHARED)) {
4164                         if (known_instance_size) {
4165                                 int size = mono_class_instance_size (klass);
4166                                 if (size < sizeof (MonoObject))
4167                                         g_error ("Invalid size %d for class %s", size, mono_type_get_full_name (klass));
4168
4169                                 EMIT_NEW_ICONST (cfg, iargs [1], mono_gc_get_aligned_size_for_allocator (size));
4170                         }
4171                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
4172                 }
4173
4174                 return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
4175         }
4176
4177         if (cfg->opt & MONO_OPT_SHARED) {
4178                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
4179                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
4180
4181                 alloc_ftn = mono_object_new;
4182         } else if (cfg->compile_aot && cfg->cbb->out_of_line && klass->type_token && klass->image == mono_defaults.corlib && !klass->generic_class) {
4183                 /* This happens often in argument checking code, eg. throw new FooException... */
4184                 /* Avoid relocations and save some space by calling a helper function specialized to mscorlib */
4185                 EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (klass->type_token));
4186                 return mono_emit_jit_icall (cfg, mono_helper_newobj_mscorlib, iargs);
4187         } else {
4188                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
4189                 MonoMethod *managed_alloc = NULL;
4190                 gboolean pass_lw;
4191
4192                 if (!vtable) {
4193                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4194                         cfg->exception_ptr = klass;
4195                         return NULL;
4196                 }
4197
4198                 managed_alloc = mono_gc_get_managed_allocator (klass, for_box, TRUE);
4199
4200                 if (managed_alloc) {
4201                         int size = mono_class_instance_size (klass);
4202                         if (size < sizeof (MonoObject))
4203                                 g_error ("Invalid size %d for class %s", size, mono_type_get_full_name (klass));
4204
4205                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
4206                         EMIT_NEW_ICONST (cfg, iargs [1], mono_gc_get_aligned_size_for_allocator (size));
4207                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
4208                 }
4209                 alloc_ftn = mono_class_get_allocation_ftn (vtable, for_box, &pass_lw);
4210                 if (pass_lw) {
4211                         guint32 lw = vtable->klass->instance_size;
4212                         lw = ((lw + (sizeof (gpointer) - 1)) & ~(sizeof (gpointer) - 1)) / sizeof (gpointer);
4213                         EMIT_NEW_ICONST (cfg, iargs [0], lw);
4214                         EMIT_NEW_VTABLECONST (cfg, iargs [1], vtable);
4215                 }
4216                 else {
4217                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
4218                 }
4219         }
4220
4221         return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
4222 }
4223         
4224 /*
4225  * Returns NULL and set the cfg exception on error.
4226  */     
4227 static MonoInst*
4228 handle_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_used)
4229 {
4230         MonoInst *alloc, *ins;
4231
4232         if (mono_class_is_nullable (klass)) {
4233                 MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
4234
4235                 if (context_used) {
4236                         /* FIXME: What if the class is shared?  We might not
4237                            have to get the method address from the RGCTX. */
4238                         MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
4239                                                                                                         MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
4240                         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
4241
4242                         return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
4243                 } else {
4244                         gboolean pass_vtable, pass_mrgctx;
4245                         MonoInst *rgctx_arg = NULL;
4246
4247                         check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
4248                         g_assert (!pass_mrgctx);
4249
4250                         if (pass_vtable) {
4251                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
4252
4253                                 g_assert (vtable);
4254                                 EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
4255                         }
4256
4257                         return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
4258                 }
4259         }
4260
4261         if (mini_is_gsharedvt_klass (klass)) {
4262                 MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
4263                 MonoInst *res, *is_ref, *src_var, *addr;
4264                 int dreg;
4265
4266                 dreg = alloc_ireg (cfg);
4267
4268                 NEW_BBLOCK (cfg, is_ref_bb);
4269                 NEW_BBLOCK (cfg, is_nullable_bb);
4270                 NEW_BBLOCK (cfg, end_bb);
4271                 is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
4272                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 1);
4273                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
4274
4275                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 2);
4276                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
4277
4278                 /* Non-ref case */
4279                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4280                 if (!alloc)
4281                         return NULL;
4282                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4283                 ins->opcode = OP_STOREV_MEMBASE;
4284
4285                 EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, alloc->dreg);
4286                 res->type = STACK_OBJ;
4287                 res->klass = klass;
4288                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4289                 
4290                 /* Ref case */
4291                 MONO_START_BB (cfg, is_ref_bb);
4292
4293                 /* val is a vtype, so has to load the value manually */
4294                 src_var = get_vreg_to_inst (cfg, val->dreg);
4295                 if (!src_var)
4296                         src_var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, val->dreg);
4297                 EMIT_NEW_VARLOADA (cfg, addr, src_var, src_var->inst_vtype);
4298                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, addr->dreg, 0);
4299                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4300
4301                 /* Nullable case */
4302                 MONO_START_BB (cfg, is_nullable_bb);
4303
4304                 {
4305                         MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass,
4306                                                                                                         MONO_RGCTX_INFO_NULLABLE_CLASS_BOX);
4307                         MonoInst *box_call;
4308                         MonoMethodSignature *box_sig;
4309
4310                         /*
4311                          * klass is Nullable<T>, need to call Nullable<T>.Box () using a gsharedvt signature, but we cannot
4312                          * construct that method at JIT time, so have to do things by hand.
4313                          */
4314                         box_sig = mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
4315                         box_sig->ret = &mono_defaults.object_class->byval_arg;
4316                         box_sig->param_count = 1;
4317                         box_sig->params [0] = &klass->byval_arg;
4318                         box_call = mono_emit_calli (cfg, box_sig, &val, addr, NULL, NULL);
4319                         EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, box_call->dreg);
4320                         res->type = STACK_OBJ;
4321                         res->klass = klass;
4322                 }
4323
4324                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4325
4326                 MONO_START_BB (cfg, end_bb);
4327
4328                 return res;
4329         } else {
4330                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4331                 if (!alloc)
4332                         return NULL;
4333
4334                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4335                 return alloc;
4336         }
4337 }
4338
4339 static gboolean
4340 mini_class_has_reference_variant_generic_argument (MonoCompile *cfg, MonoClass *klass, int context_used)
4341 {
4342         int i;
4343         MonoGenericContainer *container;
4344         MonoGenericInst *ginst;
4345
4346         if (klass->generic_class) {
4347                 container = klass->generic_class->container_class->generic_container;
4348                 ginst = klass->generic_class->context.class_inst;
4349         } else if (klass->generic_container && context_used) {
4350                 container = klass->generic_container;
4351                 ginst = container->context.class_inst;
4352         } else {
4353                 return FALSE;
4354         }
4355
4356         for (i = 0; i < container->type_argc; ++i) {
4357                 MonoType *type;
4358                 if (!(mono_generic_container_get_param_info (container, i)->flags & (MONO_GEN_PARAM_VARIANT|MONO_GEN_PARAM_COVARIANT)))
4359                         continue;
4360                 type = ginst->type_argv [i];
4361                 if (mini_type_is_reference (type))
4362                         return TRUE;
4363         }
4364         return FALSE;
4365 }
4366
4367 static GHashTable* direct_icall_type_hash;
4368
4369 static gboolean
4370 icall_is_direct_callable (MonoCompile *cfg, MonoMethod *cmethod)
4371 {
4372         /* LLVM on amd64 can't handle calls to non-32 bit addresses */
4373         if (!direct_icalls_enabled (cfg))
4374                 return FALSE;
4375
4376         /*
4377          * An icall is directly callable if it doesn't directly or indirectly call mono_raise_exception ().
4378          * Whitelist a few icalls for now.
4379          */
4380         if (!direct_icall_type_hash) {
4381                 GHashTable *h = g_hash_table_new (g_str_hash, g_str_equal);
4382
4383                 g_hash_table_insert (h, (char*)"Decimal", GUINT_TO_POINTER (1));
4384                 g_hash_table_insert (h, (char*)"Number", GUINT_TO_POINTER (1));
4385                 g_hash_table_insert (h, (char*)"Buffer", GUINT_TO_POINTER (1));
4386                 g_hash_table_insert (h, (char*)"Monitor", GUINT_TO_POINTER (1));
4387                 mono_memory_barrier ();
4388                 direct_icall_type_hash = h;
4389         }
4390
4391         if (cmethod->klass == mono_defaults.math_class)
4392                 return TRUE;
4393         /* No locking needed */
4394         if (cmethod->klass->image == mono_defaults.corlib && g_hash_table_lookup (direct_icall_type_hash, cmethod->klass->name))
4395                 return TRUE;
4396         return FALSE;
4397 }
4398
4399 #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)
4400
4401 static MonoInst*
4402 emit_castclass_with_cache (MonoCompile *cfg, MonoClass *klass, MonoInst **args)
4403 {
4404         MonoMethod *mono_castclass;
4405         MonoInst *res;
4406
4407         mono_castclass = mono_marshal_get_castclass_with_cache ();
4408
4409         save_cast_details (cfg, klass, args [0]->dreg, TRUE);
4410         res = mono_emit_method_call (cfg, mono_castclass, args, NULL);
4411         reset_cast_details (cfg);
4412
4413         return res;
4414 }
4415
4416 static int
4417 get_castclass_cache_idx (MonoCompile *cfg)
4418 {
4419         /* Each CASTCLASS_CACHE patch needs a unique index which identifies the call site */
4420         cfg->castclass_cache_index ++;
4421         return (cfg->method_index << 16) | cfg->castclass_cache_index;
4422 }
4423
4424 static MonoInst*
4425 emit_castclass_with_cache_nonshared (MonoCompile *cfg, MonoInst *obj, MonoClass *klass)
4426 {
4427         MonoInst *args [3];
4428         int idx;
4429
4430         /* obj */
4431         args [0] = obj;
4432
4433         /* klass */
4434         EMIT_NEW_CLASSCONST (cfg, args [1], klass);
4435
4436         /* inline cache*/
4437         idx = get_castclass_cache_idx (cfg);
4438         args [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
4439
4440         /*The wrapper doesn't inline well so the bloat of inlining doesn't pay off.*/
4441         return emit_castclass_with_cache (cfg, klass, args);
4442 }
4443
4444 /*
4445  * Returns NULL and set the cfg exception on error.
4446  */
4447 static MonoInst*
4448 handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, guint8 *ip, int *inline_costs)
4449 {
4450         MonoBasicBlock *is_null_bb;
4451         int obj_reg = src->dreg;
4452         int vtable_reg = alloc_preg (cfg);
4453         int context_used;
4454         MonoInst *klass_inst = NULL, *res;
4455
4456         context_used = mini_class_check_context_used (cfg, klass);
4457
4458         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
4459                 res = emit_castclass_with_cache_nonshared (cfg, src, klass);
4460                 (*inline_costs) += 2;
4461                 return res;
4462         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
4463                 MonoMethod *mono_castclass;
4464                 MonoInst *iargs [1];
4465                 int costs;
4466
4467                 mono_castclass = mono_marshal_get_castclass (klass); 
4468                 iargs [0] = src;
4469                                 
4470                 save_cast_details (cfg, klass, src->dreg, TRUE);
4471                 costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), 
4472                                                            iargs, ip, cfg->real_offset, TRUE);
4473                 reset_cast_details (cfg);
4474                 CHECK_CFG_EXCEPTION;
4475                 g_assert (costs > 0);
4476                                 
4477                 cfg->real_offset += 5;
4478
4479                 (*inline_costs) += costs;
4480
4481                 return src;
4482         }
4483
4484         if (context_used) {
4485                 MonoInst *args [3];
4486
4487                 if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
4488                         MonoInst *cache_ins;
4489
4490                         cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
4491
4492                         /* obj */
4493                         args [0] = src;
4494
4495                         /* klass - it's the second element of the cache entry*/
4496                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
4497
4498                         /* cache */
4499                         args [2] = cache_ins;
4500
4501                         return emit_castclass_with_cache (cfg, klass, args);
4502                 }
4503
4504                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
4505         }
4506
4507         NEW_BBLOCK (cfg, is_null_bb);
4508
4509         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4510         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
4511
4512         save_cast_details (cfg, klass, obj_reg, FALSE);
4513
4514         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4515                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4516                 mini_emit_iface_cast (cfg, vtable_reg, klass, NULL, NULL);
4517         } else {
4518                 int klass_reg = alloc_preg (cfg);
4519
4520                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4521
4522                 if (!klass->rank && !cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
4523                         /* the remoting code is broken, access the class for now */
4524                         if (0) { /*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4525                                 MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4526                                 if (!vt) {
4527                                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4528                                         cfg->exception_ptr = klass;
4529                                         return NULL;
4530                                 }
4531                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4532                         } else {
4533                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4534                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4535                         }
4536                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4537                 } else {
4538                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4539                         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, klass_inst, is_null_bb);
4540                 }
4541         }
4542
4543         MONO_START_BB (cfg, is_null_bb);
4544
4545         reset_cast_details (cfg);
4546
4547         return src;
4548
4549 exception_exit:
4550         return NULL;
4551 }
4552
4553 /*
4554  * Returns NULL and set the cfg exception on error.
4555  */
4556 static MonoInst*
4557 handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
4558 {
4559         MonoInst *ins;
4560         MonoBasicBlock *is_null_bb, *false_bb, *end_bb;
4561         int obj_reg = src->dreg;
4562         int vtable_reg = alloc_preg (cfg);
4563         int res_reg = alloc_ireg_ref (cfg);
4564         MonoInst *klass_inst = NULL;
4565
4566         if (context_used) {
4567                 MonoInst *args [3];
4568
4569                 if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
4570                         MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
4571                         MonoInst *cache_ins;
4572
4573                         cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
4574
4575                         /* obj */
4576                         args [0] = src;
4577
4578                         /* klass - it's the second element of the cache entry*/
4579                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
4580
4581                         /* cache */
4582                         args [2] = cache_ins;
4583
4584                         return mono_emit_method_call (cfg, mono_isinst, args, NULL);
4585                 }
4586
4587                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
4588         }
4589
4590         NEW_BBLOCK (cfg, is_null_bb);
4591         NEW_BBLOCK (cfg, false_bb);
4592         NEW_BBLOCK (cfg, end_bb);
4593
4594         /* Do the assignment at the beginning, so the other assignment can be if converted */
4595         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, res_reg, obj_reg);
4596         ins->type = STACK_OBJ;
4597         ins->klass = klass;
4598
4599         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4600         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_null_bb);
4601
4602         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4603
4604         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4605                 g_assert (!context_used);
4606                 /* the is_null_bb target simply copies the input register to the output */
4607                 mini_emit_iface_cast (cfg, vtable_reg, klass, false_bb, is_null_bb);
4608         } else {
4609                 int klass_reg = alloc_preg (cfg);
4610
4611                 if (klass->rank) {
4612                         int rank_reg = alloc_preg (cfg);
4613                         int eclass_reg = alloc_preg (cfg);
4614
4615                         g_assert (!context_used);
4616                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
4617                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
4618                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4619                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4620                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
4621                         if (klass->cast_class == mono_defaults.object_class) {
4622                                 int parent_reg = alloc_preg (cfg);
4623                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
4624                                 mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, is_null_bb);
4625                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4626                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4627                         } else if (klass->cast_class == mono_defaults.enum_class->parent) {
4628                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, is_null_bb);
4629                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);                          
4630                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4631                         } else if (klass->cast_class == mono_defaults.enum_class) {
4632                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4633                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4634                         } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
4635                                 mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4636                         } else {
4637                                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY)) {
4638                                         /* Check that the object is a vector too */
4639                                         int bounds_reg = alloc_preg (cfg);
4640                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
4641                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
4642                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4643                                 }
4644
4645                                 /* the is_null_bb target simply copies the input register to the output */
4646                                 mini_emit_isninst_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4647                         }
4648                 } else if (mono_class_is_nullable (klass)) {
4649                         g_assert (!context_used);
4650                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4651                         /* the is_null_bb target simply copies the input register to the output */
4652                         mini_emit_isninst_cast (cfg, klass_reg, klass->cast_class, false_bb, is_null_bb);
4653                 } else {
4654                         if (!cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
4655                                 g_assert (!context_used);
4656                                 /* the remoting code is broken, access the class for now */
4657                                 if (0) {/*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4658                                         MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4659                                         if (!vt) {
4660                                                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4661                                                 cfg->exception_ptr = klass;
4662                                                 return NULL;
4663                                         }
4664                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4665                                 } else {
4666                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4667                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4668                                 }
4669                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4670                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, is_null_bb);
4671                         } else {
4672                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4673                                 /* the is_null_bb target simply copies the input register to the output */
4674                                 mini_emit_isninst_cast_inst (cfg, klass_reg, klass, klass_inst, false_bb, is_null_bb);
4675                         }
4676                 }
4677         }
4678
4679         MONO_START_BB (cfg, false_bb);
4680
4681         MONO_EMIT_NEW_PCONST (cfg, res_reg, 0);
4682         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4683
4684         MONO_START_BB (cfg, is_null_bb);
4685
4686         MONO_START_BB (cfg, end_bb);
4687
4688         return ins;
4689 }
4690
4691 static MonoInst*
4692 handle_cisinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4693 {
4694         /* This opcode takes as input an object reference and a class, and returns:
4695         0) if the object is an instance of the class,
4696         1) if the object is not instance of the class,
4697         2) if the object is a proxy whose type cannot be determined */
4698
4699         MonoInst *ins;
4700 #ifndef DISABLE_REMOTING
4701         MonoBasicBlock *true_bb, *false_bb, *false2_bb, *end_bb, *no_proxy_bb, *interface_fail_bb;
4702 #else
4703         MonoBasicBlock *true_bb, *false_bb, *end_bb;
4704 #endif
4705         int obj_reg = src->dreg;
4706         int dreg = alloc_ireg (cfg);
4707         int tmp_reg;
4708 #ifndef DISABLE_REMOTING
4709         int klass_reg = alloc_preg (cfg);
4710 #endif
4711
4712         NEW_BBLOCK (cfg, true_bb);
4713         NEW_BBLOCK (cfg, false_bb);
4714         NEW_BBLOCK (cfg, end_bb);
4715 #ifndef DISABLE_REMOTING
4716         NEW_BBLOCK (cfg, false2_bb);
4717         NEW_BBLOCK (cfg, no_proxy_bb);
4718 #endif
4719
4720         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4721         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, false_bb);
4722
4723         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4724 #ifndef DISABLE_REMOTING
4725                 NEW_BBLOCK (cfg, interface_fail_bb);
4726 #endif
4727
4728                 tmp_reg = alloc_preg (cfg);
4729                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4730 #ifndef DISABLE_REMOTING
4731                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, true_bb);
4732                 MONO_START_BB (cfg, interface_fail_bb);
4733                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4734                 
4735                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, false_bb);
4736
4737                 tmp_reg = alloc_preg (cfg);
4738                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4739                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4740                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false2_bb);                
4741 #else
4742                 mini_emit_iface_cast (cfg, tmp_reg, klass, false_bb, true_bb);
4743 #endif
4744         } else {
4745 #ifndef DISABLE_REMOTING
4746                 tmp_reg = alloc_preg (cfg);
4747                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4748                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4749
4750                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4751                 tmp_reg = alloc_preg (cfg);
4752                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4753                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4754
4755                 tmp_reg = alloc_preg (cfg);             
4756                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4757                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4758                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4759                 
4760                 mini_emit_isninst_cast (cfg, klass_reg, klass, false2_bb, true_bb);
4761                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false2_bb);
4762
4763                 MONO_START_BB (cfg, no_proxy_bb);
4764
4765                 mini_emit_isninst_cast (cfg, klass_reg, klass, false_bb, true_bb);
4766 #else
4767                 g_error ("transparent proxy support is disabled while trying to JIT code that uses it");
4768 #endif
4769         }
4770
4771         MONO_START_BB (cfg, false_bb);
4772
4773         MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4774         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4775
4776 #ifndef DISABLE_REMOTING
4777         MONO_START_BB (cfg, false2_bb);
4778
4779         MONO_EMIT_NEW_ICONST (cfg, dreg, 2);
4780         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4781 #endif
4782
4783         MONO_START_BB (cfg, true_bb);
4784
4785         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4786
4787         MONO_START_BB (cfg, end_bb);
4788
4789         /* FIXME: */
4790         MONO_INST_NEW (cfg, ins, OP_ICONST);
4791         ins->dreg = dreg;
4792         ins->type = STACK_I4;
4793
4794         return ins;
4795 }
4796
4797 static MonoInst*
4798 handle_ccastclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4799 {
4800         /* This opcode takes as input an object reference and a class, and returns:
4801         0) if the object is an instance of the class,
4802         1) if the object is a proxy whose type cannot be determined
4803         an InvalidCastException exception is thrown otherwhise*/
4804         
4805         MonoInst *ins;
4806 #ifndef DISABLE_REMOTING
4807         MonoBasicBlock *end_bb, *ok_result_bb, *no_proxy_bb, *interface_fail_bb, *fail_1_bb;
4808 #else
4809         MonoBasicBlock *ok_result_bb;
4810 #endif
4811         int obj_reg = src->dreg;
4812         int dreg = alloc_ireg (cfg);
4813         int tmp_reg = alloc_preg (cfg);
4814
4815 #ifndef DISABLE_REMOTING
4816         int klass_reg = alloc_preg (cfg);
4817         NEW_BBLOCK (cfg, end_bb);
4818 #endif
4819
4820         NEW_BBLOCK (cfg, ok_result_bb);
4821
4822         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4823         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, ok_result_bb);
4824
4825         save_cast_details (cfg, klass, obj_reg, FALSE);
4826
4827         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4828 #ifndef DISABLE_REMOTING
4829                 NEW_BBLOCK (cfg, interface_fail_bb);
4830         
4831                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4832                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, ok_result_bb);
4833                 MONO_START_BB (cfg, interface_fail_bb);
4834                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4835
4836                 mini_emit_class_check (cfg, klass_reg, mono_defaults.transparent_proxy_class);
4837
4838                 tmp_reg = alloc_preg (cfg);             
4839                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4840                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4841                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
4842                 
4843                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4844                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4845 #else
4846                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4847                 mini_emit_iface_cast (cfg, tmp_reg, klass, NULL, NULL);
4848                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, ok_result_bb);
4849 #endif
4850         } else {
4851 #ifndef DISABLE_REMOTING
4852                 NEW_BBLOCK (cfg, no_proxy_bb);
4853
4854                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4855                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4856                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4857
4858                 tmp_reg = alloc_preg (cfg);
4859                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4860                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4861
4862                 tmp_reg = alloc_preg (cfg);
4863                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4864                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4865                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4866
4867                 NEW_BBLOCK (cfg, fail_1_bb);
4868                 
4869                 mini_emit_isninst_cast (cfg, klass_reg, klass, fail_1_bb, ok_result_bb);
4870
4871                 MONO_START_BB (cfg, fail_1_bb);
4872
4873                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4874                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4875
4876                 MONO_START_BB (cfg, no_proxy_bb);
4877
4878                 mini_emit_castclass (cfg, obj_reg, klass_reg, klass, ok_result_bb);
4879 #else
4880                 g_error ("Transparent proxy support is disabled while trying to JIT code that uses it");
4881 #endif
4882         }
4883
4884         MONO_START_BB (cfg, ok_result_bb);
4885
4886         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4887
4888 #ifndef DISABLE_REMOTING
4889         MONO_START_BB (cfg, end_bb);
4890 #endif
4891
4892         /* FIXME: */
4893         MONO_INST_NEW (cfg, ins, OP_ICONST);
4894         ins->dreg = dreg;
4895         ins->type = STACK_I4;
4896
4897         return ins;
4898 }
4899
4900 static G_GNUC_UNUSED MonoInst*
4901 handle_enum_has_flag (MonoCompile *cfg, MonoClass *klass, MonoInst *enum_this, MonoInst *enum_flag)
4902 {
4903         MonoType *enum_type = mono_type_get_underlying_type (&klass->byval_arg);
4904         guint32 load_opc = mono_type_to_load_membase (cfg, enum_type);
4905         gboolean is_i4;
4906
4907         switch (enum_type->type) {
4908         case MONO_TYPE_I8:
4909         case MONO_TYPE_U8:
4910 #if SIZEOF_REGISTER == 8
4911         case MONO_TYPE_I:
4912         case MONO_TYPE_U:
4913 #endif
4914                 is_i4 = FALSE;
4915                 break;
4916         default:
4917                 is_i4 = TRUE;
4918                 break;
4919         }
4920
4921         {
4922                 MonoInst *load, *and, *cmp, *ceq;
4923                 int enum_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
4924                 int and_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
4925                 int dest_reg = alloc_ireg (cfg);
4926
4927                 EMIT_NEW_LOAD_MEMBASE (cfg, load, load_opc, enum_reg, enum_this->dreg, 0);
4928                 EMIT_NEW_BIALU (cfg, and, is_i4 ? OP_IAND : OP_LAND, and_reg, enum_reg, enum_flag->dreg);
4929                 EMIT_NEW_BIALU (cfg, cmp, is_i4 ? OP_ICOMPARE : OP_LCOMPARE, -1, and_reg, enum_flag->dreg);
4930                 EMIT_NEW_UNALU (cfg, ceq, is_i4 ? OP_ICEQ : OP_LCEQ, dest_reg, -1);
4931
4932                 ceq->type = STACK_I4;
4933
4934                 if (!is_i4) {
4935                         load = mono_decompose_opcode (cfg, load);
4936                         and = mono_decompose_opcode (cfg, and);
4937                         cmp = mono_decompose_opcode (cfg, cmp);
4938                         ceq = mono_decompose_opcode (cfg, ceq);
4939                 }
4940
4941                 return ceq;
4942         }
4943 }
4944
4945 /*
4946  * Returns NULL and set the cfg exception on error.
4947  */
4948 static G_GNUC_UNUSED MonoInst*
4949 handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, MonoMethod *method, int context_used, gboolean virtual)
4950 {
4951         MonoInst *ptr;
4952         int dreg;
4953         gpointer trampoline;
4954         MonoInst *obj, *method_ins, *tramp_ins;
4955         MonoDomain *domain;
4956         guint8 **code_slot;
4957
4958         if (virtual && !cfg->llvm_only) {
4959                 MonoMethod *invoke = mono_get_delegate_invoke (klass);
4960                 g_assert (invoke);
4961
4962                 if (!mono_get_delegate_virtual_invoke_impl (mono_method_signature (invoke), context_used ? NULL : method))
4963                         return NULL;
4964         }
4965
4966         obj = handle_alloc (cfg, klass, FALSE, mono_class_check_context_used (klass));
4967         if (!obj)
4968                 return NULL;
4969
4970         if (cfg->llvm_only) {
4971                 MonoInst *args [16];
4972
4973                 /*
4974                  * If the method to be called needs an rgctx, we can't fall back to mono_delegate_ctor (), since it might receive
4975                  * the address of a gshared method. So use a JIT icall.
4976                  * FIXME: Optimize this.
4977                  */
4978                 args [0] = obj;
4979                 args [1] = target;
4980                 args [2] = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
4981                 mono_emit_jit_icall (cfg, virtual ? mono_init_delegate_virtual : mono_init_delegate, args);
4982
4983                 return obj;
4984         }
4985
4986         /* Inline the contents of mono_delegate_ctor */
4987
4988         /* Set target field */
4989         /* Optimize away setting of NULL target */
4990         if (!(target->opcode == OP_PCONST && target->inst_p0 == 0)) {
4991                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target), target->dreg);
4992                 if (cfg->gen_write_barriers) {
4993                         dreg = alloc_preg (cfg);
4994                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target));
4995                         emit_write_barrier (cfg, ptr, target);
4996                 }
4997         }
4998
4999         /* Set method field */
5000         method_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
5001         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method), method_ins->dreg);
5002
5003         /* 
5004          * To avoid looking up the compiled code belonging to the target method
5005          * in mono_delegate_trampoline (), we allocate a per-domain memory slot to
5006          * store it, and we fill it after the method has been compiled.
5007          */
5008         if (!method->dynamic && !(cfg->opt & MONO_OPT_SHARED)) {
5009                 MonoInst *code_slot_ins;
5010
5011                 if (context_used) {
5012                         code_slot_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD_DELEGATE_CODE);
5013                 } else {
5014                         domain = mono_domain_get ();
5015                         mono_domain_lock (domain);
5016                         if (!domain_jit_info (domain)->method_code_hash)
5017                                 domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
5018                         code_slot = g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, method);
5019                         if (!code_slot) {
5020                                 code_slot = mono_domain_alloc0 (domain, sizeof (gpointer));
5021                                 g_hash_table_insert (domain_jit_info (domain)->method_code_hash, method, code_slot);
5022                         }
5023                         mono_domain_unlock (domain);
5024
5025                         code_slot_ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_METHOD_CODE_SLOT, method);
5026                 }
5027                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_code), code_slot_ins->dreg);                
5028         }
5029
5030         if (cfg->compile_aot) {
5031                 MonoDelegateClassMethodPair *del_tramp;
5032
5033                 del_tramp = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoDelegateClassMethodPair));
5034                 del_tramp->klass = klass;
5035                 del_tramp->method = context_used ? NULL : method;
5036                 del_tramp->is_virtual = virtual;
5037                 EMIT_NEW_AOTCONST (cfg, tramp_ins, MONO_PATCH_INFO_DELEGATE_TRAMPOLINE, del_tramp);
5038         } else {
5039                 if (virtual)
5040                         trampoline = mono_create_delegate_virtual_trampoline (cfg->domain, klass, context_used ? NULL : method);
5041                 else
5042                         trampoline = mono_create_delegate_trampoline_info (cfg->domain, klass, context_used ? NULL : method);
5043                 EMIT_NEW_PCONST (cfg, tramp_ins, trampoline);
5044         }
5045
5046         /* Set invoke_impl field */
5047         if (virtual) {
5048                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), tramp_ins->dreg);
5049         } else {
5050                 dreg = alloc_preg (cfg);
5051                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, invoke_impl));
5052                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), dreg);
5053
5054                 dreg = alloc_preg (cfg);
5055                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, method_ptr));
5056                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr), dreg);
5057         }
5058
5059         dreg = alloc_preg (cfg);
5060         MONO_EMIT_NEW_ICONST (cfg, dreg, virtual ? 1 : 0);
5061         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_is_virtual), dreg);
5062
5063         /* All the checks which are in mono_delegate_ctor () are done by the delegate trampoline */
5064
5065         return obj;
5066 }
5067
5068 static MonoInst*
5069 handle_array_new (MonoCompile *cfg, int rank, MonoInst **sp, unsigned char *ip)
5070 {
5071         MonoJitICallInfo *info;
5072
5073         /* Need to register the icall so it gets an icall wrapper */
5074         info = mono_get_array_new_va_icall (rank);
5075
5076         cfg->flags |= MONO_CFG_HAS_VARARGS;
5077
5078         /* mono_array_new_va () needs a vararg calling convention */
5079         cfg->disable_llvm = TRUE;
5080
5081         /* FIXME: This uses info->sig, but it should use the signature of the wrapper */
5082         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, sp);
5083 }
5084
5085 /*
5086  * handle_constrained_gsharedvt_call:
5087  *
5088  *   Handle constrained calls where the receiver is a gsharedvt type.
5089  * Return the instruction representing the call. Set the cfg exception on failure.
5090  */
5091 static MonoInst*
5092 handle_constrained_gsharedvt_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp, MonoClass *constrained_class,
5093                                                                    gboolean *ref_emit_widen)
5094 {
5095         MonoInst *ins = NULL;
5096         gboolean emit_widen = *ref_emit_widen;
5097
5098         /*
5099          * Constrained calls need to behave differently at runtime dependending on whenever the receiver is instantiated as ref type or as a vtype.
5100          * 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
5101          * pack the arguments into an array, and do the rest of the work in in an icall.
5102          */
5103         if (((cmethod->klass == mono_defaults.object_class) || (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) || (!cmethod->klass->valuetype && cmethod->klass->image != mono_defaults.corlib)) &&
5104                 (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)) &&
5105                 (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]))))) {
5106                 MonoInst *args [16];
5107
5108                 /*
5109                  * This case handles calls to
5110                  * - object:ToString()/Equals()/GetHashCode(),
5111                  * - System.IComparable<T>:CompareTo()
5112                  * - System.IEquatable<T>:Equals ()
5113                  * plus some simple interface calls enough to support AsyncTaskMethodBuilder.
5114                  */
5115
5116                 args [0] = sp [0];
5117                 if (mono_method_check_context_used (cmethod))
5118                         args [1] = emit_get_rgctx_method (cfg, mono_method_check_context_used (cmethod), cmethod, MONO_RGCTX_INFO_METHOD);
5119                 else
5120                         EMIT_NEW_METHODCONST (cfg, args [1], cmethod);
5121                 args [2] = emit_get_rgctx_klass (cfg, mono_class_check_context_used (constrained_class), constrained_class, MONO_RGCTX_INFO_KLASS);
5122
5123                 /* !fsig->hasthis is for the wrapper for the Object.GetType () icall */
5124                 if (fsig->hasthis && fsig->param_count) {
5125                         /* Pass the arguments using a localloc-ed array using the format expected by runtime_invoke () */
5126                         MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
5127                         ins->dreg = alloc_preg (cfg);
5128                         ins->inst_imm = fsig->param_count * sizeof (mgreg_t);
5129                         MONO_ADD_INS (cfg->cbb, ins);
5130                         args [4] = ins;
5131
5132                         if (mini_is_gsharedvt_type (fsig->params [0])) {
5133                                 int addr_reg;
5134
5135                                 args [3] = emit_get_gsharedvt_info_klass (cfg, mono_class_from_mono_type (fsig->params [0]), MONO_RGCTX_INFO_CLASS_BOX_TYPE);
5136
5137                                 EMIT_NEW_VARLOADA_VREG (cfg, ins, sp [1]->dreg, fsig->params [0]);
5138                                 addr_reg = ins->dreg;
5139                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, addr_reg);
5140                         } else {
5141                                 EMIT_NEW_ICONST (cfg, args [3], 0);
5142                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, sp [1]->dreg);
5143                         }
5144                 } else {
5145                         EMIT_NEW_ICONST (cfg, args [3], 0);
5146                         EMIT_NEW_ICONST (cfg, args [4], 0);
5147                 }
5148                 ins = mono_emit_jit_icall (cfg, mono_gsharedvt_constrained_call, args);
5149                 emit_widen = FALSE;
5150
5151                 if (mini_is_gsharedvt_type (fsig->ret)) {
5152                         ins = handle_unbox_gsharedvt (cfg, mono_class_from_mono_type (fsig->ret), ins);
5153                 } else if (MONO_TYPE_IS_PRIMITIVE (fsig->ret) || MONO_TYPE_ISSTRUCT (fsig->ret)) {
5154                         MonoInst *add;
5155
5156                         /* Unbox */
5157                         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), ins->dreg, sizeof (MonoObject));
5158                         MONO_ADD_INS (cfg->cbb, add);
5159                         /* Load value */
5160                         NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, add->dreg, 0);
5161                         MONO_ADD_INS (cfg->cbb, ins);
5162                         /* ins represents the call result */
5163                 }
5164         } else {
5165                 GSHAREDVT_FAILURE (CEE_CALLVIRT);
5166         }
5167
5168         *ref_emit_widen = emit_widen;
5169
5170         return ins;
5171
5172  exception_exit:
5173         return NULL;
5174 }
5175
5176 static void
5177 mono_emit_load_got_addr (MonoCompile *cfg)
5178 {
5179         MonoInst *getaddr, *dummy_use;
5180
5181         if (!cfg->got_var || cfg->got_var_allocated)
5182                 return;
5183
5184         MONO_INST_NEW (cfg, getaddr, OP_LOAD_GOTADDR);
5185         getaddr->cil_code = cfg->header->code;
5186         getaddr->dreg = cfg->got_var->dreg;
5187
5188         /* Add it to the start of the first bblock */
5189         if (cfg->bb_entry->code) {
5190                 getaddr->next = cfg->bb_entry->code;
5191                 cfg->bb_entry->code = getaddr;
5192         }
5193         else
5194                 MONO_ADD_INS (cfg->bb_entry, getaddr);
5195
5196         cfg->got_var_allocated = TRUE;
5197
5198         /* 
5199          * Add a dummy use to keep the got_var alive, since real uses might
5200          * only be generated by the back ends.
5201          * Add it to end_bblock, so the variable's lifetime covers the whole
5202          * method.
5203          * It would be better to make the usage of the got var explicit in all
5204          * cases when the backend needs it (i.e. calls, throw etc.), so this
5205          * wouldn't be needed.
5206          */
5207         NEW_DUMMY_USE (cfg, dummy_use, cfg->got_var);
5208         MONO_ADD_INS (cfg->bb_exit, dummy_use);
5209 }
5210
5211 static int inline_limit;
5212 static gboolean inline_limit_inited;
5213
5214 static gboolean
5215 mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
5216 {
5217         MonoMethodHeaderSummary header;
5218         MonoVTable *vtable;
5219 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
5220         MonoMethodSignature *sig = mono_method_signature (method);
5221         int i;
5222 #endif
5223
5224         if (cfg->disable_inline)
5225                 return FALSE;
5226         if (cfg->gshared)
5227                 return FALSE;
5228
5229         if (cfg->inline_depth > 10)
5230                 return FALSE;
5231
5232         if (!mono_method_get_header_summary (method, &header))
5233                 return FALSE;
5234
5235         /*runtime, icall and pinvoke are checked by summary call*/
5236         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
5237             (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
5238             (mono_class_is_marshalbyref (method->klass)) ||
5239             header.has_clauses)
5240                 return FALSE;
5241
5242         /* also consider num_locals? */
5243         /* Do the size check early to avoid creating vtables */
5244         if (!inline_limit_inited) {
5245                 if (g_getenv ("MONO_INLINELIMIT"))
5246                         inline_limit = atoi (g_getenv ("MONO_INLINELIMIT"));
5247                 else
5248                         inline_limit = INLINE_LENGTH_LIMIT;
5249                 inline_limit_inited = TRUE;
5250         }
5251         if (header.code_size >= inline_limit && !(method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))
5252                 return FALSE;
5253
5254         /*
5255          * if we can initialize the class of the method right away, we do,
5256          * otherwise we don't allow inlining if the class needs initialization,
5257          * since it would mean inserting a call to mono_runtime_class_init()
5258          * inside the inlined code
5259          */
5260         if (!(cfg->opt & MONO_OPT_SHARED)) {
5261                 /* The AggressiveInlining hint is a good excuse to force that cctor to run. */
5262                 if (method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING) {
5263                         vtable = mono_class_vtable (cfg->domain, method->klass);
5264                         if (!vtable)
5265                                 return FALSE;
5266                         if (!cfg->compile_aot)
5267                                 mono_runtime_class_init (vtable);
5268                 } else if (method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
5269                         if (cfg->run_cctors && method->klass->has_cctor) {
5270                                 /*FIXME it would easier and lazier to just use mono_class_try_get_vtable */
5271                                 if (!method->klass->runtime_info)
5272                                         /* No vtable created yet */
5273                                         return FALSE;
5274                                 vtable = mono_class_vtable (cfg->domain, method->klass);
5275                                 if (!vtable)
5276                                         return FALSE;
5277                                 /* This makes so that inline cannot trigger */
5278                                 /* .cctors: too many apps depend on them */
5279                                 /* running with a specific order... */
5280                                 if (! vtable->initialized)
5281                                         return FALSE;
5282                                 mono_runtime_class_init (vtable);
5283                         }
5284                 } else if (mono_class_needs_cctor_run (method->klass, NULL)) {
5285                         if (!method->klass->runtime_info)
5286                                 /* No vtable created yet */
5287                                 return FALSE;
5288                         vtable = mono_class_vtable (cfg->domain, method->klass);
5289                         if (!vtable)
5290                                 return FALSE;
5291                         if (!vtable->initialized)
5292                                 return FALSE;
5293                 }
5294         } else {
5295                 /* 
5296                  * If we're compiling for shared code
5297                  * the cctor will need to be run at aot method load time, for example,
5298                  * or at the end of the compilation of the inlining method.
5299                  */
5300                 if (mono_class_needs_cctor_run (method->klass, NULL) && !((method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)))
5301                         return FALSE;
5302         }
5303
5304 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
5305         if (mono_arch_is_soft_float ()) {
5306                 /* FIXME: */
5307                 if (sig->ret && sig->ret->type == MONO_TYPE_R4)
5308                         return FALSE;
5309                 for (i = 0; i < sig->param_count; ++i)
5310                         if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_R4)
5311                                 return FALSE;
5312         }
5313 #endif
5314
5315         if (g_list_find (cfg->dont_inline, method))
5316                 return FALSE;
5317
5318         return TRUE;
5319 }
5320
5321 static gboolean
5322 mini_field_access_needs_cctor_run (MonoCompile *cfg, MonoMethod *method, MonoClass *klass, MonoVTable *vtable)
5323 {
5324         if (!cfg->compile_aot) {
5325                 g_assert (vtable);
5326                 if (vtable->initialized)
5327                         return FALSE;
5328         }
5329
5330         if (klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
5331                 if (cfg->method == method)
5332                         return FALSE;
5333         }
5334
5335         if (!mono_class_needs_cctor_run (klass, method))
5336                 return FALSE;
5337
5338         if (! (method->flags & METHOD_ATTRIBUTE_STATIC) && (klass == method->klass))
5339                 /* The initialization is already done before the method is called */
5340                 return FALSE;
5341
5342         return TRUE;
5343 }
5344
5345 static MonoInst*
5346 mini_emit_ldelema_1_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index, gboolean bcheck)
5347 {
5348         MonoInst *ins;
5349         guint32 size;
5350         int mult_reg, add_reg, array_reg, index_reg, index2_reg;
5351         int context_used;
5352
5353         if (mini_is_gsharedvt_variable_klass (klass)) {
5354                 size = -1;
5355         } else {
5356                 mono_class_init (klass);
5357                 size = mono_class_array_element_size (klass);
5358         }
5359
5360         mult_reg = alloc_preg (cfg);
5361         array_reg = arr->dreg;
5362         index_reg = index->dreg;
5363
5364 #if SIZEOF_REGISTER == 8
5365         /* The array reg is 64 bits but the index reg is only 32 */
5366         if (COMPILE_LLVM (cfg)) {
5367                 /* Not needed */
5368                 index2_reg = index_reg;
5369         } else {
5370                 index2_reg = alloc_preg (cfg);
5371                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index2_reg, index_reg);
5372         }
5373 #else
5374         if (index->type == STACK_I8) {
5375                 index2_reg = alloc_preg (cfg);
5376                 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I4, index2_reg, index_reg);
5377         } else {
5378                 index2_reg = index_reg;
5379         }
5380 #endif
5381
5382         if (bcheck)
5383                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index2_reg);
5384
5385 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5386         if (size == 1 || size == 2 || size == 4 || size == 8) {
5387                 static const int fast_log2 [] = { 1, 0, 1, -1, 2, -1, -1, -1, 3 };
5388
5389                 EMIT_NEW_X86_LEA (cfg, ins, array_reg, index2_reg, fast_log2 [size], MONO_STRUCT_OFFSET (MonoArray, vector));
5390                 ins->klass = mono_class_get_element_class (klass);
5391                 ins->type = STACK_MP;
5392
5393                 return ins;
5394         }
5395 #endif          
5396
5397         add_reg = alloc_ireg_mp (cfg);
5398
5399         if (size == -1) {
5400                 MonoInst *rgctx_ins;
5401
5402                 /* gsharedvt */
5403                 g_assert (cfg->gshared);
5404                 context_used = mini_class_check_context_used (cfg, klass);
5405                 g_assert (context_used);
5406                 rgctx_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE);
5407                 MONO_EMIT_NEW_BIALU (cfg, OP_IMUL, mult_reg, index2_reg, rgctx_ins->dreg);
5408         } else {
5409                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MUL_IMM, mult_reg, index2_reg, size);
5410         }
5411         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, array_reg, mult_reg);
5412         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
5413         ins->klass = mono_class_get_element_class (klass);
5414         ins->type = STACK_MP;
5415         MONO_ADD_INS (cfg->cbb, ins);
5416
5417         return ins;
5418 }
5419
5420 static MonoInst*
5421 mini_emit_ldelema_2_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index_ins1, MonoInst *index_ins2)
5422 {
5423         int bounds_reg = alloc_preg (cfg);
5424         int add_reg = alloc_ireg_mp (cfg);
5425         int mult_reg = alloc_preg (cfg);
5426         int mult2_reg = alloc_preg (cfg);
5427         int low1_reg = alloc_preg (cfg);
5428         int low2_reg = alloc_preg (cfg);
5429         int high1_reg = alloc_preg (cfg);
5430         int high2_reg = alloc_preg (cfg);
5431         int realidx1_reg = alloc_preg (cfg);
5432         int realidx2_reg = alloc_preg (cfg);
5433         int sum_reg = alloc_preg (cfg);
5434         int index1, index2, tmpreg;
5435         MonoInst *ins;
5436         guint32 size;
5437
5438         mono_class_init (klass);
5439         size = mono_class_array_element_size (klass);
5440
5441         index1 = index_ins1->dreg;
5442         index2 = index_ins2->dreg;
5443
5444 #if SIZEOF_REGISTER == 8
5445         /* The array reg is 64 bits but the index reg is only 32 */
5446         if (COMPILE_LLVM (cfg)) {
5447                 /* Not needed */
5448         } else {
5449                 tmpreg = alloc_preg (cfg);
5450                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index1);
5451                 index1 = tmpreg;
5452                 tmpreg = alloc_preg (cfg);
5453                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index2);
5454                 index2 = tmpreg;
5455         }
5456 #else
5457         // FIXME: Do we need to do something here for i8 indexes, like in ldelema_1_ins ?
5458         tmpreg = -1;
5459 #endif
5460
5461         /* range checking */
5462         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, 
5463                                        arr->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
5464
5465         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low1_reg, 
5466                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5467         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx1_reg, index1, low1_reg);
5468         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high1_reg, 
5469                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5470         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high1_reg, realidx1_reg);
5471         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
5472
5473         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low2_reg, 
5474                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5475         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx2_reg, index2, low2_reg);
5476         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high2_reg, 
5477                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5478         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high2_reg, realidx2_reg);
5479         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
5480
5481         MONO_EMIT_NEW_BIALU (cfg, OP_PMUL, mult_reg, high2_reg, realidx1_reg);
5482         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, mult_reg, realidx2_reg);
5483         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PMUL_IMM, mult2_reg, sum_reg, size);
5484         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult2_reg, arr->dreg);
5485         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
5486
5487         ins->type = STACK_MP;
5488         ins->klass = klass;
5489         MONO_ADD_INS (cfg->cbb, ins);
5490
5491         return ins;
5492 }
5493
5494 static MonoInst*
5495 mini_emit_ldelema_ins (MonoCompile *cfg, MonoMethod *cmethod, MonoInst **sp, unsigned char *ip, gboolean is_set)
5496 {
5497         int rank;
5498         MonoInst *addr;
5499         MonoMethod *addr_method;
5500         int element_size;
5501         MonoClass *eclass = cmethod->klass->element_class;
5502
5503         rank = mono_method_signature (cmethod)->param_count - (is_set? 1: 0);
5504
5505         if (rank == 1)
5506                 return mini_emit_ldelema_1_ins (cfg, eclass, sp [0], sp [1], TRUE);
5507
5508         /* emit_ldelema_2 depends on OP_LMUL */
5509         if (!cfg->backend->emulate_mul_div && rank == 2 && (cfg->opt & MONO_OPT_INTRINS) && !mini_is_gsharedvt_variable_klass (eclass)) {
5510                 return mini_emit_ldelema_2_ins (cfg, eclass, sp [0], sp [1], sp [2]);
5511         }
5512
5513         if (mini_is_gsharedvt_variable_klass (eclass))
5514                 element_size = 0;
5515         else
5516                 element_size = mono_class_array_element_size (eclass);
5517         addr_method = mono_marshal_get_array_address (rank, element_size);
5518         addr = mono_emit_method_call (cfg, addr_method, sp, NULL);
5519
5520         return addr;
5521 }
5522
5523 static MonoBreakPolicy
5524 always_insert_breakpoint (MonoMethod *method)
5525 {
5526         return MONO_BREAK_POLICY_ALWAYS;
5527 }
5528
5529 static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
5530
5531 /**
5532  * mono_set_break_policy:
5533  * policy_callback: the new callback function
5534  *
5535  * Allow embedders to decide wherther to actually obey breakpoint instructions
5536  * (both break IL instructions and Debugger.Break () method calls), for example
5537  * to not allow an app to be aborted by a perfectly valid IL opcode when executing
5538  * untrusted or semi-trusted code.
5539  *
5540  * @policy_callback will be called every time a break point instruction needs to
5541  * be inserted with the method argument being the method that calls Debugger.Break()
5542  * or has the IL break instruction. The callback should return #MONO_BREAK_POLICY_NEVER
5543  * if it wants the breakpoint to not be effective in the given method.
5544  * #MONO_BREAK_POLICY_ALWAYS is the default.
5545  */
5546 void
5547 mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
5548 {
5549         if (policy_callback)
5550                 break_policy_func = policy_callback;
5551         else
5552                 break_policy_func = always_insert_breakpoint;
5553 }
5554
5555 static gboolean
5556 should_insert_brekpoint (MonoMethod *method) {
5557         switch (break_policy_func (method)) {
5558         case MONO_BREAK_POLICY_ALWAYS:
5559                 return TRUE;
5560         case MONO_BREAK_POLICY_NEVER:
5561                 return FALSE;
5562         case MONO_BREAK_POLICY_ON_DBG:
5563                 g_warning ("mdb no longer supported");
5564                 return FALSE;
5565         default:
5566                 g_warning ("Incorrect value returned from break policy callback");
5567                 return FALSE;
5568         }
5569 }
5570
5571 /* optimize the simple GetGenericValueImpl/SetGenericValueImpl generic icalls */
5572 static MonoInst*
5573 emit_array_generic_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
5574 {
5575         MonoInst *addr, *store, *load;
5576         MonoClass *eklass = mono_class_from_mono_type (fsig->params [2]);
5577
5578         /* the bounds check is already done by the callers */
5579         addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
5580         if (is_set) {
5581                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, args [2]->dreg, 0);
5582                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, addr->dreg, 0, load->dreg);
5583                 if (mini_type_is_reference (fsig->params [2]))
5584                         emit_write_barrier (cfg, addr, load);
5585         } else {
5586                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, addr->dreg, 0);
5587                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, args [2]->dreg, 0, load->dreg);
5588         }
5589         return store;
5590 }
5591
5592
5593 static gboolean
5594 generic_class_is_reference_type (MonoCompile *cfg, MonoClass *klass)
5595 {
5596         return mini_type_is_reference (&klass->byval_arg);
5597 }
5598
5599 static MonoInst*
5600 emit_array_store (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, gboolean safety_checks)
5601 {
5602         if (safety_checks && generic_class_is_reference_type (cfg, klass) &&
5603                 !(sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL)) {
5604                 MonoClass *obj_array = mono_array_class_get_cached (mono_defaults.object_class, 1);
5605                 MonoMethod *helper = mono_marshal_get_virtual_stelemref (obj_array);
5606                 MonoInst *iargs [3];
5607
5608                 if (!helper->slot)
5609                         mono_class_setup_vtable (obj_array);
5610                 g_assert (helper->slot);
5611
5612                 if (sp [0]->type != STACK_OBJ)
5613                         return NULL;
5614                 if (sp [2]->type != STACK_OBJ)
5615                         return NULL;
5616
5617                 iargs [2] = sp [2];
5618                 iargs [1] = sp [1];
5619                 iargs [0] = sp [0];
5620
5621                 return mono_emit_method_call (cfg, helper, iargs, sp [0]);
5622         } else {
5623                 MonoInst *ins;
5624
5625                 if (mini_is_gsharedvt_variable_klass (klass)) {
5626                         MonoInst *addr;
5627
5628                         // FIXME-VT: OP_ICONST optimization
5629                         addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
5630                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5631                         ins->opcode = OP_STOREV_MEMBASE;
5632                 } else if (sp [1]->opcode == OP_ICONST) {
5633                         int array_reg = sp [0]->dreg;
5634                         int index_reg = sp [1]->dreg;
5635                         int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
5636
5637                         if (safety_checks)
5638                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
5639                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset, sp [2]->dreg);
5640                 } else {
5641                         MonoInst *addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], safety_checks);
5642                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5643                         if (generic_class_is_reference_type (cfg, klass))
5644                                 emit_write_barrier (cfg, addr, sp [2]);
5645                 }
5646                 return ins;
5647         }
5648 }
5649
5650 static MonoInst*
5651 emit_array_unsafe_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
5652 {
5653         MonoClass *eklass;
5654         
5655         if (is_set)
5656                 eklass = mono_class_from_mono_type (fsig->params [2]);
5657         else
5658                 eklass = mono_class_from_mono_type (fsig->ret);
5659
5660         if (is_set) {
5661                 return emit_array_store (cfg, eklass, args, FALSE);
5662         } else {
5663                 MonoInst *ins, *addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
5664                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &eklass->byval_arg, addr->dreg, 0);
5665                 return ins;
5666         }
5667 }
5668
5669 static gboolean
5670 is_unsafe_mov_compatible (MonoCompile *cfg, MonoClass *param_klass, MonoClass *return_klass)
5671 {
5672         uint32_t align;
5673         int param_size, return_size;
5674
5675         param_klass = mono_class_from_mono_type (mini_get_underlying_type (&param_klass->byval_arg));
5676         return_klass = mono_class_from_mono_type (mini_get_underlying_type (&return_klass->byval_arg));
5677
5678         if (cfg->verbose_level > 3)
5679                 printf ("[UNSAFE-MOV-INTRISIC] %s <- %s\n", return_klass->name, param_klass->name);
5680
5681         //Don't allow mixing reference types with value types
5682         if (param_klass->valuetype != return_klass->valuetype) {
5683                 if (cfg->verbose_level > 3)
5684                         printf ("[UNSAFE-MOV-INTRISIC]\tone of the args is a valuetype and the other is not\n");
5685                 return FALSE;
5686         }
5687
5688         if (!param_klass->valuetype) {
5689                 if (cfg->verbose_level > 3)
5690                         printf ("[UNSAFE-MOV-INTRISIC]\targs are reference types\n");
5691                 return TRUE;
5692         }
5693
5694         //That are blitable
5695         if (param_klass->has_references || return_klass->has_references)
5696                 return FALSE;
5697
5698         /* Avoid mixing structs and primitive types/enums, they need to be handled differently in the JIT */
5699         if ((MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && !MONO_TYPE_ISSTRUCT (&return_klass->byval_arg)) ||
5700                 (!MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && MONO_TYPE_ISSTRUCT (&return_klass->byval_arg))) {
5701                         if (cfg->verbose_level > 3)
5702                                 printf ("[UNSAFE-MOV-INTRISIC]\tmixing structs and scalars\n");
5703                 return FALSE;
5704         }
5705
5706         if (param_klass->byval_arg.type == MONO_TYPE_R4 || param_klass->byval_arg.type == MONO_TYPE_R8 ||
5707                 return_klass->byval_arg.type == MONO_TYPE_R4 || return_klass->byval_arg.type == MONO_TYPE_R8) {
5708                 if (cfg->verbose_level > 3)
5709                         printf ("[UNSAFE-MOV-INTRISIC]\tfloat or double are not supported\n");
5710                 return FALSE;
5711         }
5712
5713         param_size = mono_class_value_size (param_klass, &align);
5714         return_size = mono_class_value_size (return_klass, &align);
5715
5716         //We can do it if sizes match
5717         if (param_size == return_size) {
5718                 if (cfg->verbose_level > 3)
5719                         printf ("[UNSAFE-MOV-INTRISIC]\tsame size\n");
5720                 return TRUE;
5721         }
5722
5723         //No simple way to handle struct if sizes don't match
5724         if (MONO_TYPE_ISSTRUCT (&param_klass->byval_arg)) {
5725                 if (cfg->verbose_level > 3)
5726                         printf ("[UNSAFE-MOV-INTRISIC]\tsize mismatch and type is a struct\n");
5727                 return FALSE;
5728         }
5729
5730         /*
5731          * Same reg size category.
5732          * A quick note on why we don't require widening here.
5733          * The intrinsic is "R Array.UnsafeMov<S,R> (S s)".
5734          *
5735          * Since the source value comes from a function argument, the JIT will already have
5736          * the value in a VREG and performed any widening needed before (say, when loading from a field).
5737          */
5738         if (param_size <= 4 && return_size <= 4) {
5739                 if (cfg->verbose_level > 3)
5740                         printf ("[UNSAFE-MOV-INTRISIC]\tsize mismatch but both are of the same reg class\n");
5741                 return TRUE;
5742         }
5743
5744         return FALSE;
5745 }
5746
5747 static MonoInst*
5748 emit_array_unsafe_mov (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args)
5749 {
5750         MonoClass *param_klass = mono_class_from_mono_type (fsig->params [0]);
5751         MonoClass *return_klass = mono_class_from_mono_type (fsig->ret);
5752
5753         //Valuetypes that are semantically equivalent or numbers than can be widened to
5754         if (is_unsafe_mov_compatible (cfg, param_klass, return_klass))
5755                 return args [0];
5756
5757         //Arrays of valuetypes that are semantically equivalent
5758         if (param_klass->rank == 1 && return_klass->rank == 1 && is_unsafe_mov_compatible (cfg, param_klass->element_class, return_klass->element_class))
5759                 return args [0];
5760
5761         return NULL;
5762 }
5763
5764 static MonoInst*
5765 mini_emit_inst_for_ctor (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5766 {
5767 #ifdef MONO_ARCH_SIMD_INTRINSICS
5768         MonoInst *ins = NULL;
5769
5770         if (cfg->opt & MONO_OPT_SIMD) {
5771                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
5772                 if (ins)
5773                         return ins;
5774         }
5775 #endif
5776
5777         return mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
5778 }
5779
5780 static MonoInst*
5781 emit_memory_barrier (MonoCompile *cfg, int kind)
5782 {
5783         MonoInst *ins = NULL;
5784         MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
5785         MONO_ADD_INS (cfg->cbb, ins);
5786         ins->backend.memory_barrier_kind = kind;
5787
5788         return ins;
5789 }
5790
5791 static MonoInst*
5792 llvm_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5793 {
5794         MonoInst *ins = NULL;
5795         int opcode = 0;
5796
5797         /* The LLVM backend supports these intrinsics */
5798         if (cmethod->klass == mono_defaults.math_class) {
5799                 if (strcmp (cmethod->name, "Sin") == 0) {
5800                         opcode = OP_SIN;
5801                 } else if (strcmp (cmethod->name, "Cos") == 0) {
5802                         opcode = OP_COS;
5803                 } else if (strcmp (cmethod->name, "Sqrt") == 0) {
5804                         opcode = OP_SQRT;
5805                 } else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8) {
5806                         opcode = OP_ABS;
5807                 }
5808
5809                 if (opcode && fsig->param_count == 1) {
5810                         MONO_INST_NEW (cfg, ins, opcode);
5811                         ins->type = STACK_R8;
5812                         ins->dreg = mono_alloc_freg (cfg);
5813                         ins->sreg1 = args [0]->dreg;
5814                         MONO_ADD_INS (cfg->cbb, ins);
5815                 }
5816
5817                 opcode = 0;
5818                 if (cfg->opt & MONO_OPT_CMOV) {
5819                         if (strcmp (cmethod->name, "Min") == 0) {
5820                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5821                                         opcode = OP_IMIN;
5822                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5823                                         opcode = OP_IMIN_UN;
5824                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5825                                         opcode = OP_LMIN;
5826                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5827                                         opcode = OP_LMIN_UN;
5828                         } else if (strcmp (cmethod->name, "Max") == 0) {
5829                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5830                                         opcode = OP_IMAX;
5831                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5832                                         opcode = OP_IMAX_UN;
5833                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5834                                         opcode = OP_LMAX;
5835                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5836                                         opcode = OP_LMAX_UN;
5837                         }
5838                 }
5839
5840                 if (opcode && fsig->param_count == 2) {
5841                         MONO_INST_NEW (cfg, ins, opcode);
5842                         ins->type = fsig->params [0]->type == MONO_TYPE_I4 ? STACK_I4 : STACK_I8;
5843                         ins->dreg = mono_alloc_ireg (cfg);
5844                         ins->sreg1 = args [0]->dreg;
5845                         ins->sreg2 = args [1]->dreg;
5846                         MONO_ADD_INS (cfg->cbb, ins);
5847                 }
5848         }
5849
5850         return ins;
5851 }
5852
5853 static MonoInst*
5854 mini_emit_inst_for_sharable_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5855 {
5856         if (cmethod->klass == mono_defaults.array_class) {
5857                 if (strcmp (cmethod->name, "UnsafeStore") == 0)
5858                         return emit_array_unsafe_access (cfg, fsig, args, TRUE);
5859                 else if (strcmp (cmethod->name, "UnsafeLoad") == 0)
5860                         return emit_array_unsafe_access (cfg, fsig, args, FALSE);
5861                 else if (strcmp (cmethod->name, "UnsafeMov") == 0)
5862                         return emit_array_unsafe_mov (cfg, fsig, args);
5863         }
5864
5865         return NULL;
5866 }
5867
5868 static MonoInst*
5869 mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5870 {
5871         MonoInst *ins = NULL;
5872
5873         static MonoClass *runtime_helpers_class = NULL;
5874         if (! runtime_helpers_class)
5875                 runtime_helpers_class = mono_class_from_name (mono_defaults.corlib,
5876                         "System.Runtime.CompilerServices", "RuntimeHelpers");
5877
5878         if (cmethod->klass == mono_defaults.string_class) {
5879                 if (strcmp (cmethod->name, "get_Chars") == 0 && fsig->param_count + fsig->hasthis == 2) {
5880                         int dreg = alloc_ireg (cfg);
5881                         int index_reg = alloc_preg (cfg);
5882                         int add_reg = alloc_preg (cfg);
5883
5884 #if SIZEOF_REGISTER == 8
5885                         /* The array reg is 64 bits but the index reg is only 32 */
5886                         MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index_reg, args [1]->dreg);
5887 #else
5888                         index_reg = args [1]->dreg;
5889 #endif  
5890                         MONO_EMIT_BOUNDS_CHECK (cfg, args [0]->dreg, MonoString, length, index_reg);
5891
5892 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5893                         EMIT_NEW_X86_LEA (cfg, ins, args [0]->dreg, index_reg, 1, MONO_STRUCT_OFFSET (MonoString, chars));
5894                         add_reg = ins->dreg;
5895                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5896                                                                    add_reg, 0);
5897 #else
5898                         int mult_reg = alloc_preg (cfg);
5899                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, index_reg, 1);
5900                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
5901                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5902                                                                    add_reg, MONO_STRUCT_OFFSET (MonoString, chars));
5903 #endif
5904                         type_from_op (cfg, ins, NULL, NULL);
5905                         return ins;
5906                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count + fsig->hasthis == 1) {
5907                         int dreg = alloc_ireg (cfg);
5908                         /* Decompose later to allow more optimizations */
5909                         EMIT_NEW_UNALU (cfg, ins, OP_STRLEN, dreg, args [0]->dreg);
5910                         ins->type = STACK_I4;
5911                         ins->flags |= MONO_INST_FAULT;
5912                         cfg->cbb->has_array_access = TRUE;
5913                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
5914
5915                         return ins;
5916                 } else 
5917                         return NULL;
5918         } else if (cmethod->klass == mono_defaults.object_class) {
5919
5920                 if (strcmp (cmethod->name, "GetType") == 0 && fsig->param_count + fsig->hasthis == 1) {
5921                         int dreg = alloc_ireg_ref (cfg);
5922                         int vt_reg = alloc_preg (cfg);
5923                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vt_reg, args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
5924                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, vt_reg, MONO_STRUCT_OFFSET (MonoVTable, type));
5925                         type_from_op (cfg, ins, NULL, NULL);
5926
5927                         return ins;
5928                 } else if (!cfg->backend->emulate_mul_div && strcmp (cmethod->name, "InternalGetHashCode") == 0 && fsig->param_count == 1 && !mono_gc_is_moving ()) {
5929                         int dreg = alloc_ireg (cfg);
5930                         int t1 = alloc_ireg (cfg);
5931         
5932                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, t1, args [0]->dreg, 3);
5933                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_MUL_IMM, dreg, t1, 2654435761u);
5934                         ins->type = STACK_I4;
5935
5936                         return ins;
5937                 } else if (strcmp (cmethod->name, ".ctor") == 0 && fsig->param_count == 0) {
5938                         MONO_INST_NEW (cfg, ins, OP_NOP);
5939                         MONO_ADD_INS (cfg->cbb, ins);
5940                         return ins;
5941                 } else
5942                         return NULL;
5943         } else if (cmethod->klass == mono_defaults.array_class) {
5944                 if (strcmp (cmethod->name, "GetGenericValueImpl") == 0 && fsig->param_count + fsig->hasthis == 3 && !cfg->gsharedvt)
5945                         return emit_array_generic_access (cfg, fsig, args, FALSE);
5946                 else if (strcmp (cmethod->name, "SetGenericValueImpl") == 0 && fsig->param_count + fsig->hasthis == 3 && !cfg->gsharedvt)
5947                         return emit_array_generic_access (cfg, fsig, args, TRUE);
5948
5949 #ifndef MONO_BIG_ARRAYS
5950                 /*
5951                  * This is an inline version of GetLength/GetLowerBound(0) used frequently in
5952                  * Array methods.
5953                  */
5954                 else if (((strcmp (cmethod->name, "GetLength") == 0 && fsig->param_count + fsig->hasthis == 2) ||
5955                          (strcmp (cmethod->name, "GetLowerBound") == 0 && fsig->param_count + fsig->hasthis == 2)) &&
5956                          args [1]->opcode == OP_ICONST && args [1]->inst_c0 == 0) {
5957                         int dreg = alloc_ireg (cfg);
5958                         int bounds_reg = alloc_ireg_mp (cfg);
5959                         MonoBasicBlock *end_bb, *szarray_bb;
5960                         gboolean get_length = strcmp (cmethod->name, "GetLength") == 0;
5961
5962                         NEW_BBLOCK (cfg, end_bb);
5963                         NEW_BBLOCK (cfg, szarray_bb);
5964
5965                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOAD_MEMBASE, bounds_reg,
5966                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
5967                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
5968                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, szarray_bb);
5969                         /* Non-szarray case */
5970                         if (get_length)
5971                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5972                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5973                         else
5974                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5975                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5976                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
5977                         MONO_START_BB (cfg, szarray_bb);
5978                         /* Szarray case */
5979                         if (get_length)
5980                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5981                                                                            args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
5982                         else
5983                                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
5984                         MONO_START_BB (cfg, end_bb);
5985
5986                         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, dreg, dreg);
5987                         ins->type = STACK_I4;
5988                         
5989                         return ins;
5990                 }
5991 #endif
5992
5993                 if (cmethod->name [0] != 'g')
5994                         return NULL;
5995
5996                 if (strcmp (cmethod->name, "get_Rank") == 0 && fsig->param_count + fsig->hasthis == 1) {
5997                         int dreg = alloc_ireg (cfg);
5998                         int vtable_reg = alloc_preg (cfg);
5999                         MONO_EMIT_NEW_LOAD_MEMBASE_OP_FAULT (cfg, OP_LOAD_MEMBASE, vtable_reg, 
6000                                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
6001                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU1_MEMBASE, dreg,
6002                                                                    vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
6003                         type_from_op (cfg, ins, NULL, NULL);
6004
6005                         return ins;
6006                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count + fsig->hasthis == 1) {
6007                         int dreg = alloc_ireg (cfg);
6008
6009                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOADI4_MEMBASE, dreg, 
6010                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
6011                         type_from_op (cfg, ins, NULL, NULL);
6012
6013                         return ins;
6014                 } else
6015                         return NULL;
6016         } else if (cmethod->klass == runtime_helpers_class) {
6017
6018                 if (strcmp (cmethod->name, "get_OffsetToStringData") == 0 && fsig->param_count == 0) {
6019                         EMIT_NEW_ICONST (cfg, ins, MONO_STRUCT_OFFSET (MonoString, chars));
6020                         return ins;
6021                 } else
6022                         return NULL;
6023         } else if (cmethod->klass == mono_defaults.thread_class) {
6024                 if (strcmp (cmethod->name, "SpinWait_nop") == 0 && fsig->param_count == 0) {
6025                         MONO_INST_NEW (cfg, ins, OP_RELAXED_NOP);
6026                         MONO_ADD_INS (cfg->cbb, ins);
6027                         return ins;
6028                 } else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0) {
6029                         return emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6030                 } else if (!strcmp (cmethod->name, "VolatileRead") && fsig->param_count == 1) {
6031                         guint32 opcode = 0;
6032                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6033
6034                         if (fsig->params [0]->type == MONO_TYPE_I1)
6035                                 opcode = OP_LOADI1_MEMBASE;
6036                         else if (fsig->params [0]->type == MONO_TYPE_U1)
6037                                 opcode = OP_LOADU1_MEMBASE;
6038                         else if (fsig->params [0]->type == MONO_TYPE_I2)
6039                                 opcode = OP_LOADI2_MEMBASE;
6040                         else if (fsig->params [0]->type == MONO_TYPE_U2)
6041                                 opcode = OP_LOADU2_MEMBASE;
6042                         else if (fsig->params [0]->type == MONO_TYPE_I4)
6043                                 opcode = OP_LOADI4_MEMBASE;
6044                         else if (fsig->params [0]->type == MONO_TYPE_U4)
6045                                 opcode = OP_LOADU4_MEMBASE;
6046                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
6047                                 opcode = OP_LOADI8_MEMBASE;
6048                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6049                                 opcode = OP_LOADR4_MEMBASE;
6050                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6051                                 opcode = OP_LOADR8_MEMBASE;
6052                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
6053                                 opcode = OP_LOAD_MEMBASE;
6054
6055                         if (opcode) {
6056                                 MONO_INST_NEW (cfg, ins, opcode);
6057                                 ins->inst_basereg = args [0]->dreg;
6058                                 ins->inst_offset = 0;
6059                                 MONO_ADD_INS (cfg->cbb, ins);
6060
6061                                 switch (fsig->params [0]->type) {
6062                                 case MONO_TYPE_I1:
6063                                 case MONO_TYPE_U1:
6064                                 case MONO_TYPE_I2:
6065                                 case MONO_TYPE_U2:
6066                                 case MONO_TYPE_I4:
6067                                 case MONO_TYPE_U4:
6068                                         ins->dreg = mono_alloc_ireg (cfg);
6069                                         ins->type = STACK_I4;
6070                                         break;
6071                                 case MONO_TYPE_I8:
6072                                 case MONO_TYPE_U8:
6073                                         ins->dreg = mono_alloc_lreg (cfg);
6074                                         ins->type = STACK_I8;
6075                                         break;
6076                                 case MONO_TYPE_I:
6077                                 case MONO_TYPE_U:
6078                                         ins->dreg = mono_alloc_ireg (cfg);
6079 #if SIZEOF_REGISTER == 8
6080                                         ins->type = STACK_I8;
6081 #else
6082                                         ins->type = STACK_I4;
6083 #endif
6084                                         break;
6085                                 case MONO_TYPE_R4:
6086                                 case MONO_TYPE_R8:
6087                                         ins->dreg = mono_alloc_freg (cfg);
6088                                         ins->type = STACK_R8;
6089                                         break;
6090                                 default:
6091                                         g_assert (mini_type_is_reference (fsig->params [0]));
6092                                         ins->dreg = mono_alloc_ireg_ref (cfg);
6093                                         ins->type = STACK_OBJ;
6094                                         break;
6095                                 }
6096
6097                                 if (opcode == OP_LOADI8_MEMBASE)
6098                                         ins = mono_decompose_opcode (cfg, ins);
6099
6100                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
6101
6102                                 return ins;
6103                         }
6104                 } else if (!strcmp (cmethod->name, "VolatileWrite") && fsig->param_count == 2) {
6105                         guint32 opcode = 0;
6106                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6107
6108                         if (fsig->params [0]->type == MONO_TYPE_I1 || fsig->params [0]->type == MONO_TYPE_U1)
6109                                 opcode = OP_STOREI1_MEMBASE_REG;
6110                         else if (fsig->params [0]->type == MONO_TYPE_I2 || fsig->params [0]->type == MONO_TYPE_U2)
6111                                 opcode = OP_STOREI2_MEMBASE_REG;
6112                         else if (fsig->params [0]->type == MONO_TYPE_I4 || fsig->params [0]->type == MONO_TYPE_U4)
6113                                 opcode = OP_STOREI4_MEMBASE_REG;
6114                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
6115                                 opcode = OP_STOREI8_MEMBASE_REG;
6116                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6117                                 opcode = OP_STORER4_MEMBASE_REG;
6118                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6119                                 opcode = OP_STORER8_MEMBASE_REG;
6120                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
6121                                 opcode = OP_STORE_MEMBASE_REG;
6122
6123                         if (opcode) {
6124                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
6125
6126                                 MONO_INST_NEW (cfg, ins, opcode);
6127                                 ins->sreg1 = args [1]->dreg;
6128                                 ins->inst_destbasereg = args [0]->dreg;
6129                                 ins->inst_offset = 0;
6130                                 MONO_ADD_INS (cfg->cbb, ins);
6131
6132                                 if (opcode == OP_STOREI8_MEMBASE_REG)
6133                                         ins = mono_decompose_opcode (cfg, ins);
6134
6135                                 return ins;
6136                         }
6137                 }
6138         } else if (cmethod->klass->image == mono_defaults.corlib &&
6139                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
6140                            (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
6141                 ins = NULL;
6142
6143 #if SIZEOF_REGISTER == 8
6144                 if (!cfg->llvm_only && strcmp (cmethod->name, "Read") == 0 && fsig->param_count == 1 && (fsig->params [0]->type == MONO_TYPE_I8)) {
6145                         if (!cfg->llvm_only && mono_arch_opcode_supported (OP_ATOMIC_LOAD_I8)) {
6146                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_LOAD_I8);
6147                                 ins->dreg = mono_alloc_preg (cfg);
6148                                 ins->sreg1 = args [0]->dreg;
6149                                 ins->type = STACK_I8;
6150                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_SEQ;
6151                                 MONO_ADD_INS (cfg->cbb, ins);
6152                         } else {
6153                                 MonoInst *load_ins;
6154
6155                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6156
6157                                 /* 64 bit reads are already atomic */
6158                                 MONO_INST_NEW (cfg, load_ins, OP_LOADI8_MEMBASE);
6159                                 load_ins->dreg = mono_alloc_preg (cfg);
6160                                 load_ins->inst_basereg = args [0]->dreg;
6161                                 load_ins->inst_offset = 0;
6162                                 load_ins->type = STACK_I8;
6163                                 MONO_ADD_INS (cfg->cbb, load_ins);
6164
6165                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6166
6167                                 ins = load_ins;
6168                         }
6169                 }
6170 #endif
6171
6172                 if (strcmp (cmethod->name, "Increment") == 0 && fsig->param_count == 1) {
6173                         MonoInst *ins_iconst;
6174                         guint32 opcode = 0;
6175
6176                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6177                                 opcode = OP_ATOMIC_ADD_I4;
6178                                 cfg->has_atomic_add_i4 = TRUE;
6179                         }
6180 #if SIZEOF_REGISTER == 8
6181                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6182                                 opcode = OP_ATOMIC_ADD_I8;
6183 #endif
6184                         if (opcode) {
6185                                 if (!mono_arch_opcode_supported (opcode))
6186                                         return NULL;
6187                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
6188                                 ins_iconst->inst_c0 = 1;
6189                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
6190                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
6191
6192                                 MONO_INST_NEW (cfg, ins, opcode);
6193                                 ins->dreg = mono_alloc_ireg (cfg);
6194                                 ins->inst_basereg = args [0]->dreg;
6195                                 ins->inst_offset = 0;
6196                                 ins->sreg2 = ins_iconst->dreg;
6197                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6198                                 MONO_ADD_INS (cfg->cbb, ins);
6199                         }
6200                 } else if (strcmp (cmethod->name, "Decrement") == 0 && fsig->param_count == 1) {
6201                         MonoInst *ins_iconst;
6202                         guint32 opcode = 0;
6203
6204                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6205                                 opcode = OP_ATOMIC_ADD_I4;
6206                                 cfg->has_atomic_add_i4 = TRUE;
6207                         }
6208 #if SIZEOF_REGISTER == 8
6209                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6210                                 opcode = OP_ATOMIC_ADD_I8;
6211 #endif
6212                         if (opcode) {
6213                                 if (!mono_arch_opcode_supported (opcode))
6214                                         return NULL;
6215                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
6216                                 ins_iconst->inst_c0 = -1;
6217                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
6218                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
6219
6220                                 MONO_INST_NEW (cfg, ins, opcode);
6221                                 ins->dreg = mono_alloc_ireg (cfg);
6222                                 ins->inst_basereg = args [0]->dreg;
6223                                 ins->inst_offset = 0;
6224                                 ins->sreg2 = ins_iconst->dreg;
6225                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6226                                 MONO_ADD_INS (cfg->cbb, ins);
6227                         }
6228                 } else if (strcmp (cmethod->name, "Add") == 0 && fsig->param_count == 2) {
6229                         guint32 opcode = 0;
6230
6231                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6232                                 opcode = OP_ATOMIC_ADD_I4;
6233                                 cfg->has_atomic_add_i4 = TRUE;
6234                         }
6235 #if SIZEOF_REGISTER == 8
6236                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6237                                 opcode = OP_ATOMIC_ADD_I8;
6238 #endif
6239                         if (opcode) {
6240                                 if (!mono_arch_opcode_supported (opcode))
6241                                         return NULL;
6242                                 MONO_INST_NEW (cfg, ins, opcode);
6243                                 ins->dreg = mono_alloc_ireg (cfg);
6244                                 ins->inst_basereg = args [0]->dreg;
6245                                 ins->inst_offset = 0;
6246                                 ins->sreg2 = args [1]->dreg;
6247                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6248                                 MONO_ADD_INS (cfg->cbb, ins);
6249                         }
6250                 }
6251                 else if (strcmp (cmethod->name, "Exchange") == 0 && fsig->param_count == 2) {
6252                         MonoInst *f2i = NULL, *i2f;
6253                         guint32 opcode, f2i_opcode, i2f_opcode;
6254                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6255                         gboolean is_float = fsig->params [0]->type == MONO_TYPE_R4 || fsig->params [0]->type == MONO_TYPE_R8;
6256
6257                         if (fsig->params [0]->type == MONO_TYPE_I4 ||
6258                             fsig->params [0]->type == MONO_TYPE_R4) {
6259                                 opcode = OP_ATOMIC_EXCHANGE_I4;
6260                                 f2i_opcode = OP_MOVE_F_TO_I4;
6261                                 i2f_opcode = OP_MOVE_I4_TO_F;
6262                                 cfg->has_atomic_exchange_i4 = TRUE;
6263                         }
6264 #if SIZEOF_REGISTER == 8
6265                         else if (is_ref ||
6266                                  fsig->params [0]->type == MONO_TYPE_I8 ||
6267                                  fsig->params [0]->type == MONO_TYPE_R8 ||
6268                                  fsig->params [0]->type == MONO_TYPE_I) {
6269                                 opcode = OP_ATOMIC_EXCHANGE_I8;
6270                                 f2i_opcode = OP_MOVE_F_TO_I8;
6271                                 i2f_opcode = OP_MOVE_I8_TO_F;
6272                         }
6273 #else
6274                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I) {
6275                                 opcode = OP_ATOMIC_EXCHANGE_I4;
6276                                 cfg->has_atomic_exchange_i4 = TRUE;
6277                         }
6278 #endif
6279                         else
6280                                 return NULL;
6281
6282                         if (!mono_arch_opcode_supported (opcode))
6283                                 return NULL;
6284
6285                         if (is_float) {
6286                                 /* TODO: Decompose these opcodes instead of bailing here. */
6287                                 if (COMPILE_SOFT_FLOAT (cfg))
6288                                         return NULL;
6289
6290                                 MONO_INST_NEW (cfg, f2i, f2i_opcode);
6291                                 f2i->dreg = mono_alloc_ireg (cfg);
6292                                 f2i->sreg1 = args [1]->dreg;
6293                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6294                                         f2i->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6295                                 MONO_ADD_INS (cfg->cbb, f2i);
6296                         }
6297
6298                         MONO_INST_NEW (cfg, ins, opcode);
6299                         ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : mono_alloc_ireg (cfg);
6300                         ins->inst_basereg = args [0]->dreg;
6301                         ins->inst_offset = 0;
6302                         ins->sreg2 = is_float ? f2i->dreg : args [1]->dreg;
6303                         MONO_ADD_INS (cfg->cbb, ins);
6304
6305                         switch (fsig->params [0]->type) {
6306                         case MONO_TYPE_I4:
6307                                 ins->type = STACK_I4;
6308                                 break;
6309                         case MONO_TYPE_I8:
6310                                 ins->type = STACK_I8;
6311                                 break;
6312                         case MONO_TYPE_I:
6313 #if SIZEOF_REGISTER == 8
6314                                 ins->type = STACK_I8;
6315 #else
6316                                 ins->type = STACK_I4;
6317 #endif
6318                                 break;
6319                         case MONO_TYPE_R4:
6320                         case MONO_TYPE_R8:
6321                                 ins->type = STACK_R8;
6322                                 break;
6323                         default:
6324                                 g_assert (mini_type_is_reference (fsig->params [0]));
6325                                 ins->type = STACK_OBJ;
6326                                 break;
6327                         }
6328
6329                         if (is_float) {
6330                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
6331                                 i2f->dreg = mono_alloc_freg (cfg);
6332                                 i2f->sreg1 = ins->dreg;
6333                                 i2f->type = STACK_R8;
6334                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
6335                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6336                                 MONO_ADD_INS (cfg->cbb, i2f);
6337
6338                                 ins = i2f;
6339                         }
6340
6341                         if (cfg->gen_write_barriers && is_ref)
6342                                 emit_write_barrier (cfg, args [0], args [1]);
6343                 }
6344                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 3) {
6345                         MonoInst *f2i_new = NULL, *f2i_cmp = NULL, *i2f;
6346                         guint32 opcode, f2i_opcode, i2f_opcode;
6347                         gboolean is_ref = mini_type_is_reference (fsig->params [1]);
6348                         gboolean is_float = fsig->params [1]->type == MONO_TYPE_R4 || fsig->params [1]->type == MONO_TYPE_R8;
6349
6350                         if (fsig->params [1]->type == MONO_TYPE_I4 ||
6351                             fsig->params [1]->type == MONO_TYPE_R4) {
6352                                 opcode = OP_ATOMIC_CAS_I4;
6353                                 f2i_opcode = OP_MOVE_F_TO_I4;
6354                                 i2f_opcode = OP_MOVE_I4_TO_F;
6355                                 cfg->has_atomic_cas_i4 = TRUE;
6356                         }
6357 #if SIZEOF_REGISTER == 8
6358                         else if (is_ref ||
6359                                  fsig->params [1]->type == MONO_TYPE_I8 ||
6360                                  fsig->params [1]->type == MONO_TYPE_R8 ||
6361                                  fsig->params [1]->type == MONO_TYPE_I) {
6362                                 opcode = OP_ATOMIC_CAS_I8;
6363                                 f2i_opcode = OP_MOVE_F_TO_I8;
6364                                 i2f_opcode = OP_MOVE_I8_TO_F;
6365                         }
6366 #else
6367                         else if (is_ref || fsig->params [1]->type == MONO_TYPE_I) {
6368                                 opcode = OP_ATOMIC_CAS_I4;
6369                                 cfg->has_atomic_cas_i4 = TRUE;
6370                         }
6371 #endif
6372                         else
6373                                 return NULL;
6374
6375                         if (!mono_arch_opcode_supported (opcode))
6376                                 return NULL;
6377
6378                         if (is_float) {
6379                                 /* TODO: Decompose these opcodes instead of bailing here. */
6380                                 if (COMPILE_SOFT_FLOAT (cfg))
6381                                         return NULL;
6382
6383                                 MONO_INST_NEW (cfg, f2i_new, f2i_opcode);
6384                                 f2i_new->dreg = mono_alloc_ireg (cfg);
6385                                 f2i_new->sreg1 = args [1]->dreg;
6386                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6387                                         f2i_new->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6388                                 MONO_ADD_INS (cfg->cbb, f2i_new);
6389
6390                                 MONO_INST_NEW (cfg, f2i_cmp, f2i_opcode);
6391                                 f2i_cmp->dreg = mono_alloc_ireg (cfg);
6392                                 f2i_cmp->sreg1 = args [2]->dreg;
6393                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6394                                         f2i_cmp->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6395                                 MONO_ADD_INS (cfg->cbb, f2i_cmp);
6396                         }
6397
6398                         MONO_INST_NEW (cfg, ins, opcode);
6399                         ins->dreg = is_ref ? alloc_ireg_ref (cfg) : alloc_ireg (cfg);
6400                         ins->sreg1 = args [0]->dreg;
6401                         ins->sreg2 = is_float ? f2i_new->dreg : args [1]->dreg;
6402                         ins->sreg3 = is_float ? f2i_cmp->dreg : args [2]->dreg;
6403                         MONO_ADD_INS (cfg->cbb, ins);
6404
6405                         switch (fsig->params [1]->type) {
6406                         case MONO_TYPE_I4:
6407                                 ins->type = STACK_I4;
6408                                 break;
6409                         case MONO_TYPE_I8:
6410                                 ins->type = STACK_I8;
6411                                 break;
6412                         case MONO_TYPE_I:
6413 #if SIZEOF_REGISTER == 8
6414                                 ins->type = STACK_I8;
6415 #else
6416                                 ins->type = STACK_I4;
6417 #endif
6418                                 break;
6419                         case MONO_TYPE_R4:
6420                                 ins->type = cfg->r4_stack_type;
6421                                 break;
6422                         case MONO_TYPE_R8:
6423                                 ins->type = STACK_R8;
6424                                 break;
6425                         default:
6426                                 g_assert (mini_type_is_reference (fsig->params [1]));
6427                                 ins->type = STACK_OBJ;
6428                                 break;
6429                         }
6430
6431                         if (is_float) {
6432                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
6433                                 i2f->dreg = mono_alloc_freg (cfg);
6434                                 i2f->sreg1 = ins->dreg;
6435                                 i2f->type = STACK_R8;
6436                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
6437                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6438                                 MONO_ADD_INS (cfg->cbb, i2f);
6439
6440                                 ins = i2f;
6441                         }
6442
6443                         if (cfg->gen_write_barriers && is_ref)
6444                                 emit_write_barrier (cfg, args [0], args [1]);
6445                 }
6446                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 4 &&
6447                          fsig->params [1]->type == MONO_TYPE_I4) {
6448                         MonoInst *cmp, *ceq;
6449
6450                         if (!mono_arch_opcode_supported (OP_ATOMIC_CAS_I4))
6451                                 return NULL;
6452
6453                         /* int32 r = CAS (location, value, comparand); */
6454                         MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I4);
6455                         ins->dreg = alloc_ireg (cfg);
6456                         ins->sreg1 = args [0]->dreg;
6457                         ins->sreg2 = args [1]->dreg;
6458                         ins->sreg3 = args [2]->dreg;
6459                         ins->type = STACK_I4;
6460                         MONO_ADD_INS (cfg->cbb, ins);
6461
6462                         /* bool result = r == comparand; */
6463                         MONO_INST_NEW (cfg, cmp, OP_ICOMPARE);
6464                         cmp->sreg1 = ins->dreg;
6465                         cmp->sreg2 = args [2]->dreg;
6466                         cmp->type = STACK_I4;
6467                         MONO_ADD_INS (cfg->cbb, cmp);
6468
6469                         MONO_INST_NEW (cfg, ceq, OP_ICEQ);
6470                         ceq->dreg = alloc_ireg (cfg);
6471                         ceq->type = STACK_I4;
6472                         MONO_ADD_INS (cfg->cbb, ceq);
6473
6474                         /* *success = result; */
6475                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, args [3]->dreg, 0, ceq->dreg);
6476
6477                         cfg->has_atomic_cas_i4 = TRUE;
6478                 }
6479                 else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0)
6480                         ins = emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6481
6482                 if (ins)
6483                         return ins;
6484         } else if (cmethod->klass->image == mono_defaults.corlib &&
6485                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
6486                            (strcmp (cmethod->klass->name, "Volatile") == 0)) {
6487                 ins = NULL;
6488
6489                 if (!cfg->llvm_only && !strcmp (cmethod->name, "Read") && fsig->param_count == 1) {
6490                         guint32 opcode = 0;
6491                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6492                         gboolean is_float = fsig->params [0]->type == MONO_TYPE_R4 || fsig->params [0]->type == MONO_TYPE_R8;
6493
6494                         if (fsig->params [0]->type == MONO_TYPE_I1)
6495                                 opcode = OP_ATOMIC_LOAD_I1;
6496                         else if (fsig->params [0]->type == MONO_TYPE_U1 || fsig->params [0]->type == MONO_TYPE_BOOLEAN)
6497                                 opcode = OP_ATOMIC_LOAD_U1;
6498                         else if (fsig->params [0]->type == MONO_TYPE_I2)
6499                                 opcode = OP_ATOMIC_LOAD_I2;
6500                         else if (fsig->params [0]->type == MONO_TYPE_U2)
6501                                 opcode = OP_ATOMIC_LOAD_U2;
6502                         else if (fsig->params [0]->type == MONO_TYPE_I4)
6503                                 opcode = OP_ATOMIC_LOAD_I4;
6504                         else if (fsig->params [0]->type == MONO_TYPE_U4)
6505                                 opcode = OP_ATOMIC_LOAD_U4;
6506                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6507                                 opcode = OP_ATOMIC_LOAD_R4;
6508                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6509                                 opcode = OP_ATOMIC_LOAD_R8;
6510 #if SIZEOF_REGISTER == 8
6511                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_I)
6512                                 opcode = OP_ATOMIC_LOAD_I8;
6513                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_U8 || fsig->params [0]->type == MONO_TYPE_U)
6514                                 opcode = OP_ATOMIC_LOAD_U8;
6515 #else
6516                         else if (fsig->params [0]->type == MONO_TYPE_I)
6517                                 opcode = OP_ATOMIC_LOAD_I4;
6518                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_U)
6519                                 opcode = OP_ATOMIC_LOAD_U4;
6520 #endif
6521
6522                         if (opcode) {
6523                                 if (!mono_arch_opcode_supported (opcode))
6524                                         return NULL;
6525
6526                                 MONO_INST_NEW (cfg, ins, opcode);
6527                                 ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : (is_float ? mono_alloc_freg (cfg) : mono_alloc_ireg (cfg));
6528                                 ins->sreg1 = args [0]->dreg;
6529                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_ACQ;
6530                                 MONO_ADD_INS (cfg->cbb, ins);
6531
6532                                 switch (fsig->params [0]->type) {
6533                                 case MONO_TYPE_BOOLEAN:
6534                                 case MONO_TYPE_I1:
6535                                 case MONO_TYPE_U1:
6536                                 case MONO_TYPE_I2:
6537                                 case MONO_TYPE_U2:
6538                                 case MONO_TYPE_I4:
6539                                 case MONO_TYPE_U4:
6540                                         ins->type = STACK_I4;
6541                                         break;
6542                                 case MONO_TYPE_I8:
6543                                 case MONO_TYPE_U8:
6544                                         ins->type = STACK_I8;
6545                                         break;
6546                                 case MONO_TYPE_I:
6547                                 case MONO_TYPE_U:
6548 #if SIZEOF_REGISTER == 8
6549                                         ins->type = STACK_I8;
6550 #else
6551                                         ins->type = STACK_I4;
6552 #endif
6553                                         break;
6554                                 case MONO_TYPE_R4:
6555                                         ins->type = cfg->r4_stack_type;
6556                                         break;
6557                                 case MONO_TYPE_R8:
6558                                         ins->type = STACK_R8;
6559                                         break;
6560                                 default:
6561                                         g_assert (mini_type_is_reference (fsig->params [0]));
6562                                         ins->type = STACK_OBJ;
6563                                         break;
6564                                 }
6565                         }
6566                 }
6567
6568                 if (!cfg->llvm_only && !strcmp (cmethod->name, "Write") && fsig->param_count == 2) {
6569                         guint32 opcode = 0;
6570                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6571
6572                         if (fsig->params [0]->type == MONO_TYPE_I1)
6573                                 opcode = OP_ATOMIC_STORE_I1;
6574                         else if (fsig->params [0]->type == MONO_TYPE_U1 || fsig->params [0]->type == MONO_TYPE_BOOLEAN)
6575                                 opcode = OP_ATOMIC_STORE_U1;
6576                         else if (fsig->params [0]->type == MONO_TYPE_I2)
6577                                 opcode = OP_ATOMIC_STORE_I2;
6578                         else if (fsig->params [0]->type == MONO_TYPE_U2)
6579                                 opcode = OP_ATOMIC_STORE_U2;
6580                         else if (fsig->params [0]->type == MONO_TYPE_I4)
6581                                 opcode = OP_ATOMIC_STORE_I4;
6582                         else if (fsig->params [0]->type == MONO_TYPE_U4)
6583                                 opcode = OP_ATOMIC_STORE_U4;
6584                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6585                                 opcode = OP_ATOMIC_STORE_R4;
6586                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6587                                 opcode = OP_ATOMIC_STORE_R8;
6588 #if SIZEOF_REGISTER == 8
6589                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_I)
6590                                 opcode = OP_ATOMIC_STORE_I8;
6591                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_U8 || fsig->params [0]->type == MONO_TYPE_U)
6592                                 opcode = OP_ATOMIC_STORE_U8;
6593 #else
6594                         else if (fsig->params [0]->type == MONO_TYPE_I)
6595                                 opcode = OP_ATOMIC_STORE_I4;
6596                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_U)
6597                                 opcode = OP_ATOMIC_STORE_U4;
6598 #endif
6599
6600                         if (opcode) {
6601                                 if (!mono_arch_opcode_supported (opcode))
6602                                         return NULL;
6603
6604                                 MONO_INST_NEW (cfg, ins, opcode);
6605                                 ins->dreg = args [0]->dreg;
6606                                 ins->sreg1 = args [1]->dreg;
6607                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_REL;
6608                                 MONO_ADD_INS (cfg->cbb, ins);
6609
6610                                 if (cfg->gen_write_barriers && is_ref)
6611                                         emit_write_barrier (cfg, args [0], args [1]);
6612                         }
6613                 }
6614
6615                 if (ins)
6616                         return ins;
6617         } else if (cmethod->klass->image == mono_defaults.corlib &&
6618                            (strcmp (cmethod->klass->name_space, "System.Diagnostics") == 0) &&
6619                            (strcmp (cmethod->klass->name, "Debugger") == 0)) {
6620                 if (!strcmp (cmethod->name, "Break") && fsig->param_count == 0) {
6621                         if (should_insert_brekpoint (cfg->method)) {
6622                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
6623                         } else {
6624                                 MONO_INST_NEW (cfg, ins, OP_NOP);
6625                                 MONO_ADD_INS (cfg->cbb, ins);
6626                         }
6627                         return ins;
6628                 }
6629         } else if (cmethod->klass->image == mono_defaults.corlib &&
6630                    (strcmp (cmethod->klass->name_space, "System") == 0) &&
6631                    (strcmp (cmethod->klass->name, "Environment") == 0)) {
6632                 if (!strcmp (cmethod->name, "get_IsRunningOnWindows") && fsig->param_count == 0) {
6633 #ifdef TARGET_WIN32
6634                         EMIT_NEW_ICONST (cfg, ins, 1);
6635 #else
6636                         EMIT_NEW_ICONST (cfg, ins, 0);
6637 #endif
6638                 }
6639         } else if (cmethod->klass->image == mono_defaults.corlib &&
6640                            (strcmp (cmethod->klass->name_space, "System.Reflection") == 0) &&
6641                            (strcmp (cmethod->klass->name, "Assembly") == 0)) {
6642                 if (cfg->llvm_only && !strcmp (cmethod->name, "GetExecutingAssembly")) {
6643                         /* No stack walks are current available, so implement this as an intrinsic */
6644                         MonoInst *assembly_ins;
6645
6646                         EMIT_NEW_AOTCONST (cfg, assembly_ins, MONO_PATCH_INFO_IMAGE, cfg->method->klass->image);
6647                         ins = mono_emit_jit_icall (cfg, mono_get_assembly_object, &assembly_ins);
6648                         return ins;
6649                 }
6650         } else if (cmethod->klass == mono_defaults.math_class) {
6651                 /* 
6652                  * There is general branchless code for Min/Max, but it does not work for 
6653                  * all inputs:
6654                  * http://everything2.com/?node_id=1051618
6655                  */
6656         } else if (((!strcmp (cmethod->klass->image->assembly->aname.name, "MonoMac") ||
6657                     !strcmp (cmethod->klass->image->assembly->aname.name, "monotouch")) &&
6658                                 !strcmp (cmethod->klass->name_space, "XamCore.ObjCRuntime") &&
6659                                 !strcmp (cmethod->klass->name, "Selector")) ||
6660                            (!strcmp (cmethod->klass->image->assembly->aname.name, "Xamarin.iOS") &&
6661                                 !strcmp (cmethod->klass->name_space, "ObjCRuntime") &&
6662                                 !strcmp (cmethod->klass->name, "Selector"))
6663                            ) {
6664                 if (cfg->backend->have_objc_get_selector &&
6665                         !strcmp (cmethod->name, "GetHandle") && fsig->param_count == 1 &&
6666                     (args [0]->opcode == OP_GOT_ENTRY || args [0]->opcode == OP_AOTCONST) &&
6667                     cfg->compile_aot) {
6668                         MonoInst *pi;
6669                         MonoJumpInfoToken *ji;
6670                         MonoString *s;
6671
6672                         cfg->disable_llvm = TRUE;
6673
6674                         if (args [0]->opcode == OP_GOT_ENTRY) {
6675                                 pi = args [0]->inst_p1;
6676                                 g_assert (pi->opcode == OP_PATCH_INFO);
6677                                 g_assert (GPOINTER_TO_INT (pi->inst_p1) == MONO_PATCH_INFO_LDSTR);
6678                                 ji = pi->inst_p0;
6679                         } else {
6680                                 g_assert (GPOINTER_TO_INT (args [0]->inst_p1) == MONO_PATCH_INFO_LDSTR);
6681                                 ji = args [0]->inst_p0;
6682                         }
6683
6684                         NULLIFY_INS (args [0]);
6685
6686                         // FIXME: Ugly
6687                         s = mono_ldstr (cfg->domain, ji->image, mono_metadata_token_index (ji->token));
6688                         MONO_INST_NEW (cfg, ins, OP_OBJC_GET_SELECTOR);
6689                         ins->dreg = mono_alloc_ireg (cfg);
6690                         // FIXME: Leaks
6691                         ins->inst_p0 = mono_string_to_utf8 (s);
6692                         MONO_ADD_INS (cfg->cbb, ins);
6693                         return ins;
6694                 }
6695         }
6696
6697 #ifdef MONO_ARCH_SIMD_INTRINSICS
6698         if (cfg->opt & MONO_OPT_SIMD) {
6699                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
6700                 if (ins)
6701                         return ins;
6702         }
6703 #endif
6704
6705         ins = mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
6706         if (ins)
6707                 return ins;
6708
6709         if (COMPILE_LLVM (cfg)) {
6710                 ins = llvm_emit_inst_for_method (cfg, cmethod, fsig, args);
6711                 if (ins)
6712                         return ins;
6713         }
6714
6715         return mono_arch_emit_inst_for_method (cfg, cmethod, fsig, args);
6716 }
6717
6718 /*
6719  * This entry point could be used later for arbitrary method
6720  * redirection.
6721  */
6722 inline static MonoInst*
6723 mini_redirect_call (MonoCompile *cfg, MonoMethod *method,  
6724                                         MonoMethodSignature *signature, MonoInst **args, MonoInst *this_ins)
6725 {
6726         if (method->klass == mono_defaults.string_class) {
6727                 /* managed string allocation support */
6728                 if (strcmp (method->name, "InternalAllocateStr") == 0 && !(mono_profiler_events & MONO_PROFILE_ALLOCATIONS) && !(cfg->opt & MONO_OPT_SHARED)) {
6729                         MonoInst *iargs [2];
6730                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
6731                         MonoMethod *managed_alloc = NULL;
6732
6733                         g_assert (vtable); /*Should not fail since it System.String*/
6734 #ifndef MONO_CROSS_COMPILE
6735                         managed_alloc = mono_gc_get_managed_allocator (method->klass, FALSE, FALSE);
6736 #endif
6737                         if (!managed_alloc)
6738                                 return NULL;
6739                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
6740                         iargs [1] = args [0];
6741                         return mono_emit_method_call (cfg, managed_alloc, iargs, this_ins);
6742                 }
6743         }
6744         return NULL;
6745 }
6746
6747 static void
6748 mono_save_args (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **sp)
6749 {
6750         MonoInst *store, *temp;
6751         int i;
6752
6753         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
6754                 MonoType *argtype = (sig->hasthis && (i == 0)) ? type_from_stack_type (*sp) : sig->params [i - sig->hasthis];
6755
6756                 /*
6757                  * FIXME: We should use *args++ = sp [0], but that would mean the arg
6758                  * would be different than the MonoInst's used to represent arguments, and
6759                  * the ldelema implementation can't deal with that.
6760                  * Solution: When ldelema is used on an inline argument, create a var for 
6761                  * it, emit ldelema on that var, and emit the saving code below in
6762                  * inline_method () if needed.
6763                  */
6764                 temp = mono_compile_create_var (cfg, argtype, OP_LOCAL);
6765                 cfg->args [i] = temp;
6766                 /* This uses cfg->args [i] which is set by the preceeding line */
6767                 EMIT_NEW_ARGSTORE (cfg, store, i, *sp);
6768                 store->cil_code = sp [0]->cil_code;
6769                 sp++;
6770         }
6771 }
6772
6773 #define MONO_INLINE_CALLED_LIMITED_METHODS 1
6774 #define MONO_INLINE_CALLER_LIMITED_METHODS 1
6775
6776 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
6777 static gboolean
6778 check_inline_called_method_name_limit (MonoMethod *called_method)
6779 {
6780         int strncmp_result;
6781         static const char *limit = NULL;
6782         
6783         if (limit == NULL) {
6784                 const char *limit_string = g_getenv ("MONO_INLINE_CALLED_METHOD_NAME_LIMIT");
6785
6786                 if (limit_string != NULL)
6787                         limit = limit_string;
6788                 else
6789                         limit = "";
6790         }
6791
6792         if (limit [0] != '\0') {
6793                 char *called_method_name = mono_method_full_name (called_method, TRUE);
6794
6795                 strncmp_result = strncmp (called_method_name, limit, strlen (limit));
6796                 g_free (called_method_name);
6797         
6798                 //return (strncmp_result <= 0);
6799                 return (strncmp_result == 0);
6800         } else {
6801                 return TRUE;
6802         }
6803 }
6804 #endif
6805
6806 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
6807 static gboolean
6808 check_inline_caller_method_name_limit (MonoMethod *caller_method)
6809 {
6810         int strncmp_result;
6811         static const char *limit = NULL;
6812         
6813         if (limit == NULL) {
6814                 const char *limit_string = g_getenv ("MONO_INLINE_CALLER_METHOD_NAME_LIMIT");
6815                 if (limit_string != NULL) {
6816                         limit = limit_string;
6817                 } else {
6818                         limit = "";
6819                 }
6820         }
6821
6822         if (limit [0] != '\0') {
6823                 char *caller_method_name = mono_method_full_name (caller_method, TRUE);
6824
6825                 strncmp_result = strncmp (caller_method_name, limit, strlen (limit));
6826                 g_free (caller_method_name);
6827         
6828                 //return (strncmp_result <= 0);
6829                 return (strncmp_result == 0);
6830         } else {
6831                 return TRUE;
6832         }
6833 }
6834 #endif
6835
6836 static void
6837 emit_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
6838 {
6839         static double r8_0 = 0.0;
6840         static float r4_0 = 0.0;
6841         MonoInst *ins;
6842         int t;
6843
6844         rtype = mini_get_underlying_type (rtype);
6845         t = rtype->type;
6846
6847         if (rtype->byref) {
6848                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
6849         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
6850                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
6851         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
6852                 MONO_EMIT_NEW_I8CONST (cfg, dreg, 0);
6853         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
6854                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
6855                 ins->type = STACK_R4;
6856                 ins->inst_p0 = (void*)&r4_0;
6857                 ins->dreg = dreg;
6858                 MONO_ADD_INS (cfg->cbb, ins);
6859         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
6860                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
6861                 ins->type = STACK_R8;
6862                 ins->inst_p0 = (void*)&r8_0;
6863                 ins->dreg = dreg;
6864                 MONO_ADD_INS (cfg->cbb, ins);
6865         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
6866                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
6867                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
6868         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (rtype)) {
6869                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
6870         } else {
6871                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
6872         }
6873 }
6874
6875 static void
6876 emit_dummy_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
6877 {
6878         int t;
6879
6880         rtype = mini_get_underlying_type (rtype);
6881         t = rtype->type;
6882
6883         if (rtype->byref) {
6884                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_PCONST);
6885         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
6886                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_ICONST);
6887         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
6888                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_I8CONST);
6889         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
6890                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R4CONST);
6891         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
6892                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R8CONST);
6893         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
6894                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
6895                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
6896         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (rtype)) {
6897                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
6898         } else {
6899                 emit_init_rvar (cfg, dreg, rtype);
6900         }
6901 }
6902
6903 /* If INIT is FALSE, emit dummy initialization statements to keep the IR valid */
6904 static void
6905 emit_init_local (MonoCompile *cfg, int local, MonoType *type, gboolean init)
6906 {
6907         MonoInst *var = cfg->locals [local];
6908         if (COMPILE_SOFT_FLOAT (cfg)) {
6909                 MonoInst *store;
6910                 int reg = alloc_dreg (cfg, var->type);
6911                 emit_init_rvar (cfg, reg, type);
6912                 EMIT_NEW_LOCSTORE (cfg, store, local, cfg->cbb->last_ins);
6913         } else {
6914                 if (init)
6915                         emit_init_rvar (cfg, var->dreg, type);
6916                 else
6917                         emit_dummy_init_rvar (cfg, var->dreg, type);
6918         }
6919 }
6920
6921 /*
6922  * inline_method:
6923  *
6924  *   Return the cost of inlining CMETHOD.
6925  */
6926 static int
6927 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
6928                            guchar *ip, guint real_offset, gboolean inline_always)
6929 {
6930         MonoInst *ins, *rvar = NULL;
6931         MonoMethodHeader *cheader;
6932         MonoBasicBlock *ebblock, *sbblock;
6933         int i, costs;
6934         MonoMethod *prev_inlined_method;
6935         MonoInst **prev_locals, **prev_args;
6936         MonoType **prev_arg_types;
6937         guint prev_real_offset;
6938         GHashTable *prev_cbb_hash;
6939         MonoBasicBlock **prev_cil_offset_to_bb;
6940         MonoBasicBlock *prev_cbb;
6941         unsigned char* prev_cil_start;
6942         guint32 prev_cil_offset_to_bb_len;
6943         MonoMethod *prev_current_method;
6944         MonoGenericContext *prev_generic_context;
6945         gboolean ret_var_set, prev_ret_var_set, prev_disable_inline, virtual = FALSE;
6946
6947         g_assert (cfg->exception_type == MONO_EXCEPTION_NONE);
6948
6949 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
6950         if ((! inline_always) && ! check_inline_called_method_name_limit (cmethod))
6951                 return 0;
6952 #endif
6953 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
6954         if ((! inline_always) && ! check_inline_caller_method_name_limit (cfg->method))
6955                 return 0;
6956 #endif
6957
6958         if (!fsig)
6959                 fsig = mono_method_signature (cmethod);
6960
6961         if (cfg->verbose_level > 2)
6962                 printf ("INLINE START %p %s -> %s\n", cmethod,  mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
6963
6964         if (!cmethod->inline_info) {
6965                 cfg->stat_inlineable_methods++;
6966                 cmethod->inline_info = 1;
6967         }
6968
6969         /* allocate local variables */
6970         cheader = mono_method_get_header (cmethod);
6971
6972         if (cheader == NULL || mono_loader_get_last_error ()) {
6973                 MonoLoaderError *error = mono_loader_get_last_error ();
6974
6975                 if (cheader)
6976                         mono_metadata_free_mh (cheader);
6977                 if (inline_always && error)
6978                         mono_cfg_set_exception (cfg, error->exception_type);
6979
6980                 mono_loader_clear_error ();
6981                 return 0;
6982         }
6983
6984         /*Must verify before creating locals as it can cause the JIT to assert.*/
6985         if (mono_compile_is_broken (cfg, cmethod, FALSE)) {
6986                 mono_metadata_free_mh (cheader);
6987                 return 0;
6988         }
6989
6990         /* allocate space to store the return value */
6991         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
6992                 rvar = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
6993         }
6994
6995         prev_locals = cfg->locals;
6996         cfg->locals = mono_mempool_alloc0 (cfg->mempool, cheader->num_locals * sizeof (MonoInst*));     
6997         for (i = 0; i < cheader->num_locals; ++i)
6998                 cfg->locals [i] = mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
6999
7000         /* allocate start and end blocks */
7001         /* This is needed so if the inline is aborted, we can clean up */
7002         NEW_BBLOCK (cfg, sbblock);
7003         sbblock->real_offset = real_offset;
7004
7005         NEW_BBLOCK (cfg, ebblock);
7006         ebblock->block_num = cfg->num_bblocks++;
7007         ebblock->real_offset = real_offset;
7008
7009         prev_args = cfg->args;
7010         prev_arg_types = cfg->arg_types;
7011         prev_inlined_method = cfg->inlined_method;
7012         cfg->inlined_method = cmethod;
7013         cfg->ret_var_set = FALSE;
7014         cfg->inline_depth ++;
7015         prev_real_offset = cfg->real_offset;
7016         prev_cbb_hash = cfg->cbb_hash;
7017         prev_cil_offset_to_bb = cfg->cil_offset_to_bb;
7018         prev_cil_offset_to_bb_len = cfg->cil_offset_to_bb_len;
7019         prev_cil_start = cfg->cil_start;
7020         prev_cbb = cfg->cbb;
7021         prev_current_method = cfg->current_method;
7022         prev_generic_context = cfg->generic_context;
7023         prev_ret_var_set = cfg->ret_var_set;
7024         prev_disable_inline = cfg->disable_inline;
7025
7026         if (ip && *ip == CEE_CALLVIRT && !(cmethod->flags & METHOD_ATTRIBUTE_STATIC))
7027                 virtual = TRUE;
7028
7029         costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, rvar, sp, real_offset, virtual);
7030
7031         ret_var_set = cfg->ret_var_set;
7032
7033         cfg->inlined_method = prev_inlined_method;
7034         cfg->real_offset = prev_real_offset;
7035         cfg->cbb_hash = prev_cbb_hash;
7036         cfg->cil_offset_to_bb = prev_cil_offset_to_bb;
7037         cfg->cil_offset_to_bb_len = prev_cil_offset_to_bb_len;
7038         cfg->cil_start = prev_cil_start;
7039         cfg->locals = prev_locals;
7040         cfg->args = prev_args;
7041         cfg->arg_types = prev_arg_types;
7042         cfg->current_method = prev_current_method;
7043         cfg->generic_context = prev_generic_context;
7044         cfg->ret_var_set = prev_ret_var_set;
7045         cfg->disable_inline = prev_disable_inline;
7046         cfg->inline_depth --;
7047
7048         if ((costs >= 0 && costs < 60) || inline_always || (costs >= 0 && (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))) {
7049                 if (cfg->verbose_level > 2)
7050                         printf ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
7051                 
7052                 cfg->stat_inlined_methods++;
7053
7054                 /* always add some code to avoid block split failures */
7055                 MONO_INST_NEW (cfg, ins, OP_NOP);
7056                 MONO_ADD_INS (prev_cbb, ins);
7057
7058                 prev_cbb->next_bb = sbblock;
7059                 link_bblock (cfg, prev_cbb, sbblock);
7060
7061                 /* 
7062                  * Get rid of the begin and end bblocks if possible to aid local
7063                  * optimizations.
7064                  */
7065                 mono_merge_basic_blocks (cfg, prev_cbb, sbblock);
7066
7067                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] != ebblock))
7068                         mono_merge_basic_blocks (cfg, prev_cbb, prev_cbb->out_bb [0]);
7069
7070                 if ((ebblock->in_count == 1) && ebblock->in_bb [0]->out_count == 1) {
7071                         MonoBasicBlock *prev = ebblock->in_bb [0];
7072                         mono_merge_basic_blocks (cfg, prev, ebblock);
7073                         cfg->cbb = prev;
7074                         if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] == prev)) {
7075                                 mono_merge_basic_blocks (cfg, prev_cbb, prev);
7076                                 cfg->cbb = prev_cbb;
7077                         }
7078                 } else {
7079                         /* 
7080                          * Its possible that the rvar is set in some prev bblock, but not in others.
7081                          * (#1835).
7082                          */
7083                         if (rvar) {
7084                                 MonoBasicBlock *bb;
7085
7086                                 for (i = 0; i < ebblock->in_count; ++i) {
7087                                         bb = ebblock->in_bb [i];
7088
7089                                         if (bb->last_ins && bb->last_ins->opcode == OP_NOT_REACHED) {
7090                                                 cfg->cbb = bb;
7091
7092                                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
7093                                         }
7094                                 }
7095                         }
7096
7097                         cfg->cbb = ebblock;
7098                 }
7099
7100                 if (rvar) {
7101                         /*
7102                          * If the inlined method contains only a throw, then the ret var is not 
7103                          * set, so set it to a dummy value.
7104                          */
7105                         if (!ret_var_set)
7106                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
7107
7108                         EMIT_NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
7109                         *sp++ = ins;
7110                 }
7111                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
7112                 return costs + 1;
7113         } else {
7114                 if (cfg->verbose_level > 2)
7115                         printf ("INLINE ABORTED %s (cost %d)\n", mono_method_full_name (cmethod, TRUE), costs);
7116                 cfg->exception_type = MONO_EXCEPTION_NONE;
7117                 mono_loader_clear_error ();
7118
7119                 /* This gets rid of the newly added bblocks */
7120                 cfg->cbb = prev_cbb;
7121         }
7122         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
7123         return 0;
7124 }
7125
7126 /*
7127  * Some of these comments may well be out-of-date.
7128  * Design decisions: we do a single pass over the IL code (and we do bblock 
7129  * splitting/merging in the few cases when it's required: a back jump to an IL
7130  * address that was not already seen as bblock starting point).
7131  * Code is validated as we go (full verification is still better left to metadata/verify.c).
7132  * Complex operations are decomposed in simpler ones right away. We need to let the 
7133  * arch-specific code peek and poke inside this process somehow (except when the 
7134  * optimizations can take advantage of the full semantic info of coarse opcodes).
7135  * All the opcodes of the form opcode.s are 'normalized' to opcode.
7136  * MonoInst->opcode initially is the IL opcode or some simplification of that 
7137  * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific 
7138  * opcode with value bigger than OP_LAST.
7139  * At this point the IR can be handed over to an interpreter, a dumb code generator
7140  * or to the optimizing code generator that will translate it to SSA form.
7141  *
7142  * Profiling directed optimizations.
7143  * We may compile by default with few or no optimizations and instrument the code
7144  * or the user may indicate what methods to optimize the most either in a config file
7145  * or through repeated runs where the compiler applies offline the optimizations to 
7146  * each method and then decides if it was worth it.
7147  */
7148
7149 #define CHECK_TYPE(ins) if (!(ins)->type) UNVERIFIED
7150 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) UNVERIFIED
7151 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) UNVERIFIED
7152 #define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) UNVERIFIED
7153 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
7154 #define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
7155 #define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
7156 #define CHECK_TYPELOAD(klass) if (!(klass) || (klass)->exception_type) TYPE_LOAD_ERROR ((klass))
7157
7158 /* offset from br.s -> br like opcodes */
7159 #define BIG_BRANCH_OFFSET 13
7160
7161 static gboolean
7162 ip_in_bb (MonoCompile *cfg, MonoBasicBlock *bb, const guint8* ip)
7163 {
7164         MonoBasicBlock *b = cfg->cil_offset_to_bb [ip - cfg->cil_start];
7165
7166         return b == NULL || b == bb;
7167 }
7168
7169 static int
7170 get_basic_blocks (MonoCompile *cfg, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
7171 {
7172         unsigned char *ip = start;
7173         unsigned char *target;
7174         int i;
7175         guint cli_addr;
7176         MonoBasicBlock *bblock;
7177         const MonoOpcode *opcode;
7178
7179         while (ip < end) {
7180                 cli_addr = ip - start;
7181                 i = mono_opcode_value ((const guint8 **)&ip, end);
7182                 if (i < 0)
7183                         UNVERIFIED;
7184                 opcode = &mono_opcodes [i];
7185                 switch (opcode->argument) {
7186                 case MonoInlineNone:
7187                         ip++; 
7188                         break;
7189                 case MonoInlineString:
7190                 case MonoInlineType:
7191                 case MonoInlineField:
7192                 case MonoInlineMethod:
7193                 case MonoInlineTok:
7194                 case MonoInlineSig:
7195                 case MonoShortInlineR:
7196                 case MonoInlineI:
7197                         ip += 5;
7198                         break;
7199                 case MonoInlineVar:
7200                         ip += 3;
7201                         break;
7202                 case MonoShortInlineVar:
7203                 case MonoShortInlineI:
7204                         ip += 2;
7205                         break;
7206                 case MonoShortInlineBrTarget:
7207                         target = start + cli_addr + 2 + (signed char)ip [1];
7208                         GET_BBLOCK (cfg, bblock, target);
7209                         ip += 2;
7210                         if (ip < end)
7211                                 GET_BBLOCK (cfg, bblock, ip);
7212                         break;
7213                 case MonoInlineBrTarget:
7214                         target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
7215                         GET_BBLOCK (cfg, bblock, target);
7216                         ip += 5;
7217                         if (ip < end)
7218                                 GET_BBLOCK (cfg, bblock, ip);
7219                         break;
7220                 case MonoInlineSwitch: {
7221                         guint32 n = read32 (ip + 1);
7222                         guint32 j;
7223                         ip += 5;
7224                         cli_addr += 5 + 4 * n;
7225                         target = start + cli_addr;
7226                         GET_BBLOCK (cfg, bblock, target);
7227                         
7228                         for (j = 0; j < n; ++j) {
7229                                 target = start + cli_addr + (gint32)read32 (ip);
7230                                 GET_BBLOCK (cfg, bblock, target);
7231                                 ip += 4;
7232                         }
7233                         break;
7234                 }
7235                 case MonoInlineR:
7236                 case MonoInlineI8:
7237                         ip += 9;
7238                         break;
7239                 default:
7240                         g_assert_not_reached ();
7241                 }
7242
7243                 if (i == CEE_THROW) {
7244                         unsigned char *bb_start = ip - 1;
7245                         
7246                         /* Find the start of the bblock containing the throw */
7247                         bblock = NULL;
7248                         while ((bb_start >= start) && !bblock) {
7249                                 bblock = cfg->cil_offset_to_bb [(bb_start) - start];
7250                                 bb_start --;
7251                         }
7252                         if (bblock)
7253                                 bblock->out_of_line = 1;
7254                 }
7255         }
7256         return 0;
7257 unverified:
7258 exception_exit:
7259         *pos = ip;
7260         return 1;
7261 }
7262
7263 static inline MonoMethod *
7264 mini_get_method_allow_open (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
7265 {
7266         MonoMethod *method;
7267
7268         if (m->wrapper_type != MONO_WRAPPER_NONE) {
7269                 method = mono_method_get_wrapper_data (m, token);
7270                 if (context) {
7271                         MonoError error;
7272                         method = mono_class_inflate_generic_method_checked (method, context, &error);
7273                         g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
7274                 }
7275         } else {
7276                 method = mono_get_method_full (m->klass->image, token, klass, context);
7277         }
7278
7279         return method;
7280 }
7281
7282 static inline MonoMethod *
7283 mini_get_method (MonoCompile *cfg, MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
7284 {
7285         MonoMethod *method = mini_get_method_allow_open (m, token, klass, context);
7286
7287         if (method && cfg && !cfg->gshared && mono_class_is_open_constructed_type (&method->klass->byval_arg))
7288                 return NULL;
7289
7290         return method;
7291 }
7292
7293 static inline MonoClass*
7294 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
7295 {
7296         MonoError error;
7297         MonoClass *klass;
7298
7299         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7300                 klass = mono_method_get_wrapper_data (method, token);
7301                 if (context)
7302                         klass = mono_class_inflate_generic_class (klass, context);
7303         } else {
7304                 klass = mono_class_get_and_inflate_typespec_checked (method->klass->image, token, context, &error);
7305                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
7306         }
7307         if (klass)
7308                 mono_class_init (klass);
7309         return klass;
7310 }
7311
7312 static inline MonoMethodSignature*
7313 mini_get_signature (MonoMethod *method, guint32 token, MonoGenericContext *context)
7314 {
7315         MonoMethodSignature *fsig;
7316
7317         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7318                 fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
7319         } else {
7320                 fsig = mono_metadata_parse_signature (method->klass->image, token);
7321         }
7322         if (context) {
7323                 MonoError error;
7324                 fsig = mono_inflate_generic_signature(fsig, context, &error);
7325                 // FIXME:
7326                 g_assert(mono_error_ok(&error));
7327         }
7328         return fsig;
7329 }
7330
7331 static MonoMethod*
7332 throw_exception (void)
7333 {
7334         static MonoMethod *method = NULL;
7335
7336         if (!method) {
7337                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
7338                 method = mono_class_get_method_from_name (secman->securitymanager, "ThrowException", 1);
7339         }
7340         g_assert (method);
7341         return method;
7342 }
7343
7344 static void
7345 emit_throw_exception (MonoCompile *cfg, MonoException *ex)
7346 {
7347         MonoMethod *thrower = throw_exception ();
7348         MonoInst *args [1];
7349
7350         EMIT_NEW_PCONST (cfg, args [0], ex);
7351         mono_emit_method_call (cfg, thrower, args, NULL);
7352 }
7353
7354 /*
7355  * Return the original method is a wrapper is specified. We can only access 
7356  * the custom attributes from the original method.
7357  */
7358 static MonoMethod*
7359 get_original_method (MonoMethod *method)
7360 {
7361         if (method->wrapper_type == MONO_WRAPPER_NONE)
7362                 return method;
7363
7364         /* native code (which is like Critical) can call any managed method XXX FIXME XXX to validate all usages */
7365         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)
7366                 return NULL;
7367
7368         /* in other cases we need to find the original method */
7369         return mono_marshal_method_from_wrapper (method);
7370 }
7371
7372 static void
7373 ensure_method_is_allowed_to_access_field (MonoCompile *cfg, MonoMethod *caller, MonoClassField *field)
7374 {
7375         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
7376         MonoException *ex = mono_security_core_clr_is_field_access_allowed (get_original_method (caller), field);
7377         if (ex)
7378                 emit_throw_exception (cfg, ex);
7379 }
7380
7381 static void
7382 ensure_method_is_allowed_to_call_method (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee)
7383 {
7384         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
7385         MonoException *ex = mono_security_core_clr_is_call_allowed (get_original_method (caller), callee);
7386         if (ex)
7387                 emit_throw_exception (cfg, ex);
7388 }
7389
7390 /*
7391  * Check that the IL instructions at ip are the array initialization
7392  * sequence and return the pointer to the data and the size.
7393  */
7394 static const char*
7395 initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, MonoClass *klass, guint32 len, int *out_size, guint32 *out_field_token)
7396 {
7397         /*
7398          * newarr[System.Int32]
7399          * dup
7400          * ldtoken field valuetype ...
7401          * call void class [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle)
7402          */
7403         if (ip [0] == CEE_DUP && ip [1] == CEE_LDTOKEN && ip [5] == 0x4 && ip [6] == CEE_CALL) {
7404                 MonoError error;
7405                 guint32 token = read32 (ip + 7);
7406                 guint32 field_token = read32 (ip + 2);
7407                 guint32 field_index = field_token & 0xffffff;
7408                 guint32 rva;
7409                 const char *data_ptr;
7410                 int size = 0;
7411                 MonoMethod *cmethod;
7412                 MonoClass *dummy_class;
7413                 MonoClassField *field = mono_field_from_token_checked (method->klass->image, field_token, &dummy_class, NULL, &error);
7414                 int dummy_align;
7415
7416                 if (!field) {
7417                         mono_error_cleanup (&error); /* FIXME don't swallow the error */
7418                         return NULL;
7419                 }
7420
7421                 *out_field_token = field_token;
7422
7423                 cmethod = mini_get_method (NULL, method, token, NULL, NULL);
7424                 if (!cmethod)
7425                         return NULL;
7426                 if (strcmp (cmethod->name, "InitializeArray") || strcmp (cmethod->klass->name, "RuntimeHelpers") || cmethod->klass->image != mono_defaults.corlib)
7427                         return NULL;
7428                 switch (mono_type_get_underlying_type (&klass->byval_arg)->type) {
7429                 case MONO_TYPE_BOOLEAN:
7430                 case MONO_TYPE_I1:
7431                 case MONO_TYPE_U1:
7432                         size = 1; break;
7433                 /* we need to swap on big endian, so punt. Should we handle R4 and R8 as well? */
7434 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
7435                 case MONO_TYPE_CHAR:
7436                 case MONO_TYPE_I2:
7437                 case MONO_TYPE_U2:
7438                         size = 2; break;
7439                 case MONO_TYPE_I4:
7440                 case MONO_TYPE_U4:
7441                 case MONO_TYPE_R4:
7442                         size = 4; break;
7443                 case MONO_TYPE_R8:
7444                 case MONO_TYPE_I8:
7445                 case MONO_TYPE_U8:
7446                         size = 8; break;
7447 #endif
7448                 default:
7449                         return NULL;
7450                 }
7451                 size *= len;
7452                 if (size > mono_type_size (field->type, &dummy_align))
7453                     return NULL;
7454                 *out_size = size;
7455                 /*g_print ("optimized in %s: size: %d, numelems: %d\n", method->name, size, newarr->inst_newa_len->inst_c0);*/
7456                 if (!image_is_dynamic (method->klass->image)) {
7457                         field_index = read32 (ip + 2) & 0xffffff;
7458                         mono_metadata_field_info (method->klass->image, field_index - 1, NULL, &rva, NULL);
7459                         data_ptr = mono_image_rva_map (method->klass->image, rva);
7460                         /*g_print ("field: 0x%08x, rva: %d, rva_ptr: %p\n", read32 (ip + 2), rva, data_ptr);*/
7461                         /* for aot code we do the lookup on load */
7462                         if (aot && data_ptr)
7463                                 return GUINT_TO_POINTER (rva);
7464                 } else {
7465                         /*FIXME is it possible to AOT a SRE assembly not meant to be saved? */ 
7466                         g_assert (!aot);
7467                         data_ptr = mono_field_get_data (field);
7468                 }
7469                 return data_ptr;
7470         }
7471         return NULL;
7472 }
7473
7474 static void
7475 set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsigned char *ip)
7476 {
7477         char *method_fname = mono_method_full_name (method, TRUE);
7478         char *method_code;
7479         MonoMethodHeader *header = mono_method_get_header (method);
7480
7481         if (header->code_size == 0)
7482                 method_code = g_strdup ("method body is empty.");
7483         else
7484                 method_code = mono_disasm_code_one (NULL, method, ip, NULL);
7485         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
7486         cfg->exception_message = g_strdup_printf ("Invalid IL code in %s: %s\n", method_fname, method_code);
7487         g_free (method_fname);
7488         g_free (method_code);
7489         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
7490 }
7491
7492 static void
7493 set_exception_object (MonoCompile *cfg, MonoException *exception)
7494 {
7495         mono_cfg_set_exception (cfg, MONO_EXCEPTION_OBJECT_SUPPLIED);
7496         MONO_GC_REGISTER_ROOT_SINGLE (cfg->exception_ptr, MONO_ROOT_SOURCE_JIT, "jit exception");
7497         cfg->exception_ptr = exception;
7498 }
7499
7500 static void
7501 emit_stloc_ir (MonoCompile *cfg, MonoInst **sp, MonoMethodHeader *header, int n)
7502 {
7503         MonoInst *ins;
7504         guint32 opcode = mono_type_to_regmove (cfg, header->locals [n]);
7505         if ((opcode == OP_MOVE) && cfg->cbb->last_ins == sp [0]  &&
7506                         ((sp [0]->opcode == OP_ICONST) || (sp [0]->opcode == OP_I8CONST))) {
7507                 /* Optimize reg-reg moves away */
7508                 /* 
7509                  * Can't optimize other opcodes, since sp[0] might point to
7510                  * the last ins of a decomposed opcode.
7511                  */
7512                 sp [0]->dreg = (cfg)->locals [n]->dreg;
7513         } else {
7514                 EMIT_NEW_LOCSTORE (cfg, ins, n, *sp);
7515         }
7516 }
7517
7518 /*
7519  * ldloca inhibits many optimizations so try to get rid of it in common
7520  * cases.
7521  */
7522 static inline unsigned char *
7523 emit_optimized_ldloca_ir (MonoCompile *cfg, unsigned char *ip, unsigned char *end, int size)
7524 {
7525         int local, token;
7526         MonoClass *klass;
7527         MonoType *type;
7528
7529         if (size == 1) {
7530                 local = ip [1];
7531                 ip += 2;
7532         } else {
7533                 local = read16 (ip + 2);
7534                 ip += 4;
7535         }
7536         
7537         if (ip + 6 < end && (ip [0] == CEE_PREFIX1) && (ip [1] == CEE_INITOBJ) && ip_in_bb (cfg, cfg->cbb, ip + 1)) {
7538                 /* From the INITOBJ case */
7539                 token = read32 (ip + 2);
7540                 klass = mini_get_class (cfg->current_method, token, cfg->generic_context);
7541                 CHECK_TYPELOAD (klass);
7542                 type = mini_get_underlying_type (&klass->byval_arg);
7543                 emit_init_local (cfg, local, type, TRUE);
7544                 return ip + 6;
7545         }
7546  exception_exit:
7547         return NULL;
7548 }
7549
7550 static gboolean
7551 is_exception_class (MonoClass *klass)
7552 {
7553         while (klass) {
7554                 if (klass == mono_defaults.exception_class)
7555                         return TRUE;
7556                 klass = klass->parent;
7557         }
7558         return FALSE;
7559 }
7560
7561 /*
7562  * is_jit_optimizer_disabled:
7563  *
7564  *   Determine whenever M's assembly has a DebuggableAttribute with the
7565  * IsJITOptimizerDisabled flag set.
7566  */
7567 static gboolean
7568 is_jit_optimizer_disabled (MonoMethod *m)
7569 {
7570         MonoAssembly *ass = m->klass->image->assembly;
7571         MonoCustomAttrInfo* attrs;
7572         static MonoClass *klass;
7573         int i;
7574         gboolean val = FALSE;
7575
7576         g_assert (ass);
7577         if (ass->jit_optimizer_disabled_inited)
7578                 return ass->jit_optimizer_disabled;
7579
7580         if (!klass)
7581                 klass = mono_class_from_name (mono_defaults.corlib, "System.Diagnostics", "DebuggableAttribute");
7582         if (!klass) {
7583                 /* Linked away */
7584                 ass->jit_optimizer_disabled = FALSE;
7585                 mono_memory_barrier ();
7586                 ass->jit_optimizer_disabled_inited = TRUE;
7587                 return FALSE;
7588         }
7589
7590         attrs = mono_custom_attrs_from_assembly (ass);
7591         if (attrs) {
7592                 for (i = 0; i < attrs->num_attrs; ++i) {
7593                         MonoCustomAttrEntry *attr = &attrs->attrs [i];
7594                         const gchar *p;
7595                         MonoMethodSignature *sig;
7596
7597                         if (!attr->ctor || attr->ctor->klass != klass)
7598                                 continue;
7599                         /* Decode the attribute. See reflection.c */
7600                         p = (const char*)attr->data;
7601                         g_assert (read16 (p) == 0x0001);
7602                         p += 2;
7603
7604                         // FIXME: Support named parameters
7605                         sig = mono_method_signature (attr->ctor);
7606                         if (sig->param_count != 2 || sig->params [0]->type != MONO_TYPE_BOOLEAN || sig->params [1]->type != MONO_TYPE_BOOLEAN)
7607                                 continue;
7608                         /* Two boolean arguments */
7609                         p ++;
7610                         val = *p;
7611                 }
7612                 mono_custom_attrs_free (attrs);
7613         }
7614
7615         ass->jit_optimizer_disabled = val;
7616         mono_memory_barrier ();
7617         ass->jit_optimizer_disabled_inited = TRUE;
7618
7619         return val;
7620 }
7621
7622 static gboolean
7623 is_supported_tail_call (MonoCompile *cfg, MonoMethod *method, MonoMethod *cmethod, MonoMethodSignature *fsig, int call_opcode)
7624 {
7625         gboolean supported_tail_call;
7626         int i;
7627
7628         supported_tail_call = mono_arch_tail_call_supported (cfg, mono_method_signature (method), mono_method_signature (cmethod));
7629
7630         for (i = 0; i < fsig->param_count; ++i) {
7631                 if (fsig->params [i]->byref || fsig->params [i]->type == MONO_TYPE_PTR || fsig->params [i]->type == MONO_TYPE_FNPTR)
7632                         /* These can point to the current method's stack */
7633                         supported_tail_call = FALSE;
7634         }
7635         if (fsig->hasthis && cmethod->klass->valuetype)
7636                 /* this might point to the current method's stack */
7637                 supported_tail_call = FALSE;
7638         if (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
7639                 supported_tail_call = FALSE;
7640         if (cfg->method->save_lmf)
7641                 supported_tail_call = FALSE;
7642         if (cmethod->wrapper_type && cmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD)
7643                 supported_tail_call = FALSE;
7644         if (call_opcode != CEE_CALL)
7645                 supported_tail_call = FALSE;
7646
7647         /* Debugging support */
7648 #if 0
7649         if (supported_tail_call) {
7650                 if (!mono_debug_count ())
7651                         supported_tail_call = FALSE;
7652         }
7653 #endif
7654
7655         return supported_tail_call;
7656 }
7657
7658 /*
7659  * handle_ctor_call:
7660  *
7661  *   Handle calls made to ctors from NEWOBJ opcodes.
7662  */
7663 static void
7664 handle_ctor_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used,
7665                                   MonoInst **sp, guint8 *ip, int *inline_costs)
7666 {
7667         MonoInst *vtable_arg = NULL, *callvirt_this_arg = NULL, *ins;
7668
7669         if (cmethod->klass->valuetype && mono_class_generic_sharing_enabled (cmethod->klass) &&
7670                                         mono_method_is_generic_sharable (cmethod, TRUE)) {
7671                 if (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst) {
7672                         mono_class_vtable (cfg->domain, cmethod->klass);
7673                         CHECK_TYPELOAD (cmethod->klass);
7674
7675                         vtable_arg = emit_get_rgctx_method (cfg, context_used,
7676                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
7677                 } else {
7678                         if (context_used) {
7679                                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
7680                                                                                                    cmethod->klass, MONO_RGCTX_INFO_VTABLE);
7681                         } else {
7682                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
7683
7684                                 CHECK_TYPELOAD (cmethod->klass);
7685                                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
7686                         }
7687                 }
7688         }
7689
7690         /* Avoid virtual calls to ctors if possible */
7691         if (mono_class_is_marshalbyref (cmethod->klass))
7692                 callvirt_this_arg = sp [0];
7693
7694         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_ctor (cfg, cmethod, fsig, sp))) {
7695                 g_assert (MONO_TYPE_IS_VOID (fsig->ret));
7696                 CHECK_CFG_EXCEPTION;
7697         } else if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used && !vtable_arg &&
7698                            mono_method_check_inlining (cfg, cmethod) &&
7699                            !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE)) {
7700                 int costs;
7701
7702                 if ((costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, FALSE))) {
7703                         cfg->real_offset += 5;
7704
7705                         *inline_costs += costs - 5;
7706                 } else {
7707                         INLINE_FAILURE ("inline failure");
7708                         // FIXME-VT: Clean this up
7709                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))
7710                                 GSHAREDVT_FAILURE(*ip);
7711                         mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, callvirt_this_arg, NULL, NULL);
7712                 }
7713         } else if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
7714                 MonoInst *addr;
7715
7716                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE);
7717                 mono_emit_calli (cfg, fsig, sp, addr, NULL, vtable_arg);
7718         } else if (context_used &&
7719                            ((!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
7720                                  !mono_class_generic_sharing_enabled (cmethod->klass)) || cfg->gsharedvt)) {
7721                 MonoInst *cmethod_addr;
7722
7723                 /* Generic calls made out of gsharedvt methods cannot be patched, so use an indirect call */
7724
7725                 cmethod_addr = emit_get_rgctx_method (cfg, context_used,
7726                                                                                           cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
7727
7728                 mono_emit_calli (cfg, fsig, sp, cmethod_addr, NULL, vtable_arg);
7729         } else {
7730                 INLINE_FAILURE ("ctor call");
7731                 ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp,
7732                                                                                   callvirt_this_arg, NULL, vtable_arg);
7733         }
7734  exception_exit:
7735         return;
7736 }
7737
7738 static void
7739 emit_setret (MonoCompile *cfg, MonoInst *val)
7740 {
7741         MonoType *ret_type = mini_get_underlying_type (mono_method_signature (cfg->method)->ret);
7742         MonoInst *ins;
7743
7744         if (mini_type_to_stind (cfg, ret_type) == CEE_STOBJ) {
7745                 MonoInst *ret_addr;
7746
7747                 if (!cfg->vret_addr) {
7748                         EMIT_NEW_VARSTORE (cfg, ins, cfg->ret, ret_type, val);
7749                 } else {
7750                         EMIT_NEW_RETLOADA (cfg, ret_addr);
7751
7752                         EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STOREV_MEMBASE, ret_addr->dreg, 0, val->dreg);
7753                         ins->klass = mono_class_from_mono_type (ret_type);
7754                 }
7755         } else {
7756 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
7757                 if (COMPILE_SOFT_FLOAT (cfg) && !ret_type->byref && ret_type->type == MONO_TYPE_R4) {
7758                         MonoInst *iargs [1];
7759                         MonoInst *conv;
7760
7761                         iargs [0] = val;
7762                         conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
7763                         mono_arch_emit_setret (cfg, cfg->method, conv);
7764                 } else {
7765                         mono_arch_emit_setret (cfg, cfg->method, val);
7766                 }
7767 #else
7768                 mono_arch_emit_setret (cfg, cfg->method, val);
7769 #endif
7770         }
7771 }
7772
7773 static MonoMethodSignature*
7774 sig_to_rgctx_sig (MonoMethodSignature *sig)
7775 {
7776         // FIXME: memory allocation
7777         MonoMethodSignature *res;
7778         int i;
7779
7780         res = g_malloc (MONO_SIZEOF_METHOD_SIGNATURE + (sig->param_count + 1) * sizeof (MonoType*));
7781         memcpy (res, sig, MONO_SIZEOF_METHOD_SIGNATURE);
7782         res->param_count = sig->param_count + 1;
7783         for (i = 0; i < sig->param_count; ++i)
7784                 res->params [i] = sig->params [i];
7785         res->params [sig->param_count] = &mono_defaults.int_class->byval_arg;
7786         return res;
7787 }
7788
7789 /*
7790  * mono_method_to_ir:
7791  *
7792  *   Translate the .net IL into linear IR.
7793  */
7794 int
7795 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
7796                    MonoInst *return_var, MonoInst **inline_args, 
7797                    guint inline_offset, gboolean is_virtual_call)
7798 {
7799         MonoError error;
7800         MonoInst *ins, **sp, **stack_start;
7801         MonoBasicBlock *tblock = NULL, *init_localsbb = NULL;
7802         MonoSimpleBasicBlock *bb = NULL, *original_bb = NULL;
7803         MonoMethod *cmethod, *method_definition;
7804         MonoInst **arg_array;
7805         MonoMethodHeader *header;
7806         MonoImage *image;
7807         guint32 token, ins_flag;
7808         MonoClass *klass;
7809         MonoClass *constrained_class = NULL;
7810         unsigned char *ip, *end, *target, *err_pos;
7811         MonoMethodSignature *sig;
7812         MonoGenericContext *generic_context = NULL;
7813         MonoGenericContainer *generic_container = NULL;
7814         MonoType **param_types;
7815         int i, n, start_new_bblock, dreg;
7816         int num_calls = 0, inline_costs = 0;
7817         int breakpoint_id = 0;
7818         guint num_args;
7819         GSList *class_inits = NULL;
7820         gboolean dont_verify, dont_verify_stloc, readonly = FALSE;
7821         int context_used;
7822         gboolean init_locals, seq_points, skip_dead_blocks;
7823         gboolean sym_seq_points = FALSE;
7824         MonoDebugMethodInfo *minfo;
7825         MonoBitSet *seq_point_locs = NULL;
7826         MonoBitSet *seq_point_set_locs = NULL;
7827
7828         cfg->disable_inline = is_jit_optimizer_disabled (method);
7829
7830         /* serialization and xdomain stuff may need access to private fields and methods */
7831         dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
7832         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE;
7833         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH;
7834         dont_verify |= method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; /* bug #77896 */
7835         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP;
7836         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP_INVOKE;
7837
7838         /* still some type unsafety issues in marshal wrappers... (unknown is PtrToStructure) */
7839         dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE;
7840         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_UNKNOWN;
7841         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED;
7842         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_STELEMREF;
7843
7844         image = method->klass->image;
7845         header = mono_method_get_header (method);
7846         if (!header) {
7847                 MonoLoaderError *error;
7848
7849                 if ((error = mono_loader_get_last_error ())) {
7850                         mono_cfg_set_exception (cfg, error->exception_type);
7851                 } else {
7852                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
7853                         cfg->exception_message = g_strdup_printf ("Missing or incorrect header for method %s", cfg->method->name);
7854                 }
7855                 goto exception_exit;
7856         }
7857         generic_container = mono_method_get_generic_container (method);
7858         sig = mono_method_signature (method);
7859         num_args = sig->hasthis + sig->param_count;
7860         ip = (unsigned char*)header->code;
7861         cfg->cil_start = ip;
7862         end = ip + header->code_size;
7863         cfg->stat_cil_code_size += header->code_size;
7864
7865         seq_points = cfg->gen_seq_points && cfg->method == method;
7866
7867         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
7868                 /* We could hit a seq point before attaching to the JIT (#8338) */
7869                 seq_points = FALSE;
7870         }
7871
7872         if (cfg->gen_sdb_seq_points && cfg->method == method) {
7873                 minfo = mono_debug_lookup_method (method);
7874                 if (minfo) {
7875                         MonoSymSeqPoint *sps;
7876                         int i, n_il_offsets;
7877
7878                         mono_debug_get_seq_points (minfo, NULL, NULL, NULL, &sps, &n_il_offsets);
7879                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
7880                         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);
7881                         sym_seq_points = TRUE;
7882                         for (i = 0; i < n_il_offsets; ++i) {
7883                                 if (sps [i].il_offset < header->code_size)
7884                                         mono_bitset_set_fast (seq_point_locs, sps [i].il_offset);
7885                         }
7886                         g_free (sps);
7887                 } else if (!method->wrapper_type && !method->dynamic && mono_debug_image_has_debug_info (method->klass->image)) {
7888                         /* Methods without line number info like auto-generated property accessors */
7889                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
7890                         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);
7891                         sym_seq_points = TRUE;
7892                 }
7893         }
7894
7895         /* 
7896          * Methods without init_locals set could cause asserts in various passes
7897          * (#497220). To work around this, we emit dummy initialization opcodes
7898          * (OP_DUMMY_ICONST etc.) which generate no code. These are only supported
7899          * on some platforms.
7900          */
7901         if ((cfg->opt & MONO_OPT_UNSAFE) && cfg->backend->have_dummy_init)
7902                 init_locals = header->init_locals;
7903         else
7904                 init_locals = TRUE;
7905
7906         method_definition = method;
7907         while (method_definition->is_inflated) {
7908                 MonoMethodInflated *imethod = (MonoMethodInflated *) method_definition;
7909                 method_definition = imethod->declaring;
7910         }
7911
7912         /* SkipVerification is not allowed if core-clr is enabled */
7913         if (!dont_verify && mini_assembly_can_skip_verification (cfg->domain, method)) {
7914                 dont_verify = TRUE;
7915                 dont_verify_stloc = TRUE;
7916         }
7917
7918         if (sig->is_inflated)
7919                 generic_context = mono_method_get_context (method);
7920         else if (generic_container)
7921                 generic_context = &generic_container->context;
7922         cfg->generic_context = generic_context;
7923
7924         if (!cfg->gshared)
7925                 g_assert (!sig->has_type_parameters);
7926
7927         if (sig->generic_param_count && method->wrapper_type == MONO_WRAPPER_NONE) {
7928                 g_assert (method->is_inflated);
7929                 g_assert (mono_method_get_context (method)->method_inst);
7930         }
7931         if (method->is_inflated && mono_method_get_context (method)->method_inst)
7932                 g_assert (sig->generic_param_count);
7933
7934         if (cfg->method == method) {
7935                 cfg->real_offset = 0;
7936         } else {
7937                 cfg->real_offset = inline_offset;
7938         }
7939
7940         cfg->cil_offset_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoBasicBlock*) * header->code_size);
7941         cfg->cil_offset_to_bb_len = header->code_size;
7942
7943         cfg->current_method = method;
7944
7945         if (cfg->verbose_level > 2)
7946                 printf ("method to IR %s\n", mono_method_full_name (method, TRUE));
7947
7948         param_types = mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * num_args);
7949         if (sig->hasthis)
7950                 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
7951         for (n = 0; n < sig->param_count; ++n)
7952                 param_types [n + sig->hasthis] = sig->params [n];
7953         cfg->arg_types = param_types;
7954
7955         cfg->dont_inline = g_list_prepend (cfg->dont_inline, method);
7956         if (cfg->method == method) {
7957
7958                 if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
7959                         cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
7960
7961                 /* ENTRY BLOCK */
7962                 NEW_BBLOCK (cfg, start_bblock);
7963                 cfg->bb_entry = start_bblock;
7964                 start_bblock->cil_code = NULL;
7965                 start_bblock->cil_length = 0;
7966
7967                 /* EXIT BLOCK */
7968                 NEW_BBLOCK (cfg, end_bblock);
7969                 cfg->bb_exit = end_bblock;
7970                 end_bblock->cil_code = NULL;
7971                 end_bblock->cil_length = 0;
7972                 end_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
7973                 g_assert (cfg->num_bblocks == 2);
7974
7975                 arg_array = cfg->args;
7976
7977                 if (header->num_clauses) {
7978                         cfg->spvars = g_hash_table_new (NULL, NULL);
7979                         cfg->exvars = g_hash_table_new (NULL, NULL);
7980                 }
7981                 /* handle exception clauses */
7982                 for (i = 0; i < header->num_clauses; ++i) {
7983                         MonoBasicBlock *try_bb;
7984                         MonoExceptionClause *clause = &header->clauses [i];
7985                         GET_BBLOCK (cfg, try_bb, ip + clause->try_offset);
7986
7987                         try_bb->real_offset = clause->try_offset;
7988                         try_bb->try_start = TRUE;
7989                         try_bb->region = ((i + 1) << 8) | clause->flags;
7990                         GET_BBLOCK (cfg, tblock, ip + clause->handler_offset);
7991                         tblock->real_offset = clause->handler_offset;
7992                         tblock->flags |= BB_EXCEPTION_HANDLER;
7993
7994                         /*
7995                          * Linking the try block with the EH block hinders inlining as we won't be able to 
7996                          * merge the bblocks from inlining and produce an artificial hole for no good reason.
7997                          */
7998                         if (COMPILE_LLVM (cfg))
7999                                 link_bblock (cfg, try_bb, tblock);
8000
8001                         if (*(ip + clause->handler_offset) == CEE_POP)
8002                                 tblock->flags |= BB_EXCEPTION_DEAD_OBJ;
8003
8004                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
8005                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER ||
8006                             clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
8007                                 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
8008                                 MONO_ADD_INS (tblock, ins);
8009
8010                                 if (seq_points && clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY && clause->flags != MONO_EXCEPTION_CLAUSE_FILTER) {
8011                                         /* finally clauses already have a seq point */
8012                                         /* seq points for filter clauses are emitted below */
8013                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
8014                                         MONO_ADD_INS (tblock, ins);
8015                                 }
8016
8017                                 /* todo: is a fault block unsafe to optimize? */
8018                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
8019                                         tblock->flags |= BB_EXCEPTION_UNSAFE;
8020                         }
8021
8022                         /*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);
8023                           while (p < end) {
8024                           printf ("%s", mono_disasm_code_one (NULL, method, p, &p));
8025                           }*/
8026                         /* catch and filter blocks get the exception object on the stack */
8027                         if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
8028                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
8029
8030                                 /* mostly like handle_stack_args (), but just sets the input args */
8031                                 /* printf ("handling clause at IL_%04x\n", clause->handler_offset); */
8032                                 tblock->in_scount = 1;
8033                                 tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
8034                                 tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
8035
8036                                 cfg->cbb = tblock;
8037
8038 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
8039                                 /* The EH code passes in the exception in a register to both JITted and LLVM compiled code */
8040                                 if (!cfg->compile_llvm) {
8041                                         MONO_INST_NEW (cfg, ins, OP_GET_EX_OBJ);
8042                                         ins->dreg = tblock->in_stack [0]->dreg;
8043                                         MONO_ADD_INS (tblock, ins);
8044                                 }
8045 #else
8046                                 MonoInst *dummy_use;
8047
8048                                 /* 
8049                                  * Add a dummy use for the exvar so its liveness info will be
8050                                  * correct.
8051                                  */
8052                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, tblock->in_stack [0]);
8053 #endif
8054
8055                                 if (seq_points && clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
8056                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
8057                                         MONO_ADD_INS (tblock, ins);
8058                                 }
8059                                 
8060                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
8061                                         GET_BBLOCK (cfg, tblock, ip + clause->data.filter_offset);
8062                                         tblock->flags |= BB_EXCEPTION_HANDLER;
8063                                         tblock->real_offset = clause->data.filter_offset;
8064                                         tblock->in_scount = 1;
8065                                         tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
8066                                         /* The filter block shares the exvar with the handler block */
8067                                         tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
8068                                         MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
8069                                         MONO_ADD_INS (tblock, ins);
8070                                 }
8071                         }
8072
8073                         if (clause->flags != MONO_EXCEPTION_CLAUSE_FILTER &&
8074                                         clause->data.catch_class &&
8075                                         cfg->gshared &&
8076                                         mono_class_check_context_used (clause->data.catch_class)) {
8077                                 /*
8078                                  * In shared generic code with catch
8079                                  * clauses containing type variables
8080                                  * the exception handling code has to
8081                                  * be able to get to the rgctx.
8082                                  * Therefore we have to make sure that
8083                                  * the vtable/mrgctx argument (for
8084                                  * static or generic methods) or the
8085                                  * "this" argument (for non-static
8086                                  * methods) are live.
8087                                  */
8088                                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
8089                                                 mini_method_get_context (method)->method_inst ||
8090                                                 method->klass->valuetype) {
8091                                         mono_get_vtable_var (cfg);
8092                                 } else {
8093                                         MonoInst *dummy_use;
8094
8095                                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, arg_array [0]);
8096                                 }
8097                         }
8098                 }
8099         } else {
8100                 arg_array = (MonoInst **) alloca (sizeof (MonoInst *) * num_args);
8101                 cfg->cbb = start_bblock;
8102                 cfg->args = arg_array;
8103                 mono_save_args (cfg, sig, inline_args);
8104         }
8105
8106         /* FIRST CODE BLOCK */
8107         NEW_BBLOCK (cfg, tblock);
8108         tblock->cil_code = ip;
8109         cfg->cbb = tblock;
8110         cfg->ip = ip;
8111
8112         ADD_BBLOCK (cfg, tblock);
8113
8114         if (cfg->method == method) {
8115                 breakpoint_id = mono_debugger_method_has_breakpoint (method);
8116                 if (breakpoint_id) {
8117                         MONO_INST_NEW (cfg, ins, OP_BREAK);
8118                         MONO_ADD_INS (cfg->cbb, ins);
8119                 }
8120         }
8121
8122         /* we use a separate basic block for the initialization code */
8123         NEW_BBLOCK (cfg, init_localsbb);
8124         cfg->bb_init = init_localsbb;
8125         init_localsbb->real_offset = cfg->real_offset;
8126         start_bblock->next_bb = init_localsbb;
8127         init_localsbb->next_bb = cfg->cbb;
8128         link_bblock (cfg, start_bblock, init_localsbb);
8129         link_bblock (cfg, init_localsbb, cfg->cbb);
8130                 
8131         cfg->cbb = init_localsbb;
8132
8133         if (cfg->gsharedvt && cfg->method == method) {
8134                 MonoGSharedVtMethodInfo *info;
8135                 MonoInst *var, *locals_var;
8136                 int dreg;
8137
8138                 info = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoGSharedVtMethodInfo));
8139                 info->method = cfg->method;
8140                 info->count_entries = 16;
8141                 info->entries = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
8142                 cfg->gsharedvt_info = info;
8143
8144                 var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8145                 /* prevent it from being register allocated */
8146                 //var->flags |= MONO_INST_VOLATILE;
8147                 cfg->gsharedvt_info_var = var;
8148
8149                 ins = emit_get_rgctx_gsharedvt_method (cfg, mini_method_check_context_used (cfg, method), method, info);
8150                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, var->dreg, ins->dreg);
8151
8152                 /* Allocate locals */
8153                 locals_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8154                 /* prevent it from being register allocated */
8155                 //locals_var->flags |= MONO_INST_VOLATILE;
8156                 cfg->gsharedvt_locals_var = locals_var;
8157
8158                 dreg = alloc_ireg (cfg);
8159                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, dreg, var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, locals_size));
8160
8161                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
8162                 ins->dreg = locals_var->dreg;
8163                 ins->sreg1 = dreg;
8164                 MONO_ADD_INS (cfg->cbb, ins);
8165                 cfg->gsharedvt_locals_var_ins = ins;
8166                 
8167                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
8168                 /*
8169                 if (init_locals)
8170                         ins->flags |= MONO_INST_INIT;
8171                 */
8172         }
8173
8174         if (mono_security_core_clr_enabled ()) {
8175                 /* check if this is native code, e.g. an icall or a p/invoke */
8176                 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
8177                         MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
8178                         if (wrapped) {
8179                                 gboolean pinvk = (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL);
8180                                 gboolean icall = (wrapped->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL);
8181
8182                                 /* if this ia a native call then it can only be JITted from platform code */
8183                                 if ((icall || pinvk) && method->klass && method->klass->image) {
8184                                         if (!mono_security_core_clr_is_platform_image (method->klass->image)) {
8185                                                 MonoException *ex = icall ? mono_get_exception_security () : 
8186                                                         mono_get_exception_method_access ();
8187                                                 emit_throw_exception (cfg, ex);
8188                                         }
8189                                 }
8190                         }
8191                 }
8192         }
8193
8194         CHECK_CFG_EXCEPTION;
8195
8196         if (header->code_size == 0)
8197                 UNVERIFIED;
8198
8199         if (get_basic_blocks (cfg, header, cfg->real_offset, ip, end, &err_pos)) {
8200                 ip = err_pos;
8201                 UNVERIFIED;
8202         }
8203
8204         if (cfg->method == method)
8205                 mono_debug_init_method (cfg, cfg->cbb, breakpoint_id);
8206
8207         for (n = 0; n < header->num_locals; ++n) {
8208                 if (header->locals [n]->type == MONO_TYPE_VOID && !header->locals [n]->byref)
8209                         UNVERIFIED;
8210         }
8211         class_inits = NULL;
8212
8213         /* We force the vtable variable here for all shared methods
8214            for the possibility that they might show up in a stack
8215            trace where their exact instantiation is needed. */
8216         if (cfg->gshared && method == cfg->method) {
8217                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
8218                                 mini_method_get_context (method)->method_inst ||
8219                                 method->klass->valuetype) {
8220                         mono_get_vtable_var (cfg);
8221                 } else {
8222                         /* FIXME: Is there a better way to do this?
8223                            We need the variable live for the duration
8224                            of the whole method. */
8225                         cfg->args [0]->flags |= MONO_INST_VOLATILE;
8226                 }
8227         }
8228
8229         /* add a check for this != NULL to inlined methods */
8230         if (is_virtual_call) {
8231                 MonoInst *arg_ins;
8232
8233                 NEW_ARGLOAD (cfg, arg_ins, 0);
8234                 MONO_ADD_INS (cfg->cbb, arg_ins);
8235                 MONO_EMIT_NEW_CHECK_THIS (cfg, arg_ins->dreg);
8236         }
8237
8238         skip_dead_blocks = !dont_verify;
8239         if (skip_dead_blocks) {
8240                 original_bb = bb = mono_basic_block_split (method, &cfg->error);
8241                 CHECK_CFG_ERROR;
8242                 g_assert (bb);
8243         }
8244
8245         /* we use a spare stack slot in SWITCH and NEWOBJ and others */
8246         stack_start = sp = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
8247
8248         ins_flag = 0;
8249         start_new_bblock = 0;
8250         while (ip < end) {
8251                 if (cfg->method == method)
8252                         cfg->real_offset = ip - header->code;
8253                 else
8254                         cfg->real_offset = inline_offset;
8255                 cfg->ip = ip;
8256
8257                 context_used = 0;
8258
8259                 if (start_new_bblock) {
8260                         cfg->cbb->cil_length = ip - cfg->cbb->cil_code;
8261                         if (start_new_bblock == 2) {
8262                                 g_assert (ip == tblock->cil_code);
8263                         } else {
8264                                 GET_BBLOCK (cfg, tblock, ip);
8265                         }
8266                         cfg->cbb->next_bb = tblock;
8267                         cfg->cbb = tblock;
8268                         start_new_bblock = 0;
8269                         for (i = 0; i < cfg->cbb->in_scount; ++i) {
8270                                 if (cfg->verbose_level > 3)
8271                                         printf ("loading %d from temp %d\n", i, (int)cfg->cbb->in_stack [i]->inst_c0);
8272                                 EMIT_NEW_TEMPLOAD (cfg, ins, cfg->cbb->in_stack [i]->inst_c0);
8273                                 *sp++ = ins;
8274                         }
8275                         if (class_inits)
8276                                 g_slist_free (class_inits);
8277                         class_inits = NULL;
8278                 } else {
8279                         if ((tblock = cfg->cil_offset_to_bb [ip - cfg->cil_start]) && (tblock != cfg->cbb)) {
8280                                 link_bblock (cfg, cfg->cbb, tblock);
8281                                 if (sp != stack_start) {
8282                                         handle_stack_args (cfg, stack_start, sp - stack_start);
8283                                         sp = stack_start;
8284                                         CHECK_UNVERIFIABLE (cfg);
8285                                 }
8286                                 cfg->cbb->next_bb = tblock;
8287                                 cfg->cbb = tblock;
8288                                 for (i = 0; i < cfg->cbb->in_scount; ++i) {
8289                                         if (cfg->verbose_level > 3)
8290                                                 printf ("loading %d from temp %d\n", i, (int)cfg->cbb->in_stack [i]->inst_c0);
8291                                         EMIT_NEW_TEMPLOAD (cfg, ins, cfg->cbb->in_stack [i]->inst_c0);
8292                                         *sp++ = ins;
8293                                 }
8294                                 g_slist_free (class_inits);
8295                                 class_inits = NULL;
8296                         }
8297                 }
8298
8299                 if (skip_dead_blocks) {
8300                         int ip_offset = ip - header->code;
8301
8302                         if (ip_offset == bb->end)
8303                                 bb = bb->next;
8304
8305                         if (bb->dead) {
8306                                 int op_size = mono_opcode_size (ip, end);
8307                                 g_assert (op_size > 0); /*The BB formation pass must catch all bad ops*/
8308
8309                                 if (cfg->verbose_level > 3) printf ("SKIPPING DEAD OP at %x\n", ip_offset);
8310
8311                                 if (ip_offset + op_size == bb->end) {
8312                                         MONO_INST_NEW (cfg, ins, OP_NOP);
8313                                         MONO_ADD_INS (cfg->cbb, ins);
8314                                         start_new_bblock = 1;
8315                                 }
8316
8317                                 ip += op_size;
8318                                 continue;
8319                         }
8320                 }
8321                 /*
8322                  * Sequence points are points where the debugger can place a breakpoint.
8323                  * Currently, we generate these automatically at points where the IL
8324                  * stack is empty.
8325                  */
8326                 if (seq_points && ((!sym_seq_points && (sp == stack_start)) || (sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code)))) {
8327                         /*
8328                          * Make methods interruptable at the beginning, and at the targets of
8329                          * backward branches.
8330                          * Also, do this at the start of every bblock in methods with clauses too,
8331                          * to be able to handle instructions with inprecise control flow like
8332                          * throw/endfinally.
8333                          * Backward branches are handled at the end of method-to-ir ().
8334                          */
8335                         gboolean intr_loc = ip == header->code || (!cfg->cbb->last_ins && cfg->header->num_clauses);
8336                         gboolean sym_seq_point = sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code);
8337
8338                         /* Avoid sequence points on empty IL like .volatile */
8339                         // FIXME: Enable this
8340                         //if (!(cfg->cbb->last_ins && cfg->cbb->last_ins->opcode == OP_SEQ_POINT)) {
8341                         NEW_SEQ_POINT (cfg, ins, ip - header->code, intr_loc);
8342                         if ((sp != stack_start) && !sym_seq_point)
8343                                 ins->flags |= MONO_INST_NONEMPTY_STACK;
8344                         MONO_ADD_INS (cfg->cbb, ins);
8345
8346                         if (sym_seq_points)
8347                                 mono_bitset_set_fast (seq_point_set_locs, ip - header->code);
8348                 }
8349
8350                 cfg->cbb->real_offset = cfg->real_offset;
8351
8352                 if ((cfg->method == method) && cfg->coverage_info) {
8353                         guint32 cil_offset = ip - header->code;
8354                         cfg->coverage_info->data [cil_offset].cil_code = ip;
8355
8356                         /* TODO: Use an increment here */
8357 #if defined(TARGET_X86)
8358                         MONO_INST_NEW (cfg, ins, OP_STORE_MEM_IMM);
8359                         ins->inst_p0 = &(cfg->coverage_info->data [cil_offset].count);
8360                         ins->inst_imm = 1;
8361                         MONO_ADD_INS (cfg->cbb, ins);
8362 #else
8363                         EMIT_NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
8364                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, ins->dreg, 0, 1);
8365 #endif
8366                 }
8367
8368                 if (cfg->verbose_level > 3)
8369                         printf ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
8370
8371                 switch (*ip) {
8372                 case CEE_NOP:
8373                         if (seq_points && !sym_seq_points && sp != stack_start) {
8374                                 /*
8375                                  * The C# compiler uses these nops to notify the JIT that it should
8376                                  * insert seq points.
8377                                  */
8378                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, FALSE);
8379                                 MONO_ADD_INS (cfg->cbb, ins);
8380                         }
8381                         if (cfg->keep_cil_nops)
8382                                 MONO_INST_NEW (cfg, ins, OP_HARD_NOP);
8383                         else
8384                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8385                         ip++;
8386                         MONO_ADD_INS (cfg->cbb, ins);
8387                         break;
8388                 case CEE_BREAK:
8389                         if (should_insert_brekpoint (cfg->method)) {
8390                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
8391                         } else {
8392                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8393                         }
8394                         ip++;
8395                         MONO_ADD_INS (cfg->cbb, ins);
8396                         break;
8397                 case CEE_LDARG_0:
8398                 case CEE_LDARG_1:
8399                 case CEE_LDARG_2:
8400                 case CEE_LDARG_3:
8401                         CHECK_STACK_OVF (1);
8402                         n = (*ip)-CEE_LDARG_0;
8403                         CHECK_ARG (n);
8404                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8405                         ip++;
8406                         *sp++ = ins;
8407                         break;
8408                 case CEE_LDLOC_0:
8409                 case CEE_LDLOC_1:
8410                 case CEE_LDLOC_2:
8411                 case CEE_LDLOC_3:
8412                         CHECK_STACK_OVF (1);
8413                         n = (*ip)-CEE_LDLOC_0;
8414                         CHECK_LOCAL (n);
8415                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8416                         ip++;
8417                         *sp++ = ins;
8418                         break;
8419                 case CEE_STLOC_0:
8420                 case CEE_STLOC_1:
8421                 case CEE_STLOC_2:
8422                 case CEE_STLOC_3: {
8423                         CHECK_STACK (1);
8424                         n = (*ip)-CEE_STLOC_0;
8425                         CHECK_LOCAL (n);
8426                         --sp;
8427                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
8428                                 UNVERIFIED;
8429                         emit_stloc_ir (cfg, sp, header, n);
8430                         ++ip;
8431                         inline_costs += 1;
8432                         break;
8433                         }
8434                 case CEE_LDARG_S:
8435                         CHECK_OPSIZE (2);
8436                         CHECK_STACK_OVF (1);
8437                         n = ip [1];
8438                         CHECK_ARG (n);
8439                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8440                         *sp++ = ins;
8441                         ip += 2;
8442                         break;
8443                 case CEE_LDARGA_S:
8444                         CHECK_OPSIZE (2);
8445                         CHECK_STACK_OVF (1);
8446                         n = ip [1];
8447                         CHECK_ARG (n);
8448                         NEW_ARGLOADA (cfg, ins, n);
8449                         MONO_ADD_INS (cfg->cbb, ins);
8450                         *sp++ = ins;
8451                         ip += 2;
8452                         break;
8453                 case CEE_STARG_S:
8454                         CHECK_OPSIZE (2);
8455                         CHECK_STACK (1);
8456                         --sp;
8457                         n = ip [1];
8458                         CHECK_ARG (n);
8459                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [ip [1]], *sp))
8460                                 UNVERIFIED;
8461                         EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
8462                         ip += 2;
8463                         break;
8464                 case CEE_LDLOC_S:
8465                         CHECK_OPSIZE (2);
8466                         CHECK_STACK_OVF (1);
8467                         n = ip [1];
8468                         CHECK_LOCAL (n);
8469                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8470                         *sp++ = ins;
8471                         ip += 2;
8472                         break;
8473                 case CEE_LDLOCA_S: {
8474                         unsigned char *tmp_ip;
8475                         CHECK_OPSIZE (2);
8476                         CHECK_STACK_OVF (1);
8477                         CHECK_LOCAL (ip [1]);
8478
8479                         if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 1))) {
8480                                 ip = tmp_ip;
8481                                 inline_costs += 1;
8482                                 break;
8483                         }
8484
8485                         EMIT_NEW_LOCLOADA (cfg, ins, ip [1]);
8486                         *sp++ = ins;
8487                         ip += 2;
8488                         break;
8489                 }
8490                 case CEE_STLOC_S:
8491                         CHECK_OPSIZE (2);
8492                         CHECK_STACK (1);
8493                         --sp;
8494                         CHECK_LOCAL (ip [1]);
8495                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [ip [1]], *sp))
8496                                 UNVERIFIED;
8497                         emit_stloc_ir (cfg, sp, header, ip [1]);
8498                         ip += 2;
8499                         inline_costs += 1;
8500                         break;
8501                 case CEE_LDNULL:
8502                         CHECK_STACK_OVF (1);
8503                         EMIT_NEW_PCONST (cfg, ins, NULL);
8504                         ins->type = STACK_OBJ;
8505                         ++ip;
8506                         *sp++ = ins;
8507                         break;
8508                 case CEE_LDC_I4_M1:
8509                         CHECK_STACK_OVF (1);
8510                         EMIT_NEW_ICONST (cfg, ins, -1);
8511                         ++ip;
8512                         *sp++ = ins;
8513                         break;
8514                 case CEE_LDC_I4_0:
8515                 case CEE_LDC_I4_1:
8516                 case CEE_LDC_I4_2:
8517                 case CEE_LDC_I4_3:
8518                 case CEE_LDC_I4_4:
8519                 case CEE_LDC_I4_5:
8520                 case CEE_LDC_I4_6:
8521                 case CEE_LDC_I4_7:
8522                 case CEE_LDC_I4_8:
8523                         CHECK_STACK_OVF (1);
8524                         EMIT_NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
8525                         ++ip;
8526                         *sp++ = ins;
8527                         break;
8528                 case CEE_LDC_I4_S:
8529                         CHECK_OPSIZE (2);
8530                         CHECK_STACK_OVF (1);
8531                         ++ip;
8532                         EMIT_NEW_ICONST (cfg, ins, *((signed char*)ip));
8533                         ++ip;
8534                         *sp++ = ins;
8535                         break;
8536                 case CEE_LDC_I4:
8537                         CHECK_OPSIZE (5);
8538                         CHECK_STACK_OVF (1);
8539                         EMIT_NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
8540                         ip += 5;
8541                         *sp++ = ins;
8542                         break;
8543                 case CEE_LDC_I8:
8544                         CHECK_OPSIZE (9);
8545                         CHECK_STACK_OVF (1);
8546                         MONO_INST_NEW (cfg, ins, OP_I8CONST);
8547                         ins->type = STACK_I8;
8548                         ins->dreg = alloc_dreg (cfg, STACK_I8);
8549                         ++ip;
8550                         ins->inst_l = (gint64)read64 (ip);
8551                         MONO_ADD_INS (cfg->cbb, ins);
8552                         ip += 8;
8553                         *sp++ = ins;
8554                         break;
8555                 case CEE_LDC_R4: {
8556                         float *f;
8557                         gboolean use_aotconst = FALSE;
8558
8559 #ifdef TARGET_POWERPC
8560                         /* FIXME: Clean this up */
8561                         if (cfg->compile_aot)
8562                                 use_aotconst = TRUE;
8563 #endif
8564
8565                         /* FIXME: we should really allocate this only late in the compilation process */
8566                         f = mono_domain_alloc (cfg->domain, sizeof (float));
8567                         CHECK_OPSIZE (5);
8568                         CHECK_STACK_OVF (1);
8569
8570                         if (use_aotconst) {
8571                                 MonoInst *cons;
8572                                 int dreg;
8573
8574                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R4, f);
8575
8576                                 dreg = alloc_freg (cfg);
8577                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR4_MEMBASE, dreg, cons->dreg, 0);
8578                                 ins->type = cfg->r4_stack_type;
8579                         } else {
8580                                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
8581                                 ins->type = cfg->r4_stack_type;
8582                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8583                                 ins->inst_p0 = f;
8584                                 MONO_ADD_INS (cfg->cbb, ins);
8585                         }
8586                         ++ip;
8587                         readr4 (ip, f);
8588                         ip += 4;
8589                         *sp++ = ins;                    
8590                         break;
8591                 }
8592                 case CEE_LDC_R8: {
8593                         double *d;
8594                         gboolean use_aotconst = FALSE;
8595
8596 #ifdef TARGET_POWERPC
8597                         /* FIXME: Clean this up */
8598                         if (cfg->compile_aot)
8599                                 use_aotconst = TRUE;
8600 #endif
8601
8602                         /* FIXME: we should really allocate this only late in the compilation process */
8603                         d = mono_domain_alloc (cfg->domain, sizeof (double));
8604                         CHECK_OPSIZE (9);
8605                         CHECK_STACK_OVF (1);
8606
8607                         if (use_aotconst) {
8608                                 MonoInst *cons;
8609                                 int dreg;
8610
8611                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R8, d);
8612
8613                                 dreg = alloc_freg (cfg);
8614                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR8_MEMBASE, dreg, cons->dreg, 0);
8615                                 ins->type = STACK_R8;
8616                         } else {
8617                                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
8618                                 ins->type = STACK_R8;
8619                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8620                                 ins->inst_p0 = d;
8621                                 MONO_ADD_INS (cfg->cbb, ins);
8622                         }
8623                         ++ip;
8624                         readr8 (ip, d);
8625                         ip += 8;
8626                         *sp++ = ins;
8627                         break;
8628                 }
8629                 case CEE_DUP: {
8630                         MonoInst *temp, *store;
8631                         CHECK_STACK (1);
8632                         CHECK_STACK_OVF (1);
8633                         sp--;
8634                         ins = *sp;
8635
8636                         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
8637                         EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
8638
8639                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8640                         *sp++ = ins;
8641
8642                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8643                         *sp++ = ins;
8644
8645                         ++ip;
8646                         inline_costs += 2;
8647                         break;
8648                 }
8649                 case CEE_POP:
8650                         CHECK_STACK (1);
8651                         ip++;
8652                         --sp;
8653
8654 #ifdef TARGET_X86
8655                         if (sp [0]->type == STACK_R8)
8656                                 /* we need to pop the value from the x86 FP stack */
8657                                 MONO_EMIT_NEW_UNALU (cfg, OP_X86_FPOP, -1, sp [0]->dreg);
8658 #endif
8659                         break;
8660                 case CEE_JMP: {
8661                         MonoCallInst *call;
8662                         MonoMethodSignature *fsig;
8663                         int i, n;
8664
8665                         INLINE_FAILURE ("jmp");
8666                         GSHAREDVT_FAILURE (*ip);
8667
8668                         CHECK_OPSIZE (5);
8669                         if (stack_start != sp)
8670                                 UNVERIFIED;
8671                         token = read32 (ip + 1);
8672                         /* FIXME: check the signature matches */
8673                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
8674
8675                         if (!cmethod || mono_loader_get_last_error ())
8676                                 LOAD_ERROR;
8677  
8678                         if (cfg->gshared && mono_method_check_context_used (cmethod))
8679                                 GENERIC_SHARING_FAILURE (CEE_JMP);
8680
8681                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
8682
8683                         fsig = mono_method_signature (cmethod);
8684                         n = fsig->param_count + fsig->hasthis;
8685                         if (cfg->llvm_only) {
8686                                 MonoInst **args;
8687
8688                                 args = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
8689                                 for (i = 0; i < n; ++i)
8690                                         EMIT_NEW_ARGLOAD (cfg, args [i], i);
8691                                 ins = mono_emit_method_call_full (cfg, cmethod, fsig, TRUE, args, NULL, NULL, NULL);
8692                                 /*
8693                                  * The code in mono-basic-block.c treats the rest of the code as dead, but we
8694                                  * have to emit a normal return since llvm expects it.
8695                                  */
8696                                 if (cfg->ret)
8697                                         emit_setret (cfg, ins);
8698                                 MONO_INST_NEW (cfg, ins, OP_BR);
8699                                 ins->inst_target_bb = end_bblock;
8700                                 MONO_ADD_INS (cfg->cbb, ins);
8701                                 link_bblock (cfg, cfg->cbb, end_bblock);
8702                                 ip += 5;
8703                                 break;
8704                         } else if (cfg->backend->have_op_tail_call) {
8705                                 /* Handle tail calls similarly to calls */
8706                                 DISABLE_AOT (cfg);
8707
8708                                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
8709                                 call->method = cmethod;
8710                                 call->tail_call = TRUE;
8711                                 call->signature = mono_method_signature (cmethod);
8712                                 call->args = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
8713                                 call->inst.inst_p0 = cmethod;
8714                                 for (i = 0; i < n; ++i)
8715                                         EMIT_NEW_ARGLOAD (cfg, call->args [i], i);
8716
8717                                 mono_arch_emit_call (cfg, call);
8718                                 cfg->param_area = MAX(cfg->param_area, call->stack_usage);
8719                                 MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
8720                         } else {
8721                                 for (i = 0; i < num_args; ++i)
8722                                         /* Prevent arguments from being optimized away */
8723                                         arg_array [i]->flags |= MONO_INST_VOLATILE;
8724
8725                                 MONO_INST_NEW_CALL (cfg, call, OP_JMP);
8726                                 ins = (MonoInst*)call;
8727                                 ins->inst_p0 = cmethod;
8728                                 MONO_ADD_INS (cfg->cbb, ins);
8729                         }
8730
8731                         ip += 5;
8732                         start_new_bblock = 1;
8733                         break;
8734                 }
8735                 case CEE_CALLI: {
8736                         MonoInst *addr;
8737                         MonoMethodSignature *fsig;
8738
8739                         CHECK_OPSIZE (5);
8740                         token = read32 (ip + 1);
8741
8742                         ins = NULL;
8743
8744                         //GSHAREDVT_FAILURE (*ip);
8745                         cmethod = NULL;
8746                         CHECK_STACK (1);
8747                         --sp;
8748                         addr = *sp;
8749                         fsig = mini_get_signature (method, token, generic_context);
8750
8751                         if (method->dynamic && fsig->pinvoke) {
8752                                 MonoInst *args [3];
8753
8754                                 /*
8755                                  * This is a call through a function pointer using a pinvoke
8756                                  * signature. Have to create a wrapper and call that instead.
8757                                  * FIXME: This is very slow, need to create a wrapper at JIT time
8758                                  * instead based on the signature.
8759                                  */
8760                                 EMIT_NEW_IMAGECONST (cfg, args [0], method->klass->image);
8761                                 EMIT_NEW_PCONST (cfg, args [1], fsig);
8762                                 args [2] = addr;
8763                                 addr = mono_emit_jit_icall (cfg, mono_get_native_calli_wrapper, args);
8764                         }
8765
8766                         n = fsig->param_count + fsig->hasthis;
8767
8768                         CHECK_STACK (n);
8769
8770                         //g_assert (!virtual || fsig->hasthis);
8771
8772                         sp -= n;
8773
8774                         inline_costs += 10 * num_calls++;
8775
8776                         /*
8777                          * Making generic calls out of gsharedvt methods.
8778                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
8779                          * patching gshared method addresses into a gsharedvt method.
8780                          */
8781                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
8782                                 /*
8783                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
8784                                  */
8785                                 MonoInst *callee = addr;
8786
8787                                 if (method->wrapper_type != MONO_WRAPPER_DELEGATE_INVOKE)
8788                                         /* Not tested */
8789                                         GSHAREDVT_FAILURE (*ip);
8790
8791                                 addr = emit_get_rgctx_sig (cfg, context_used,
8792                                                                                           fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
8793                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
8794                                 goto calli_end;
8795                         }
8796
8797                         /* Prevent inlining of methods with indirect calls */
8798                         INLINE_FAILURE ("indirect call");
8799
8800                         if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST || addr->opcode == OP_GOT_ENTRY) {
8801                                 int info_type;
8802                                 gpointer info_data;
8803
8804                                 /*
8805                                  * Instead of emitting an indirect call, emit a direct call
8806                                  * with the contents of the aotconst as the patch info.
8807                                  */
8808                                 if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST) {
8809                                         info_type = addr->inst_c1;
8810                                         info_data = addr->inst_p0;
8811                                 } else {
8812                                         info_type = addr->inst_right->inst_c1;
8813                                         info_data = addr->inst_right->inst_left;
8814                                 }
8815
8816                                 if (info_type == MONO_PATCH_INFO_ICALL_ADDR || info_type == MONO_PATCH_INFO_JIT_ICALL_ADDR) {
8817                                         ins = (MonoInst*)mono_emit_abs_call (cfg, info_type, info_data, fsig, sp);
8818                                         NULLIFY_INS (addr);
8819                                         goto calli_end;
8820                                 }
8821                         }
8822                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8823
8824                         calli_end:
8825
8826                         /* End of call, INS should contain the result of the call, if any */
8827
8828                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8829                                 g_assert (ins);
8830                                 *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
8831                         }
8832
8833                         CHECK_CFG_EXCEPTION;
8834
8835                         ip += 5;
8836                         ins_flag = 0;
8837                         constrained_class = NULL;
8838                         break;
8839                 }
8840                 case CEE_CALL:
8841                 case CEE_CALLVIRT: {
8842                         MonoInst *addr = NULL;
8843                         MonoMethodSignature *fsig = NULL;
8844                         int array_rank = 0;
8845                         int virtual = *ip == CEE_CALLVIRT;
8846                         gboolean pass_imt_from_rgctx = FALSE;
8847                         MonoInst *imt_arg = NULL;
8848                         MonoInst *keep_this_alive = NULL;
8849                         gboolean pass_vtable = FALSE;
8850                         gboolean pass_mrgctx = FALSE;
8851                         MonoInst *vtable_arg = NULL;
8852                         gboolean check_this = FALSE;
8853                         gboolean supported_tail_call = FALSE;
8854                         gboolean tail_call = FALSE;
8855                         gboolean need_seq_point = FALSE;
8856                         guint32 call_opcode = *ip;
8857                         gboolean emit_widen = TRUE;
8858                         gboolean push_res = TRUE;
8859                         gboolean skip_ret = FALSE;
8860                         gboolean delegate_invoke = FALSE;
8861                         gboolean direct_icall = FALSE;
8862                         gboolean constrained_partial_call = FALSE;
8863                         MonoMethod *cil_method;
8864
8865                         CHECK_OPSIZE (5);
8866                         token = read32 (ip + 1);
8867
8868                         ins = NULL;
8869
8870                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
8871                         cil_method = cmethod;
8872                                 
8873                         if (constrained_class) {
8874                                 if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->gshared) {
8875                                         if (!mini_is_gsharedvt_klass (constrained_class)) {
8876                                                 g_assert (!cmethod->klass->valuetype);
8877                                                 if (!mini_type_is_reference (&constrained_class->byval_arg))
8878                                                         constrained_partial_call = TRUE;
8879                                         }
8880                                 }
8881
8882                                 if (method->wrapper_type != MONO_WRAPPER_NONE) {
8883                                         if (cfg->verbose_level > 2)
8884                                                 printf ("DM Constrained call to %s\n", mono_type_get_full_name (constrained_class));
8885                                         if (!((constrained_class->byval_arg.type == MONO_TYPE_VAR ||
8886                                                    constrained_class->byval_arg.type == MONO_TYPE_MVAR) &&
8887                                                   cfg->gshared)) {
8888                                                 cmethod = mono_get_method_constrained_with_method (image, cil_method, constrained_class, generic_context, &cfg->error);
8889                                                 CHECK_CFG_ERROR;
8890                                         }
8891                                 } else {
8892                                         if (cfg->verbose_level > 2)
8893                                                 printf ("Constrained call to %s\n", mono_type_get_full_name (constrained_class));
8894
8895                                         if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->gshared) {
8896                                                 /* 
8897                                                  * This is needed since get_method_constrained can't find 
8898                                                  * the method in klass representing a type var.
8899                                                  * The type var is guaranteed to be a reference type in this
8900                                                  * case.
8901                                                  */
8902                                                 if (!mini_is_gsharedvt_klass (constrained_class))
8903                                                         g_assert (!cmethod->klass->valuetype);
8904                                         } else {
8905                                                 cmethod = mono_get_method_constrained_checked (image, token, constrained_class, generic_context, &cil_method, &cfg->error);
8906                                                 CHECK_CFG_ERROR;
8907                                         }
8908                                 }
8909                         }
8910                                         
8911                         if (!cmethod || mono_loader_get_last_error ())
8912                                 LOAD_ERROR;
8913                         if (!dont_verify && !cfg->skip_visibility) {
8914                                 MonoMethod *target_method = cil_method;
8915                                 if (method->is_inflated) {
8916                                         target_method = mini_get_method_allow_open (method, token, NULL, &(mono_method_get_generic_container (method_definition)->context));
8917                                 }
8918                                 if (!mono_method_can_access_method (method_definition, target_method) &&
8919                                         !mono_method_can_access_method (method, cil_method))
8920                                         METHOD_ACCESS_FAILURE (method, cil_method);
8921                         }
8922
8923                         if (mono_security_core_clr_enabled ())
8924                                 ensure_method_is_allowed_to_call_method (cfg, method, cil_method);
8925
8926                         if (!virtual && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
8927                                 /* MS.NET seems to silently convert this to a callvirt */
8928                                 virtual = 1;
8929
8930                         {
8931                                 /*
8932                                  * MS.NET accepts non virtual calls to virtual final methods of transparent proxy classes and
8933                                  * converts to a callvirt.
8934                                  *
8935                                  * tests/bug-515884.il is an example of this behavior
8936                                  */
8937                                 const int test_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_STATIC;
8938                                 const int expected_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL;
8939                                 if (!virtual && mono_class_is_marshalbyref (cmethod->klass) && (cmethod->flags & test_flags) == expected_flags && cfg->method->wrapper_type == MONO_WRAPPER_NONE)
8940                                         virtual = 1;
8941                         }
8942
8943                         if (!cmethod->klass->inited)
8944                                 if (!mono_class_init (cmethod->klass))
8945                                         TYPE_LOAD_ERROR (cmethod->klass);
8946
8947                         fsig = mono_method_signature (cmethod);
8948                         if (!fsig)
8949                                 LOAD_ERROR;
8950                         if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
8951                                 mini_class_is_system_array (cmethod->klass)) {
8952                                 array_rank = cmethod->klass->rank;
8953                         } else if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && icall_is_direct_callable (cfg, cmethod)) {
8954                                 direct_icall = TRUE;
8955                         } else if (fsig->pinvoke) {
8956                                 MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
8957                                 fsig = mono_method_signature (wrapper);
8958                         } else if (constrained_class) {
8959                         } else {
8960                                 fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
8961                                 CHECK_CFG_ERROR;
8962                         }
8963
8964                         /* See code below */
8965                         if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
8966                                 MonoBasicBlock *tbb;
8967
8968                                 GET_BBLOCK (cfg, tbb, ip + 5);
8969                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
8970                                         /*
8971                                          * We want to extend the try block to cover the call, but we can't do it if the
8972                                          * call is made directly since its followed by an exception check.
8973                                          */
8974                                         direct_icall = FALSE;
8975                                 }
8976                         }
8977
8978                         mono_save_token_info (cfg, image, token, cil_method);
8979
8980                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip + 5 - header->code)))
8981                                 need_seq_point = TRUE;
8982
8983                         /* Don't support calls made using type arguments for now */
8984                         /*
8985                           if (cfg->gsharedvt) {
8986                           if (mini_is_gsharedvt_signature (fsig))
8987                           GSHAREDVT_FAILURE (*ip);
8988                           }
8989                         */
8990
8991                         if (cmethod->string_ctor && method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE)
8992                                 g_assert_not_reached ();
8993
8994                         n = fsig->param_count + fsig->hasthis;
8995
8996                         if (!cfg->gshared && cmethod->klass->generic_container)
8997                                 UNVERIFIED;
8998
8999                         if (!cfg->gshared)
9000                                 g_assert (!mono_method_check_context_used (cmethod));
9001
9002                         CHECK_STACK (n);
9003
9004                         //g_assert (!virtual || fsig->hasthis);
9005
9006                         sp -= n;
9007
9008                         if (constrained_class) {
9009                                 if (mini_is_gsharedvt_klass (constrained_class)) {
9010                                         if ((cmethod->klass != mono_defaults.object_class) && constrained_class->valuetype && cmethod->klass->valuetype) {
9011                                                 /* The 'Own method' case below */
9012                                         } else if (cmethod->klass->image != mono_defaults.corlib && !(cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !cmethod->klass->valuetype) {
9013                                                 /* 'The type parameter is instantiated as a reference type' case below. */
9014                                         } else {
9015                                                 ins = handle_constrained_gsharedvt_call (cfg, cmethod, fsig, sp, constrained_class, &emit_widen);
9016                                                 CHECK_CFG_EXCEPTION;
9017                                                 g_assert (ins);
9018                                                 goto call_end;
9019                                         }
9020                                 }
9021
9022                                 /*
9023                                  * We have the `constrained.' prefix opcode.
9024                                  */
9025                                 if (constrained_partial_call) {
9026                                         gboolean need_box = TRUE;
9027
9028                                         /*
9029                                          * The receiver is a valuetype, but the exact type is not known at compile time. This means the
9030                                          * called method is not known at compile time either. The called method could end up being
9031                                          * one of the methods on the parent classes (object/valuetype/enum), in which case we need
9032                                          * to box the receiver.
9033                                          * A simple solution would be to box always and make a normal virtual call, but that would
9034                                          * be bad performance wise.
9035                                          */
9036                                         if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE && cmethod->klass->generic_class) {
9037                                                 /*
9038                                                  * The parent classes implement no generic interfaces, so the called method will be a vtype method, so no boxing neccessary.
9039                                                  */
9040                                                 need_box = FALSE;
9041                                         }
9042
9043                                         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)) {
9044                                                 /* The called method is not virtual, i.e. Object:GetType (), the receiver is a vtype, has to box */
9045                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9046                                                 ins->klass = constrained_class;
9047                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9048                                                 CHECK_CFG_EXCEPTION;
9049                                         } else if (need_box) {
9050                                                 MonoInst *box_type;
9051                                                 MonoBasicBlock *is_ref_bb, *end_bb;
9052                                                 MonoInst *nonbox_call;
9053
9054                                                 /*
9055                                                  * Determine at runtime whenever the called method is defined on object/valuetype/enum, and emit a boxing call
9056                                                  * if needed.
9057                                                  * FIXME: It is possible to inline the called method in a lot of cases, i.e. for T_INT,
9058                                                  * the no-box case goes to a method in Int32, while the box case goes to a method in Enum.
9059                                                  */
9060                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
9061
9062                                                 NEW_BBLOCK (cfg, is_ref_bb);
9063                                                 NEW_BBLOCK (cfg, end_bb);
9064
9065                                                 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);
9066                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, box_type->dreg, 1);
9067                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
9068
9069                                                 /* Non-ref case */
9070                                                 nonbox_call = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9071
9072                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
9073
9074                                                 /* Ref case */
9075                                                 MONO_START_BB (cfg, is_ref_bb);
9076                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9077                                                 ins->klass = constrained_class;
9078                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9079                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9080
9081                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
9082
9083                                                 MONO_START_BB (cfg, end_bb);
9084                                                 cfg->cbb = end_bb;
9085
9086                                                 nonbox_call->dreg = ins->dreg;
9087                                                 goto call_end;
9088                                         } else {
9089                                                 g_assert (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE);
9090                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
9091                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9092                                                 goto call_end;
9093                                         }
9094                                 } else if (constrained_class->valuetype && (cmethod->klass == mono_defaults.object_class || cmethod->klass == mono_defaults.enum_class->parent || cmethod->klass == mono_defaults.enum_class)) {
9095                                         /*
9096                                          * The type parameter is instantiated as a valuetype,
9097                                          * but that type doesn't override the method we're
9098                                          * calling, so we need to box `this'.
9099                                          */
9100                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9101                                         ins->klass = constrained_class;
9102                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9103                                         CHECK_CFG_EXCEPTION;
9104                                 } else if (!constrained_class->valuetype) {
9105                                         int dreg = alloc_ireg_ref (cfg);
9106
9107                                         /*
9108                                          * The type parameter is instantiated as a reference
9109                                          * type.  We have a managed pointer on the stack, so
9110                                          * we need to dereference it here.
9111                                          */
9112                                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, sp [0]->dreg, 0);
9113                                         ins->type = STACK_OBJ;
9114                                         sp [0] = ins;
9115                                 } else {
9116                                         if (cmethod->klass->valuetype) {
9117                                                 /* Own method */
9118                                         } else {
9119                                                 /* Interface method */
9120                                                 int ioffset, slot;
9121
9122                                                 mono_class_setup_vtable (constrained_class);
9123                                                 CHECK_TYPELOAD (constrained_class);
9124                                                 ioffset = mono_class_interface_offset (constrained_class, cmethod->klass);
9125                                                 if (ioffset == -1)
9126                                                         TYPE_LOAD_ERROR (constrained_class);
9127                                                 slot = mono_method_get_vtable_slot (cmethod);
9128                                                 if (slot == -1)
9129                                                         TYPE_LOAD_ERROR (cmethod->klass);
9130                                                 cmethod = constrained_class->vtable [ioffset + slot];
9131
9132                                                 if (cmethod->klass == mono_defaults.enum_class) {
9133                                                         /* Enum implements some interfaces, so treat this as the first case */
9134                                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9135                                                         ins->klass = constrained_class;
9136                                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9137                                                         CHECK_CFG_EXCEPTION;
9138                                                 }
9139                                         }
9140                                         virtual = 0;
9141                                 }
9142                                 constrained_class = NULL;
9143                         }
9144
9145                         if (check_call_signature (cfg, fsig, sp))
9146                                 UNVERIFIED;
9147
9148                         if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (cmethod->name, "Invoke"))
9149                                 delegate_invoke = TRUE;
9150
9151                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_sharable_method (cfg, cmethod, fsig, sp))) {
9152                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9153                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
9154                                         emit_widen = FALSE;
9155                                 }
9156
9157                                 goto call_end;
9158                         }
9159
9160                         /* 
9161                          * If the callee is a shared method, then its static cctor
9162                          * might not get called after the call was patched.
9163                          */
9164                         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)) {
9165                                 emit_class_init (cfg, cmethod->klass);
9166                                 CHECK_TYPELOAD (cmethod->klass);
9167                         }
9168
9169                         check_method_sharing (cfg, cmethod, &pass_vtable, &pass_mrgctx);
9170
9171                         if (cfg->gshared) {
9172                                 MonoGenericContext *cmethod_context = mono_method_get_context (cmethod);
9173
9174                                 context_used = mini_method_check_context_used (cfg, cmethod);
9175
9176                                 if (context_used && (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
9177                                         /* Generic method interface
9178                                            calls are resolved via a
9179                                            helper function and don't
9180                                            need an imt. */
9181                                         if (!cmethod_context || !cmethod_context->method_inst)
9182                                                 pass_imt_from_rgctx = TRUE;
9183                                 }
9184
9185                                 /*
9186                                  * If a shared method calls another
9187                                  * shared method then the caller must
9188                                  * have a generic sharing context
9189                                  * because the magic trampoline
9190                                  * requires it.  FIXME: We shouldn't
9191                                  * have to force the vtable/mrgctx
9192                                  * variable here.  Instead there
9193                                  * should be a flag in the cfg to
9194                                  * request a generic sharing context.
9195                                  */
9196                                 if (context_used &&
9197                                                 ((method->flags & METHOD_ATTRIBUTE_STATIC) || method->klass->valuetype))
9198                                         mono_get_vtable_var (cfg);
9199                         }
9200
9201                         if (pass_vtable) {
9202                                 if (context_used) {
9203                                         vtable_arg = emit_get_rgctx_klass (cfg, context_used, cmethod->klass, MONO_RGCTX_INFO_VTABLE);
9204                                 } else {
9205                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
9206
9207                                         CHECK_TYPELOAD (cmethod->klass);
9208                                         EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
9209                                 }
9210                         }
9211
9212                         if (pass_mrgctx) {
9213                                 g_assert (!vtable_arg);
9214
9215                                 if (!cfg->compile_aot) {
9216                                         /* 
9217                                          * emit_get_rgctx_method () calls mono_class_vtable () so check 
9218                                          * for type load errors before.
9219                                          */
9220                                         mono_class_setup_vtable (cmethod->klass);
9221                                         CHECK_TYPELOAD (cmethod->klass);
9222                                 }
9223
9224                                 vtable_arg = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
9225
9226                                 /* !marshalbyref is needed to properly handle generic methods + remoting */
9227                                 if ((!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
9228                                          MONO_METHOD_IS_FINAL (cmethod)) &&
9229                                         !mono_class_is_marshalbyref (cmethod->klass)) {
9230                                         if (virtual)
9231                                                 check_this = TRUE;
9232                                         virtual = 0;
9233                                 }
9234                         }
9235
9236                         if (pass_imt_from_rgctx) {
9237                                 g_assert (!pass_vtable);
9238
9239                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9240                                         cmethod, MONO_RGCTX_INFO_METHOD);
9241                         }
9242
9243                         if (check_this)
9244                                 MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9245
9246                         /* Calling virtual generic methods */
9247                         if (virtual && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) && 
9248                             !(MONO_METHOD_IS_FINAL (cmethod) && 
9249                               cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) &&
9250                             fsig->generic_param_count && 
9251                                 !(cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) &&
9252                                 !cfg->llvm_only) {
9253                                 MonoInst *this_temp, *this_arg_temp, *store;
9254                                 MonoInst *iargs [4];
9255
9256                                 g_assert (fsig->is_inflated);
9257
9258                                 /* Prevent inlining of methods that contain indirect calls */
9259                                 INLINE_FAILURE ("virtual generic call");
9260
9261                                 if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))
9262                                         GSHAREDVT_FAILURE (*ip);
9263
9264                                 if (cfg->backend->have_generalized_imt_thunk && cfg->backend->gshared_supported && cmethod->wrapper_type == MONO_WRAPPER_NONE) {
9265                                         g_assert (!imt_arg);
9266                                         if (!context_used)
9267                                                 g_assert (cmethod->is_inflated);
9268                                         imt_arg = emit_get_rgctx_method (cfg, context_used,
9269                                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
9270                                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, sp [0], imt_arg, NULL);
9271                                 } else {
9272                                         this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
9273                                         NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
9274                                         MONO_ADD_INS (cfg->cbb, store);
9275
9276                                         /* FIXME: This should be a managed pointer */
9277                                         this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
9278
9279                                         EMIT_NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
9280                                         iargs [1] = emit_get_rgctx_method (cfg, context_used,
9281                                                                                                            cmethod, MONO_RGCTX_INFO_METHOD);
9282                                         EMIT_NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
9283                                         addr = mono_emit_jit_icall (cfg,
9284                                                                                                 mono_helper_compile_generic_method, iargs);
9285
9286                                         EMIT_NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
9287
9288                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9289                                 }
9290
9291                                 goto call_end;
9292                         }
9293
9294                         /*
9295                          * Implement a workaround for the inherent races involved in locking:
9296                          * Monitor.Enter ()
9297                          * try {
9298                          * } finally {
9299                          *    Monitor.Exit ()
9300                          * }
9301                          * If a thread abort happens between the call to Monitor.Enter () and the start of the
9302                          * try block, the Exit () won't be executed, see:
9303                          * http://www.bluebytesoftware.com/blog/2007/01/30/MonitorEnterThreadAbortsAndOrphanedLocks.aspx
9304                          * To work around this, we extend such try blocks to include the last x bytes
9305                          * of the Monitor.Enter () call.
9306                          */
9307                         if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
9308                                 MonoBasicBlock *tbb;
9309
9310                                 GET_BBLOCK (cfg, tbb, ip + 5);
9311                                 /* 
9312                                  * Only extend try blocks with a finally, to avoid catching exceptions thrown
9313                                  * from Monitor.Enter like ArgumentNullException.
9314                                  */
9315                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
9316                                         /* Mark this bblock as needing to be extended */
9317                                         tbb->extend_try_block = TRUE;
9318                                 }
9319                         }
9320
9321                         /* Conversion to a JIT intrinsic */
9322                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_method (cfg, cmethod, fsig, sp))) {
9323                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9324                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
9325                                         emit_widen = FALSE;
9326                                 }
9327                                 goto call_end;
9328                         }
9329
9330                         /* Inlining */
9331                         if ((cfg->opt & MONO_OPT_INLINE) &&
9332                                 (!virtual || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || MONO_METHOD_IS_FINAL (cmethod)) &&
9333                             mono_method_check_inlining (cfg, cmethod)) {
9334                                 int costs;
9335                                 gboolean always = FALSE;
9336
9337                                 if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
9338                                         (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
9339                                         /* Prevent inlining of methods that call wrappers */
9340                                         INLINE_FAILURE ("wrapper call");
9341                                         cmethod = mono_marshal_get_native_wrapper (cmethod, TRUE, FALSE);
9342                                         always = TRUE;
9343                                 }
9344
9345                                 costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, always);
9346                                 if (costs) {
9347                                         cfg->real_offset += 5;
9348
9349                                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9350                                                 /* *sp is already set by inline_method */
9351                                                 sp++;
9352                                                 push_res = FALSE;
9353                                         }
9354
9355                                         inline_costs += costs;
9356
9357                                         goto call_end;
9358                                 }
9359                         }
9360
9361                         /* Tail recursion elimination */
9362                         if ((cfg->opt & MONO_OPT_TAILC) && call_opcode == CEE_CALL && cmethod == method && ip [5] == CEE_RET && !vtable_arg) {
9363                                 gboolean has_vtargs = FALSE;
9364                                 int i;
9365
9366                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9367                                 INLINE_FAILURE ("tail call");
9368
9369                                 /* keep it simple */
9370                                 for (i =  fsig->param_count - 1; i >= 0; i--) {
9371                                         if (MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->params [i])) 
9372                                                 has_vtargs = TRUE;
9373                                 }
9374
9375                                 if (!has_vtargs) {
9376                                         for (i = 0; i < n; ++i)
9377                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9378                                         MONO_INST_NEW (cfg, ins, OP_BR);
9379                                         MONO_ADD_INS (cfg->cbb, ins);
9380                                         tblock = start_bblock->out_bb [0];
9381                                         link_bblock (cfg, cfg->cbb, tblock);
9382                                         ins->inst_target_bb = tblock;
9383                                         start_new_bblock = 1;
9384
9385                                         /* skip the CEE_RET, too */
9386                                         if (ip_in_bb (cfg, cfg->cbb, ip + 5))
9387                                                 skip_ret = TRUE;
9388                                         push_res = FALSE;
9389                                         goto call_end;
9390                                 }
9391                         }
9392
9393                         inline_costs += 10 * num_calls++;
9394
9395                         /*
9396                          * Making generic calls out of gsharedvt methods.
9397                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
9398                          * patching gshared method addresses into a gsharedvt method.
9399                          */
9400                         if (cfg->gsharedvt && (mini_is_gsharedvt_signature (fsig) || cmethod->is_inflated || cmethod->klass->generic_class) &&
9401                                 !(cmethod->klass->rank && cmethod->klass->byval_arg.type != MONO_TYPE_SZARRAY)) {
9402                                 MonoRgctxInfoType info_type;
9403
9404                                 if (virtual) {
9405                                         //if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
9406                                                 //GSHAREDVT_FAILURE (*ip);
9407                                         // disable for possible remoting calls
9408                                         if (fsig->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class))
9409                                                 GSHAREDVT_FAILURE (*ip);
9410                                         if (fsig->generic_param_count) {
9411                                                 /* virtual generic call */
9412                                                 g_assert (!imt_arg);
9413                                                 /* Same as the virtual generic case above */
9414                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9415                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9416                                                 /* This is not needed, as the trampoline code will pass one, and it might be passed in the same reg as the imt arg */
9417                                                 vtable_arg = NULL;
9418                                         } else if ((cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !imt_arg) {
9419                                                 /* This can happen when we call a fully instantiated iface method */
9420                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9421                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9422                                                 vtable_arg = NULL;
9423                                         }
9424                                 }
9425
9426                                 if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (cmethod->name, "Invoke")))
9427                                         keep_this_alive = sp [0];
9428
9429                                 if (virtual && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))
9430                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
9431                                 else
9432                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE;
9433                                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, info_type);
9434
9435                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9436                                 goto call_end;
9437                         }
9438
9439                         /* Generic sharing */
9440
9441                         /*
9442                          * Use this if the callee is gsharedvt sharable too, since
9443                          * at runtime we might find an instantiation so the call cannot
9444                          * be patched (the 'no_patch' code path in mini-trampolines.c).
9445                          */
9446                         if (context_used && !imt_arg && !array_rank && !delegate_invoke &&
9447                                 (!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
9448                                  !mono_class_generic_sharing_enabled (cmethod->klass)) &&
9449                                 (!virtual || MONO_METHOD_IS_FINAL (cmethod) ||
9450                                  !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))) {
9451                                 INLINE_FAILURE ("gshared");
9452
9453                                 g_assert (cfg->gshared && cmethod);
9454                                 g_assert (!addr);
9455
9456                                 /*
9457                                  * We are compiling a call to a
9458                                  * generic method from shared code,
9459                                  * which means that we have to look up
9460                                  * the method in the rgctx and do an
9461                                  * indirect call.
9462                                  */
9463                                 if (fsig->hasthis)
9464                                         MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9465
9466                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
9467                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9468                                 goto call_end;
9469                         }
9470
9471                         /* Direct calls to icalls */
9472                         if (direct_icall) {
9473                                 MonoMethod *wrapper;
9474                                 int costs;
9475
9476                                 /* Inline the wrapper */
9477                                 wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
9478
9479                                 costs = inline_method (cfg, wrapper, fsig, sp, ip, cfg->real_offset, TRUE);
9480                                 g_assert (costs > 0);
9481                                 cfg->real_offset += 5;
9482
9483                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9484                                         /* *sp is already set by inline_method */
9485                                         sp++;
9486                                         push_res = FALSE;
9487                                 }
9488
9489                                 inline_costs += costs;
9490
9491                                 goto call_end;
9492                         }
9493                                         
9494                         /* Array methods */
9495                         if (array_rank) {
9496                                 MonoInst *addr;
9497
9498                                 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ 
9499                                         MonoInst *val = sp [fsig->param_count];
9500
9501                                         if (val->type == STACK_OBJ) {
9502                                                 MonoInst *iargs [2];
9503
9504                                                 iargs [0] = sp [0];
9505                                                 iargs [1] = val;
9506                                                 
9507                                                 mono_emit_jit_icall (cfg, mono_helper_stelem_ref_check, iargs);
9508                                         }
9509                                         
9510                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, TRUE);
9511                                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, fsig->params [fsig->param_count - 1], addr->dreg, 0, val->dreg);
9512                                         if (cfg->gen_write_barriers && val->type == STACK_OBJ && !(val->opcode == OP_PCONST && val->inst_c0 == 0))
9513                                                 emit_write_barrier (cfg, addr, val);
9514                                         if (cfg->gen_write_barriers && mini_is_gsharedvt_klass (cmethod->klass))
9515                                                 GSHAREDVT_FAILURE (*ip);
9516                                 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
9517                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9518
9519                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, addr->dreg, 0);
9520                                 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
9521                                         if (!cmethod->klass->element_class->valuetype && !readonly)
9522                                                 mini_emit_check_array_type (cfg, sp [0], cmethod->klass);
9523                                         CHECK_TYPELOAD (cmethod->klass);
9524                                         
9525                                         readonly = FALSE;
9526                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9527                                         ins = addr;
9528                                 } else {
9529                                         g_assert_not_reached ();
9530                                 }
9531
9532                                 emit_widen = FALSE;
9533                                 goto call_end;
9534                         }
9535
9536                         ins = mini_redirect_call (cfg, cmethod, fsig, sp, virtual ? sp [0] : NULL);
9537                         if (ins)
9538                                 goto call_end;
9539
9540                         /* Tail prefix / tail call optimization */
9541
9542                         /* FIXME: Enabling TAILC breaks some inlining/stack trace/etc tests */
9543                         /* FIXME: runtime generic context pointer for jumps? */
9544                         /* FIXME: handle this for generic sharing eventually */
9545                         if ((ins_flag & MONO_INST_TAILCALL) &&
9546                                 !vtable_arg && !cfg->gshared && is_supported_tail_call (cfg, method, cmethod, fsig, call_opcode))
9547                                 supported_tail_call = TRUE;
9548
9549                         if (supported_tail_call) {
9550                                 MonoCallInst *call;
9551
9552                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9553                                 INLINE_FAILURE ("tail call");
9554
9555                                 //printf ("HIT: %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
9556
9557                                 if (cfg->backend->have_op_tail_call) {
9558                                         /* Handle tail calls similarly to normal calls */
9559                                         tail_call = TRUE;
9560                                 } else {
9561                                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
9562
9563                                         MONO_INST_NEW_CALL (cfg, call, OP_JMP);
9564                                         call->tail_call = TRUE;
9565                                         call->method = cmethod;
9566                                         call->signature = mono_method_signature (cmethod);
9567
9568                                         /*
9569                                          * We implement tail calls by storing the actual arguments into the 
9570                                          * argument variables, then emitting a CEE_JMP.
9571                                          */
9572                                         for (i = 0; i < n; ++i) {
9573                                                 /* Prevent argument from being register allocated */
9574                                                 arg_array [i]->flags |= MONO_INST_VOLATILE;
9575                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9576                                         }
9577                                         ins = (MonoInst*)call;
9578                                         ins->inst_p0 = cmethod;
9579                                         ins->inst_p1 = arg_array [0];
9580                                         MONO_ADD_INS (cfg->cbb, ins);
9581                                         link_bblock (cfg, cfg->cbb, end_bblock);
9582                                         start_new_bblock = 1;
9583
9584                                         // FIXME: Eliminate unreachable epilogs
9585
9586                                         /*
9587                                          * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9588                                          * only reachable from this call.
9589                                          */
9590                                         GET_BBLOCK (cfg, tblock, ip + 5);
9591                                         if (tblock == cfg->cbb || tblock->in_count == 0)
9592                                                 skip_ret = TRUE;
9593                                         push_res = FALSE;
9594
9595                                         goto call_end;
9596                                 }
9597                         }
9598
9599                         /* 
9600                          * Synchronized wrappers.
9601                          * Its hard to determine where to replace a method with its synchronized
9602                          * wrapper without causing an infinite recursion. The current solution is
9603                          * to add the synchronized wrapper in the trampolines, and to
9604                          * change the called method to a dummy wrapper, and resolve that wrapper
9605                          * to the real method in mono_jit_compile_method ().
9606                          */
9607                         if (cfg->method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
9608                                 MonoMethod *orig = mono_marshal_method_from_wrapper (cfg->method);
9609                                 if (cmethod == orig || (cmethod->is_inflated && mono_method_get_declaring_generic_method (cmethod) == orig))
9610                                         cmethod = mono_marshal_get_synchronized_inner_wrapper (cmethod);
9611                         }
9612
9613                         /*
9614                          * Interface calls in llvm-only mode are complicated becase the callee might need an rgctx arg,
9615                          * (i.e. its a vtype method), and there is no way to for the caller to know this at compile time.
9616                          * So we make resolve_iface_call return the rgctx, and do two calls with different signatures
9617                          * based on whenever there is an rgctx or not.
9618                          */
9619                         if (cfg->llvm_only && virtual && cmethod && (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
9620                                 MonoInst *args_buf [16], *icall_args [16];
9621                                 MonoInst **args;
9622                                 MonoBasicBlock *rgctx_bb, *end_bb;
9623                                 MonoInst *call1, *call2, *call_target;
9624                                 MonoMethodSignature *rgctx_sig;
9625                                 int rgctx_reg, tmp_reg;
9626
9627                                 MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
9628
9629                                 NEW_BBLOCK (cfg, rgctx_bb);
9630                                 NEW_BBLOCK (cfg, end_bb);
9631
9632                                 // FIXME: Optimize this
9633
9634                                 guint32 imt_slot = mono_method_get_imt_slot (cmethod);
9635
9636                                 icall_args [0] = sp [0];
9637                                 EMIT_NEW_ICONST (cfg, icall_args [1], imt_slot);
9638                                 if (imt_arg) {
9639                                         icall_args [2] = imt_arg;
9640                                 } else {
9641                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_METHODCONST, cmethod);
9642                                         icall_args [2] = ins;
9643                                 }
9644
9645                                 rgctx_reg = alloc_preg (cfg);
9646                                 MONO_EMIT_NEW_PCONST (cfg, rgctx_reg, NULL);
9647                                 EMIT_NEW_VARLOADA_VREG (cfg, icall_args [3], rgctx_reg, &mono_defaults.int_class->byval_arg);
9648                                 //EMIT_NEW_PCONST (cfg, icall_args [3], NULL);
9649
9650                                 call_target = mono_emit_jit_icall (cfg, mono_resolve_iface_call, icall_args);
9651
9652                                 // FIXME: Only do this if needed (generic calls)
9653
9654                                 // Check whenever to pass an rgctx
9655                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rgctx_reg, 0);
9656                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, rgctx_bb);
9657                                 /* Non rgctx case */
9658                                 call1 = mono_emit_calli (cfg, fsig, sp, call_target, NULL, vtable_arg);
9659                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
9660                                 /* Rgctx case */
9661                                 MONO_START_BB (cfg, rgctx_bb);
9662                                 /* Make a call with an rgctx */
9663                                 if (fsig->param_count + 2 < 16)
9664                                         args = args_buf;
9665                                 else
9666                                         args = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (fsig->param_count + 2));
9667                                 args [0] = sp [0];
9668                                 for (i = 0; i < fsig->param_count; ++i)
9669                                         args [i + 1] = sp [i + 1];
9670                                 tmp_reg = alloc_preg (cfg);
9671                                 EMIT_NEW_UNALU (cfg, args [fsig->param_count + 1], OP_MOVE, tmp_reg, rgctx_reg);
9672                                 rgctx_sig = sig_to_rgctx_sig (fsig);
9673                                 call2 = mono_emit_calli (cfg, rgctx_sig, args, call_target, NULL, NULL);
9674                                 call2->dreg = call1->dreg;
9675                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
9676                                 /* End */
9677                                 MONO_START_BB (cfg, end_bb);
9678                                 ins = call1;
9679                                 goto call_end;
9680                         }
9681
9682                         /* Common call */
9683                         INLINE_FAILURE ("call");
9684                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, tail_call, sp, virtual ? sp [0] : NULL,
9685                                                                                           imt_arg, vtable_arg);
9686
9687                         if (tail_call && !cfg->llvm_only) {
9688                                 link_bblock (cfg, cfg->cbb, end_bblock);
9689                                 start_new_bblock = 1;
9690
9691                                 // FIXME: Eliminate unreachable epilogs
9692
9693                                 /*
9694                                  * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9695                                  * only reachable from this call.
9696                                  */
9697                                 GET_BBLOCK (cfg, tblock, ip + 5);
9698                                 if (tblock == cfg->cbb || tblock->in_count == 0)
9699                                         skip_ret = TRUE;
9700                                 push_res = FALSE;
9701                         }
9702
9703                         call_end:
9704
9705                         /* End of call, INS should contain the result of the call, if any */
9706
9707                         if (push_res && !MONO_TYPE_IS_VOID (fsig->ret)) {
9708                                 g_assert (ins);
9709                                 if (emit_widen)
9710                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
9711                                 else
9712                                         *sp++ = ins;
9713                         }
9714
9715                         if (keep_this_alive) {
9716                                 MonoInst *dummy_use;
9717
9718                                 /* See mono_emit_method_call_full () */
9719                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, keep_this_alive);
9720                         }
9721
9722                         CHECK_CFG_EXCEPTION;
9723
9724                         ip += 5;
9725                         if (skip_ret) {
9726                                 g_assert (*ip == CEE_RET);
9727                                 ip += 1;
9728                         }
9729                         ins_flag = 0;
9730                         constrained_class = NULL;
9731                         if (need_seq_point)
9732                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
9733                         break;
9734                 }
9735                 case CEE_RET:
9736                         if (cfg->method != method) {
9737                                 /* return from inlined method */
9738                                 /* 
9739                                  * If in_count == 0, that means the ret is unreachable due to
9740                                  * being preceeded by a throw. In that case, inline_method () will
9741                                  * handle setting the return value 
9742                                  * (test case: test_0_inline_throw ()).
9743                                  */
9744                                 if (return_var && cfg->cbb->in_count) {
9745                                         MonoType *ret_type = mono_method_signature (method)->ret;
9746
9747                                         MonoInst *store;
9748                                         CHECK_STACK (1);
9749                                         --sp;
9750
9751                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
9752                                                 UNVERIFIED;
9753
9754                                         //g_assert (returnvar != -1);
9755                                         EMIT_NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
9756                                         cfg->ret_var_set = TRUE;
9757                                 } 
9758                         } else {
9759                                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
9760
9761                                 if (cfg->lmf_var && cfg->cbb->in_count && !cfg->llvm_only)
9762                                         emit_pop_lmf (cfg);
9763
9764                                 if (cfg->ret) {
9765                                         MonoType *ret_type = mini_get_underlying_type (mono_method_signature (method)->ret);
9766
9767                                         if (seq_points && !sym_seq_points) {
9768                                                 /* 
9769                                                  * Place a seq point here too even through the IL stack is not
9770                                                  * empty, so a step over on
9771                                                  * call <FOO>
9772                                                  * ret
9773                                                  * will work correctly.
9774                                                  */
9775                                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, TRUE);
9776                                                 MONO_ADD_INS (cfg->cbb, ins);
9777                                         }
9778
9779                                         g_assert (!return_var);
9780                                         CHECK_STACK (1);
9781                                         --sp;
9782
9783                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
9784                                                 UNVERIFIED;
9785
9786                                         emit_setret (cfg, *sp);
9787                                 }
9788                         }
9789                         if (sp != stack_start)
9790                                 UNVERIFIED;
9791                         MONO_INST_NEW (cfg, ins, OP_BR);
9792                         ip++;
9793                         ins->inst_target_bb = end_bblock;
9794                         MONO_ADD_INS (cfg->cbb, ins);
9795                         link_bblock (cfg, cfg->cbb, end_bblock);
9796                         start_new_bblock = 1;
9797                         break;
9798                 case CEE_BR_S:
9799                         CHECK_OPSIZE (2);
9800                         MONO_INST_NEW (cfg, ins, OP_BR);
9801                         ip++;
9802                         target = ip + 1 + (signed char)(*ip);
9803                         ++ip;
9804                         GET_BBLOCK (cfg, tblock, target);
9805                         link_bblock (cfg, cfg->cbb, tblock);
9806                         ins->inst_target_bb = tblock;
9807                         if (sp != stack_start) {
9808                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9809                                 sp = stack_start;
9810                                 CHECK_UNVERIFIABLE (cfg);
9811                         }
9812                         MONO_ADD_INS (cfg->cbb, ins);
9813                         start_new_bblock = 1;
9814                         inline_costs += BRANCH_COST;
9815                         break;
9816                 case CEE_BEQ_S:
9817                 case CEE_BGE_S:
9818                 case CEE_BGT_S:
9819                 case CEE_BLE_S:
9820                 case CEE_BLT_S:
9821                 case CEE_BNE_UN_S:
9822                 case CEE_BGE_UN_S:
9823                 case CEE_BGT_UN_S:
9824                 case CEE_BLE_UN_S:
9825                 case CEE_BLT_UN_S:
9826                         CHECK_OPSIZE (2);
9827                         CHECK_STACK (2);
9828                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
9829                         ip++;
9830                         target = ip + 1 + *(signed char*)ip;
9831                         ip++;
9832
9833                         ADD_BINCOND (NULL);
9834
9835                         sp = stack_start;
9836                         inline_costs += BRANCH_COST;
9837                         break;
9838                 case CEE_BR:
9839                         CHECK_OPSIZE (5);
9840                         MONO_INST_NEW (cfg, ins, OP_BR);
9841                         ip++;
9842
9843                         target = ip + 4 + (gint32)read32(ip);
9844                         ip += 4;
9845                         GET_BBLOCK (cfg, tblock, target);
9846                         link_bblock (cfg, cfg->cbb, tblock);
9847                         ins->inst_target_bb = tblock;
9848                         if (sp != stack_start) {
9849                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9850                                 sp = stack_start;
9851                                 CHECK_UNVERIFIABLE (cfg);
9852                         }
9853
9854                         MONO_ADD_INS (cfg->cbb, ins);
9855
9856                         start_new_bblock = 1;
9857                         inline_costs += BRANCH_COST;
9858                         break;
9859                 case CEE_BRFALSE_S:
9860                 case CEE_BRTRUE_S:
9861                 case CEE_BRFALSE:
9862                 case CEE_BRTRUE: {
9863                         MonoInst *cmp;
9864                         gboolean is_short = ((*ip) == CEE_BRFALSE_S) || ((*ip) == CEE_BRTRUE_S);
9865                         gboolean is_true = ((*ip) == CEE_BRTRUE_S) || ((*ip) == CEE_BRTRUE);
9866                         guint32 opsize = is_short ? 1 : 4;
9867
9868                         CHECK_OPSIZE (opsize);
9869                         CHECK_STACK (1);
9870                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
9871                                 UNVERIFIED;
9872                         ip ++;
9873                         target = ip + opsize + (is_short ? *(signed char*)ip : (gint32)read32(ip));
9874                         ip += opsize;
9875
9876                         sp--;
9877
9878                         GET_BBLOCK (cfg, tblock, target);
9879                         link_bblock (cfg, cfg->cbb, tblock);
9880                         GET_BBLOCK (cfg, tblock, ip);
9881                         link_bblock (cfg, cfg->cbb, tblock);
9882
9883                         if (sp != stack_start) {
9884                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9885                                 CHECK_UNVERIFIABLE (cfg);
9886                         }
9887
9888                         MONO_INST_NEW(cfg, cmp, OP_ICOMPARE_IMM);
9889                         cmp->sreg1 = sp [0]->dreg;
9890                         type_from_op (cfg, cmp, sp [0], NULL);
9891                         CHECK_TYPE (cmp);
9892
9893 #if SIZEOF_REGISTER == 4
9894                         if (cmp->opcode == OP_LCOMPARE_IMM) {
9895                                 /* Convert it to OP_LCOMPARE */
9896                                 MONO_INST_NEW (cfg, ins, OP_I8CONST);
9897                                 ins->type = STACK_I8;
9898                                 ins->dreg = alloc_dreg (cfg, STACK_I8);
9899                                 ins->inst_l = 0;
9900                                 MONO_ADD_INS (cfg->cbb, ins);
9901                                 cmp->opcode = OP_LCOMPARE;
9902                                 cmp->sreg2 = ins->dreg;
9903                         }
9904 #endif
9905                         MONO_ADD_INS (cfg->cbb, cmp);
9906
9907                         MONO_INST_NEW (cfg, ins, is_true ? CEE_BNE_UN : CEE_BEQ);
9908                         type_from_op (cfg, ins, sp [0], NULL);
9909                         MONO_ADD_INS (cfg->cbb, ins);
9910                         ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);
9911                         GET_BBLOCK (cfg, tblock, target);
9912                         ins->inst_true_bb = tblock;
9913                         GET_BBLOCK (cfg, tblock, ip);
9914                         ins->inst_false_bb = tblock;
9915                         start_new_bblock = 2;
9916
9917                         sp = stack_start;
9918                         inline_costs += BRANCH_COST;
9919                         break;
9920                 }
9921                 case CEE_BEQ:
9922                 case CEE_BGE:
9923                 case CEE_BGT:
9924                 case CEE_BLE:
9925                 case CEE_BLT:
9926                 case CEE_BNE_UN:
9927                 case CEE_BGE_UN:
9928                 case CEE_BGT_UN:
9929                 case CEE_BLE_UN:
9930                 case CEE_BLT_UN:
9931                         CHECK_OPSIZE (5);
9932                         CHECK_STACK (2);
9933                         MONO_INST_NEW (cfg, ins, *ip);
9934                         ip++;
9935                         target = ip + 4 + (gint32)read32(ip);
9936                         ip += 4;
9937
9938                         ADD_BINCOND (NULL);
9939
9940                         sp = stack_start;
9941                         inline_costs += BRANCH_COST;
9942                         break;
9943                 case CEE_SWITCH: {
9944                         MonoInst *src1;
9945                         MonoBasicBlock **targets;
9946                         MonoBasicBlock *default_bblock;
9947                         MonoJumpInfoBBTable *table;
9948                         int offset_reg = alloc_preg (cfg);
9949                         int target_reg = alloc_preg (cfg);
9950                         int table_reg = alloc_preg (cfg);
9951                         int sum_reg = alloc_preg (cfg);
9952                         gboolean use_op_switch;
9953
9954                         CHECK_OPSIZE (5);
9955                         CHECK_STACK (1);
9956                         n = read32 (ip + 1);
9957                         --sp;
9958                         src1 = sp [0];
9959                         if ((src1->type != STACK_I4) && (src1->type != STACK_PTR)) 
9960                                 UNVERIFIED;
9961
9962                         ip += 5;
9963                         CHECK_OPSIZE (n * sizeof (guint32));
9964                         target = ip + n * sizeof (guint32);
9965
9966                         GET_BBLOCK (cfg, default_bblock, target);
9967                         default_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
9968
9969                         targets = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * n);
9970                         for (i = 0; i < n; ++i) {
9971                                 GET_BBLOCK (cfg, tblock, target + (gint32)read32(ip));
9972                                 targets [i] = tblock;
9973                                 targets [i]->flags |= BB_INDIRECT_JUMP_TARGET;
9974                                 ip += 4;
9975                         }
9976
9977                         if (sp != stack_start) {
9978                                 /* 
9979                                  * Link the current bb with the targets as well, so handle_stack_args
9980                                  * will set their in_stack correctly.
9981                                  */
9982                                 link_bblock (cfg, cfg->cbb, default_bblock);
9983                                 for (i = 0; i < n; ++i)
9984                                         link_bblock (cfg, cfg->cbb, targets [i]);
9985
9986                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9987                                 sp = stack_start;
9988                                 CHECK_UNVERIFIABLE (cfg);
9989
9990                                 /* Undo the links */
9991                                 mono_unlink_bblock (cfg, cfg->cbb, default_bblock);
9992                                 for (i = 0; i < n; ++i)
9993                                         mono_unlink_bblock (cfg, cfg->cbb, targets [i]);
9994                         }
9995
9996                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, src1->dreg, n);
9997                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBGE_UN, default_bblock);
9998
9999                         for (i = 0; i < n; ++i)
10000                                 link_bblock (cfg, cfg->cbb, targets [i]);
10001
10002                         table = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
10003                         table->table = targets;
10004                         table->table_size = n;
10005
10006                         use_op_switch = FALSE;
10007 #ifdef TARGET_ARM
10008                         /* ARM implements SWITCH statements differently */
10009                         /* FIXME: Make it use the generic implementation */
10010                         if (!cfg->compile_aot)
10011                                 use_op_switch = TRUE;
10012 #endif
10013
10014                         if (COMPILE_LLVM (cfg))
10015                                 use_op_switch = TRUE;
10016
10017                         cfg->cbb->has_jump_table = 1;
10018
10019                         if (use_op_switch) {
10020                                 MONO_INST_NEW (cfg, ins, OP_SWITCH);
10021                                 ins->sreg1 = src1->dreg;
10022                                 ins->inst_p0 = table;
10023                                 ins->inst_many_bb = targets;
10024                                 ins->klass = GUINT_TO_POINTER (n);
10025                                 MONO_ADD_INS (cfg->cbb, ins);
10026                         } else {
10027                                 if (sizeof (gpointer) == 8)
10028                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 3);
10029                                 else
10030                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 2);
10031
10032 #if SIZEOF_REGISTER == 8
10033                                 /* The upper word might not be zero, and we add it to a 64 bit address later */
10034                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, offset_reg, offset_reg);
10035 #endif
10036
10037                                 if (cfg->compile_aot) {
10038                                         MONO_EMIT_NEW_AOTCONST (cfg, table_reg, table, MONO_PATCH_INFO_SWITCH);
10039                                 } else {
10040                                         MONO_INST_NEW (cfg, ins, OP_JUMP_TABLE);
10041                                         ins->inst_c1 = MONO_PATCH_INFO_SWITCH;
10042                                         ins->inst_p0 = table;
10043                                         ins->dreg = table_reg;
10044                                         MONO_ADD_INS (cfg->cbb, ins);
10045                                 }
10046
10047                                 /* FIXME: Use load_memindex */
10048                                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, table_reg, offset_reg);
10049                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, target_reg, sum_reg, 0);
10050                                 MONO_EMIT_NEW_UNALU (cfg, OP_BR_REG, -1, target_reg);
10051                         }
10052                         start_new_bblock = 1;
10053                         inline_costs += (BRANCH_COST * 2);
10054                         break;
10055                 }
10056                 case CEE_LDIND_I1:
10057                 case CEE_LDIND_U1:
10058                 case CEE_LDIND_I2:
10059                 case CEE_LDIND_U2:
10060                 case CEE_LDIND_I4:
10061                 case CEE_LDIND_U4:
10062                 case CEE_LDIND_I8:
10063                 case CEE_LDIND_I:
10064                 case CEE_LDIND_R4:
10065                 case CEE_LDIND_R8:
10066                 case CEE_LDIND_REF:
10067                         CHECK_STACK (1);
10068                         --sp;
10069
10070                         switch (*ip) {
10071                         case CEE_LDIND_R4:
10072                         case CEE_LDIND_R8:
10073                                 dreg = alloc_freg (cfg);
10074                                 break;
10075                         case CEE_LDIND_I8:
10076                                 dreg = alloc_lreg (cfg);
10077                                 break;
10078                         case CEE_LDIND_REF:
10079                                 dreg = alloc_ireg_ref (cfg);
10080                                 break;
10081                         default:
10082                                 dreg = alloc_preg (cfg);
10083                         }
10084
10085                         NEW_LOAD_MEMBASE (cfg, ins, ldind_to_load_membase (*ip), dreg, sp [0]->dreg, 0);
10086                         ins->type = ldind_type [*ip - CEE_LDIND_I1];
10087                         if (*ip == CEE_LDIND_R4)
10088                                 ins->type = cfg->r4_stack_type;
10089                         ins->flags |= ins_flag;
10090                         MONO_ADD_INS (cfg->cbb, ins);
10091                         *sp++ = ins;
10092                         if (ins_flag & MONO_INST_VOLATILE) {
10093                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10094                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10095                         }
10096                         ins_flag = 0;
10097                         ++ip;
10098                         break;
10099                 case CEE_STIND_REF:
10100                 case CEE_STIND_I1:
10101                 case CEE_STIND_I2:
10102                 case CEE_STIND_I4:
10103                 case CEE_STIND_I8:
10104                 case CEE_STIND_R4:
10105                 case CEE_STIND_R8:
10106                 case CEE_STIND_I:
10107                         CHECK_STACK (2);
10108                         sp -= 2;
10109
10110                         if (ins_flag & MONO_INST_VOLATILE) {
10111                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
10112                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
10113                         }
10114
10115                         NEW_STORE_MEMBASE (cfg, ins, stind_to_store_membase (*ip), sp [0]->dreg, 0, sp [1]->dreg);
10116                         ins->flags |= ins_flag;
10117                         ins_flag = 0;
10118
10119                         MONO_ADD_INS (cfg->cbb, ins);
10120
10121                         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)))
10122                                 emit_write_barrier (cfg, sp [0], sp [1]);
10123
10124                         inline_costs += 1;
10125                         ++ip;
10126                         break;
10127
10128                 case CEE_MUL:
10129                         CHECK_STACK (2);
10130
10131                         MONO_INST_NEW (cfg, ins, (*ip));
10132                         sp -= 2;
10133                         ins->sreg1 = sp [0]->dreg;
10134                         ins->sreg2 = sp [1]->dreg;
10135                         type_from_op (cfg, ins, sp [0], sp [1]);
10136                         CHECK_TYPE (ins);
10137                         ins->dreg = alloc_dreg ((cfg), (ins)->type);
10138
10139                         /* Use the immediate opcodes if possible */
10140                         if ((sp [1]->opcode == OP_ICONST) && mono_arch_is_inst_imm (sp [1]->inst_c0)) {
10141                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
10142                                 if (imm_opcode != -1) {
10143                                         ins->opcode = imm_opcode;
10144                                         ins->inst_p1 = (gpointer)(gssize)(sp [1]->inst_c0);
10145                                         ins->sreg2 = -1;
10146
10147                                         NULLIFY_INS (sp [1]);
10148                                 }
10149                         }
10150
10151                         MONO_ADD_INS ((cfg)->cbb, (ins));
10152
10153                         *sp++ = mono_decompose_opcode (cfg, ins);
10154                         ip++;
10155                         break;
10156                 case CEE_ADD:
10157                 case CEE_SUB:
10158                 case CEE_DIV:
10159                 case CEE_DIV_UN:
10160                 case CEE_REM:
10161                 case CEE_REM_UN:
10162                 case CEE_AND:
10163                 case CEE_OR:
10164                 case CEE_XOR:
10165                 case CEE_SHL:
10166                 case CEE_SHR:
10167                 case CEE_SHR_UN:
10168                         CHECK_STACK (2);
10169
10170                         MONO_INST_NEW (cfg, ins, (*ip));
10171                         sp -= 2;
10172                         ins->sreg1 = sp [0]->dreg;
10173                         ins->sreg2 = sp [1]->dreg;
10174                         type_from_op (cfg, ins, sp [0], sp [1]);
10175                         CHECK_TYPE (ins);
10176                         add_widen_op (cfg, ins, &sp [0], &sp [1]);
10177                         ins->dreg = alloc_dreg ((cfg), (ins)->type);
10178
10179                         /* FIXME: Pass opcode to is_inst_imm */
10180
10181                         /* Use the immediate opcodes if possible */
10182                         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)) {
10183                                 int imm_opcode;
10184
10185                                 imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
10186 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
10187                                 /* Keep emulated opcodes which are optimized away later */
10188                                 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) {
10189                                         imm_opcode = mono_op_to_op_imm (ins->opcode);
10190                                 }
10191 #endif
10192                                 if (imm_opcode != -1) {
10193                                         ins->opcode = imm_opcode;
10194                                         if (sp [1]->opcode == OP_I8CONST) {
10195 #if SIZEOF_REGISTER == 8
10196                                                 ins->inst_imm = sp [1]->inst_l;
10197 #else
10198                                                 ins->inst_ls_word = sp [1]->inst_ls_word;
10199                                                 ins->inst_ms_word = sp [1]->inst_ms_word;
10200 #endif
10201                                         }
10202                                         else
10203                                                 ins->inst_imm = (gssize)(sp [1]->inst_c0);
10204                                         ins->sreg2 = -1;
10205
10206                                         /* Might be followed by an instruction added by add_widen_op */
10207                                         if (sp [1]->next == NULL)
10208                                                 NULLIFY_INS (sp [1]);
10209                                 }
10210                         }
10211                         MONO_ADD_INS ((cfg)->cbb, (ins));
10212
10213                         *sp++ = mono_decompose_opcode (cfg, ins);
10214                         ip++;
10215                         break;
10216                 case CEE_NEG:
10217                 case CEE_NOT:
10218                 case CEE_CONV_I1:
10219                 case CEE_CONV_I2:
10220                 case CEE_CONV_I4:
10221                 case CEE_CONV_R4:
10222                 case CEE_CONV_R8:
10223                 case CEE_CONV_U4:
10224                 case CEE_CONV_I8:
10225                 case CEE_CONV_U8:
10226                 case CEE_CONV_OVF_I8:
10227                 case CEE_CONV_OVF_U8:
10228                 case CEE_CONV_R_UN:
10229                         CHECK_STACK (1);
10230
10231                         /* Special case this earlier so we have long constants in the IR */
10232                         if ((((*ip) == CEE_CONV_I8) || ((*ip) == CEE_CONV_U8)) && (sp [-1]->opcode == OP_ICONST)) {
10233                                 int data = sp [-1]->inst_c0;
10234                                 sp [-1]->opcode = OP_I8CONST;
10235                                 sp [-1]->type = STACK_I8;
10236 #if SIZEOF_REGISTER == 8
10237                                 if ((*ip) == CEE_CONV_U8)
10238                                         sp [-1]->inst_c0 = (guint32)data;
10239                                 else
10240                                         sp [-1]->inst_c0 = data;
10241 #else
10242                                 sp [-1]->inst_ls_word = data;
10243                                 if ((*ip) == CEE_CONV_U8)
10244                                         sp [-1]->inst_ms_word = 0;
10245                                 else
10246                                         sp [-1]->inst_ms_word = (data < 0) ? -1 : 0;
10247 #endif
10248                                 sp [-1]->dreg = alloc_dreg (cfg, STACK_I8);
10249                         }
10250                         else {
10251                                 ADD_UNOP (*ip);
10252                         }
10253                         ip++;
10254                         break;
10255                 case CEE_CONV_OVF_I4:
10256                 case CEE_CONV_OVF_I1:
10257                 case CEE_CONV_OVF_I2:
10258                 case CEE_CONV_OVF_I:
10259                 case CEE_CONV_OVF_U:
10260                         CHECK_STACK (1);
10261
10262                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
10263                                 ADD_UNOP (CEE_CONV_OVF_I8);
10264                                 ADD_UNOP (*ip);
10265                         } else {
10266                                 ADD_UNOP (*ip);
10267                         }
10268                         ip++;
10269                         break;
10270                 case CEE_CONV_OVF_U1:
10271                 case CEE_CONV_OVF_U2:
10272                 case CEE_CONV_OVF_U4:
10273                         CHECK_STACK (1);
10274
10275                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
10276                                 ADD_UNOP (CEE_CONV_OVF_U8);
10277                                 ADD_UNOP (*ip);
10278                         } else {
10279                                 ADD_UNOP (*ip);
10280                         }
10281                         ip++;
10282                         break;
10283                 case CEE_CONV_OVF_I1_UN:
10284                 case CEE_CONV_OVF_I2_UN:
10285                 case CEE_CONV_OVF_I4_UN:
10286                 case CEE_CONV_OVF_I8_UN:
10287                 case CEE_CONV_OVF_U1_UN:
10288                 case CEE_CONV_OVF_U2_UN:
10289                 case CEE_CONV_OVF_U4_UN:
10290                 case CEE_CONV_OVF_U8_UN:
10291                 case CEE_CONV_OVF_I_UN:
10292                 case CEE_CONV_OVF_U_UN:
10293                 case CEE_CONV_U2:
10294                 case CEE_CONV_U1:
10295                 case CEE_CONV_I:
10296                 case CEE_CONV_U:
10297                         CHECK_STACK (1);
10298                         ADD_UNOP (*ip);
10299                         CHECK_CFG_EXCEPTION;
10300                         ip++;
10301                         break;
10302                 case CEE_ADD_OVF:
10303                 case CEE_ADD_OVF_UN:
10304                 case CEE_MUL_OVF:
10305                 case CEE_MUL_OVF_UN:
10306                 case CEE_SUB_OVF:
10307                 case CEE_SUB_OVF_UN:
10308                         CHECK_STACK (2);
10309                         ADD_BINOP (*ip);
10310                         ip++;
10311                         break;
10312                 case CEE_CPOBJ:
10313                         GSHAREDVT_FAILURE (*ip);
10314                         CHECK_OPSIZE (5);
10315                         CHECK_STACK (2);
10316                         token = read32 (ip + 1);
10317                         klass = mini_get_class (method, token, generic_context);
10318                         CHECK_TYPELOAD (klass);
10319                         sp -= 2;
10320                         if (generic_class_is_reference_type (cfg, klass)) {
10321                                 MonoInst *store, *load;
10322                                 int dreg = alloc_ireg_ref (cfg);
10323
10324                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, dreg, sp [1]->dreg, 0);
10325                                 load->flags |= ins_flag;
10326                                 MONO_ADD_INS (cfg->cbb, load);
10327
10328                                 NEW_STORE_MEMBASE (cfg, store, OP_STORE_MEMBASE_REG, sp [0]->dreg, 0, dreg);
10329                                 store->flags |= ins_flag;
10330                                 MONO_ADD_INS (cfg->cbb, store);
10331
10332                                 if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER)
10333                                         emit_write_barrier (cfg, sp [0], sp [1]);
10334                         } else {
10335                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
10336                         }
10337                         ins_flag = 0;
10338                         ip += 5;
10339                         break;
10340                 case CEE_LDOBJ: {
10341                         int loc_index = -1;
10342                         int stloc_len = 0;
10343
10344                         CHECK_OPSIZE (5);
10345                         CHECK_STACK (1);
10346                         --sp;
10347                         token = read32 (ip + 1);
10348                         klass = mini_get_class (method, token, generic_context);
10349                         CHECK_TYPELOAD (klass);
10350
10351                         /* Optimize the common ldobj+stloc combination */
10352                         switch (ip [5]) {
10353                         case CEE_STLOC_S:
10354                                 loc_index = ip [6];
10355                                 stloc_len = 2;
10356                                 break;
10357                         case CEE_STLOC_0:
10358                         case CEE_STLOC_1:
10359                         case CEE_STLOC_2:
10360                         case CEE_STLOC_3:
10361                                 loc_index = ip [5] - CEE_STLOC_0;
10362                                 stloc_len = 1;
10363                                 break;
10364                         default:
10365                                 break;
10366                         }
10367
10368                         if ((loc_index != -1) && ip_in_bb (cfg, cfg->cbb, ip + 5)) {
10369                                 CHECK_LOCAL (loc_index);
10370
10371                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10372                                 ins->dreg = cfg->locals [loc_index]->dreg;
10373                                 ins->flags |= ins_flag;
10374                                 ip += 5;
10375                                 ip += stloc_len;
10376                                 if (ins_flag & MONO_INST_VOLATILE) {
10377                                         /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10378                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10379                                 }
10380                                 ins_flag = 0;
10381                                 break;
10382                         }
10383
10384                         /* Optimize the ldobj+stobj combination */
10385                         /* The reference case ends up being a load+store anyway */
10386                         /* Skip this if the operation is volatile. */
10387                         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)) {
10388                                 CHECK_STACK (1);
10389
10390                                 sp --;
10391
10392                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
10393
10394                                 ip += 5 + 5;
10395                                 ins_flag = 0;
10396                                 break;
10397                         }
10398
10399                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10400                         ins->flags |= ins_flag;
10401                         *sp++ = ins;
10402
10403                         if (ins_flag & MONO_INST_VOLATILE) {
10404                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10405                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10406                         }
10407
10408                         ip += 5;
10409                         ins_flag = 0;
10410                         inline_costs += 1;
10411                         break;
10412                 }
10413                 case CEE_LDSTR:
10414                         CHECK_STACK_OVF (1);
10415                         CHECK_OPSIZE (5);
10416                         n = read32 (ip + 1);
10417
10418                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
10419                                 EMIT_NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
10420                                 ins->type = STACK_OBJ;
10421                                 *sp = ins;
10422                         }
10423                         else if (method->wrapper_type != MONO_WRAPPER_NONE) {
10424                                 MonoInst *iargs [1];
10425                                 char *str = mono_method_get_wrapper_data (method, n);
10426
10427                                 if (cfg->compile_aot)
10428                                         EMIT_NEW_LDSTRLITCONST (cfg, iargs [0], str);
10429                                 else
10430                                         EMIT_NEW_PCONST (cfg, iargs [0], str);
10431                                 *sp = mono_emit_jit_icall (cfg, mono_string_new_wrapper, iargs);
10432                         } else {
10433                                 if (cfg->opt & MONO_OPT_SHARED) {
10434                                         MonoInst *iargs [3];
10435
10436                                         if (cfg->compile_aot) {
10437                                                 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
10438                                         }
10439                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10440                                         EMIT_NEW_IMAGECONST (cfg, iargs [1], image);
10441                                         EMIT_NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
10442                                         *sp = mono_emit_jit_icall (cfg, mono_ldstr, iargs);
10443                                         mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
10444                                 } else {
10445                                         if (cfg->cbb->out_of_line) {
10446                                                 MonoInst *iargs [2];
10447
10448                                                 if (image == mono_defaults.corlib) {
10449                                                         /* 
10450                                                          * Avoid relocations in AOT and save some space by using a 
10451                                                          * version of helper_ldstr specialized to mscorlib.
10452                                                          */
10453                                                         EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (n));
10454                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr_mscorlib, iargs);
10455                                                 } else {
10456                                                         /* Avoid creating the string object */
10457                                                         EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
10458                                                         EMIT_NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n));
10459                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr, iargs);
10460                                                 }
10461                                         } 
10462                                         else
10463                                         if (cfg->compile_aot) {
10464                                                 NEW_LDSTRCONST (cfg, ins, image, n);
10465                                                 *sp = ins;
10466                                                 MONO_ADD_INS (cfg->cbb, ins);
10467                                         } 
10468                                         else {
10469                                                 NEW_PCONST (cfg, ins, NULL);
10470                                                 ins->type = STACK_OBJ;
10471                                                 ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
10472                                                 if (!ins->inst_p0)
10473                                                         OUT_OF_MEMORY_FAILURE;
10474
10475                                                 *sp = ins;
10476                                                 MONO_ADD_INS (cfg->cbb, ins);
10477                                         }
10478                                 }
10479                         }
10480
10481                         sp++;
10482                         ip += 5;
10483                         break;
10484                 case CEE_NEWOBJ: {
10485                         MonoInst *iargs [2];
10486                         MonoMethodSignature *fsig;
10487                         MonoInst this_ins;
10488                         MonoInst *alloc;
10489                         MonoInst *vtable_arg = NULL;
10490
10491                         CHECK_OPSIZE (5);
10492                         token = read32 (ip + 1);
10493                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
10494                         if (!cmethod || mono_loader_get_last_error ())
10495                                 LOAD_ERROR;
10496                         fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
10497                         CHECK_CFG_ERROR;
10498
10499                         mono_save_token_info (cfg, image, token, cmethod);
10500
10501                         if (!mono_class_init (cmethod->klass))
10502                                 TYPE_LOAD_ERROR (cmethod->klass);
10503
10504                         context_used = mini_method_check_context_used (cfg, cmethod);
10505
10506                         if (mono_security_core_clr_enabled ())
10507                                 ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
10508
10509                         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)) {
10510                                 emit_class_init (cfg, cmethod->klass);
10511                                 CHECK_TYPELOAD (cmethod->klass);
10512                         }
10513
10514                         /*
10515                         if (cfg->gsharedvt) {
10516                                 if (mini_is_gsharedvt_variable_signature (sig))
10517                                         GSHAREDVT_FAILURE (*ip);
10518                         }
10519                         */
10520
10521                         n = fsig->param_count;
10522                         CHECK_STACK (n);
10523
10524                         /* 
10525                          * Generate smaller code for the common newobj <exception> instruction in
10526                          * argument checking code.
10527                          */
10528                         if (cfg->cbb->out_of_line && cmethod->klass->image == mono_defaults.corlib &&
10529                                 is_exception_class (cmethod->klass) && n <= 2 &&
10530                                 ((n < 1) || (!fsig->params [0]->byref && fsig->params [0]->type == MONO_TYPE_STRING)) && 
10531                                 ((n < 2) || (!fsig->params [1]->byref && fsig->params [1]->type == MONO_TYPE_STRING))) {
10532                                 MonoInst *iargs [3];
10533
10534                                 sp -= n;
10535
10536                                 EMIT_NEW_ICONST (cfg, iargs [0], cmethod->klass->type_token);
10537                                 switch (n) {
10538                                 case 0:
10539                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_0, iargs);
10540                                         break;
10541                                 case 1:
10542                                         iargs [1] = sp [0];
10543                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_1, iargs);
10544                                         break;
10545                                 case 2:
10546                                         iargs [1] = sp [0];
10547                                         iargs [2] = sp [1];
10548                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_2, iargs);
10549                                         break;
10550                                 default:
10551                                         g_assert_not_reached ();
10552                                 }
10553
10554                                 ip += 5;
10555                                 inline_costs += 5;
10556                                 break;
10557                         }
10558
10559                         /* move the args to allow room for 'this' in the first position */
10560                         while (n--) {
10561                                 --sp;
10562                                 sp [1] = sp [0];
10563                         }
10564
10565                         /* check_call_signature () requires sp[0] to be set */
10566                         this_ins.type = STACK_OBJ;
10567                         sp [0] = &this_ins;
10568                         if (check_call_signature (cfg, fsig, sp))
10569                                 UNVERIFIED;
10570
10571                         iargs [0] = NULL;
10572
10573                         if (mini_class_is_system_array (cmethod->klass)) {
10574                                 *sp = emit_get_rgctx_method (cfg, context_used,
10575                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
10576
10577                                 /* Avoid varargs in the common case */
10578                                 if (fsig->param_count == 1)
10579                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_1, sp);
10580                                 else if (fsig->param_count == 2)
10581                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_2, sp);
10582                                 else if (fsig->param_count == 3)
10583                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_3, sp);
10584                                 else if (fsig->param_count == 4)
10585                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_4, sp);
10586                                 else
10587                                         alloc = handle_array_new (cfg, fsig->param_count, sp, ip);
10588                         } else if (cmethod->string_ctor) {
10589                                 g_assert (!context_used);
10590                                 g_assert (!vtable_arg);
10591                                 /* we simply pass a null pointer */
10592                                 EMIT_NEW_PCONST (cfg, *sp, NULL); 
10593                                 /* now call the string ctor */
10594                                 alloc = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, NULL, NULL, NULL);
10595                         } else {
10596                                 if (cmethod->klass->valuetype) {
10597                                         iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
10598                                         emit_init_rvar (cfg, iargs [0]->dreg, &cmethod->klass->byval_arg);
10599                                         EMIT_NEW_TEMPLOADA (cfg, *sp, iargs [0]->inst_c0);
10600
10601                                         alloc = NULL;
10602
10603                                         /* 
10604                                          * The code generated by mini_emit_virtual_call () expects
10605                                          * iargs [0] to be a boxed instance, but luckily the vcall
10606                                          * will be transformed into a normal call there.
10607                                          */
10608                                 } else if (context_used) {
10609                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, context_used);
10610                                         *sp = alloc;
10611                                 } else {
10612                                         MonoVTable *vtable = NULL;
10613
10614                                         if (!cfg->compile_aot)
10615                                                 vtable = mono_class_vtable (cfg->domain, cmethod->klass);
10616                                         CHECK_TYPELOAD (cmethod->klass);
10617
10618                                         /*
10619                                          * TypeInitializationExceptions thrown from the mono_runtime_class_init
10620                                          * call in mono_jit_runtime_invoke () can abort the finalizer thread.
10621                                          * As a workaround, we call class cctors before allocating objects.
10622                                          */
10623                                         if (mini_field_access_needs_cctor_run (cfg, method, cmethod->klass, vtable) && !(g_slist_find (class_inits, cmethod->klass))) {
10624                                                 emit_class_init (cfg, cmethod->klass);
10625                                                 if (cfg->verbose_level > 2)
10626                                                         printf ("class %s.%s needs init call for ctor\n", cmethod->klass->name_space, cmethod->klass->name);
10627                                                 class_inits = g_slist_prepend (class_inits, cmethod->klass);
10628                                         }
10629
10630                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, 0);
10631                                         *sp = alloc;
10632                                 }
10633                                 CHECK_CFG_EXCEPTION; /*for handle_alloc*/
10634
10635                                 if (alloc)
10636                                         MONO_EMIT_NEW_UNALU (cfg, OP_NOT_NULL, -1, alloc->dreg);
10637
10638                                 /* Now call the actual ctor */
10639                                 handle_ctor_call (cfg, cmethod, fsig, context_used, sp, ip, &inline_costs);
10640                                 CHECK_CFG_EXCEPTION;
10641                         }
10642
10643                         if (alloc == NULL) {
10644                                 /* Valuetype */
10645                                 EMIT_NEW_TEMPLOAD (cfg, ins, iargs [0]->inst_c0);
10646                                 type_to_eval_stack_type (cfg, &ins->klass->byval_arg, ins);
10647                                 *sp++= ins;
10648                         } else {
10649                                 *sp++ = alloc;
10650                         }
10651                         
10652                         ip += 5;
10653                         inline_costs += 5;
10654                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip - header->code)))
10655                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
10656                         break;
10657                 }
10658                 case CEE_CASTCLASS:
10659                         CHECK_STACK (1);
10660                         --sp;
10661                         CHECK_OPSIZE (5);
10662                         token = read32 (ip + 1);
10663                         klass = mini_get_class (method, token, generic_context);
10664                         CHECK_TYPELOAD (klass);
10665                         if (sp [0]->type != STACK_OBJ)
10666                                 UNVERIFIED;
10667
10668                         ins = handle_castclass (cfg, klass, *sp, ip, &inline_costs);
10669                         CHECK_CFG_EXCEPTION;
10670
10671                         *sp ++ = ins;
10672                         ip += 5;
10673                         break;
10674                 case CEE_ISINST: {
10675                         CHECK_STACK (1);
10676                         --sp;
10677                         CHECK_OPSIZE (5);
10678                         token = read32 (ip + 1);
10679                         klass = mini_get_class (method, token, generic_context);
10680                         CHECK_TYPELOAD (klass);
10681                         if (sp [0]->type != STACK_OBJ)
10682                                 UNVERIFIED;
10683  
10684                         context_used = mini_class_check_context_used (cfg, klass);
10685
10686                         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
10687                                 MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
10688                                 MonoInst *args [3];
10689                                 int idx;
10690
10691                                 /* obj */
10692                                 args [0] = *sp;
10693
10694                                 /* klass */
10695                                 EMIT_NEW_CLASSCONST (cfg, args [1], klass);
10696
10697                                 /* inline cache*/
10698                                 idx = get_castclass_cache_idx (cfg);
10699                                 args [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
10700
10701                                 *sp++ = mono_emit_method_call (cfg, mono_isinst, args, NULL);
10702                                 ip += 5;
10703                                 inline_costs += 2;
10704                         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
10705                                 MonoMethod *mono_isinst;
10706                                 MonoInst *iargs [1];
10707                                 int costs;
10708
10709                                 mono_isinst = mono_marshal_get_isinst (klass); 
10710                                 iargs [0] = sp [0];
10711
10712                                 costs = inline_method (cfg, mono_isinst, mono_method_signature (mono_isinst), 
10713                                                                            iargs, ip, cfg->real_offset, TRUE);
10714                                 CHECK_CFG_EXCEPTION;
10715                                 g_assert (costs > 0);
10716                                 
10717                                 ip += 5;
10718                                 cfg->real_offset += 5;
10719
10720                                 *sp++= iargs [0];
10721
10722                                 inline_costs += costs;
10723                         }
10724                         else {
10725                                 ins = handle_isinst (cfg, klass, *sp, context_used);
10726                                 CHECK_CFG_EXCEPTION;
10727                                 *sp ++ = ins;
10728                                 ip += 5;
10729                         }
10730                         break;
10731                 }
10732                 case CEE_UNBOX_ANY: {
10733                         MonoInst *res, *addr;
10734
10735                         CHECK_STACK (1);
10736                         --sp;
10737                         CHECK_OPSIZE (5);
10738                         token = read32 (ip + 1);
10739                         klass = mini_get_class (method, token, generic_context);
10740                         CHECK_TYPELOAD (klass);
10741
10742                         mono_save_token_info (cfg, image, token, klass);
10743
10744                         context_used = mini_class_check_context_used (cfg, klass);
10745
10746                         if (mini_is_gsharedvt_klass (klass)) {
10747                                 res = handle_unbox_gsharedvt (cfg, klass, *sp);
10748                                 inline_costs += 2;
10749                         } else if (generic_class_is_reference_type (cfg, klass)) {
10750                                 res = handle_castclass (cfg, klass, *sp, ip, &inline_costs);
10751                                 CHECK_CFG_EXCEPTION;
10752                         } else if (mono_class_is_nullable (klass)) {
10753                                 res = handle_unbox_nullable (cfg, *sp, klass, context_used);
10754                         } else {
10755                                 addr = handle_unbox (cfg, klass, sp, context_used);
10756                                 /* LDOBJ */
10757                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
10758                                 res = ins;
10759                                 inline_costs += 2;
10760                         }
10761
10762                         *sp ++ = res;
10763                         ip += 5;
10764                         break;
10765                 }
10766                 case CEE_BOX: {
10767                         MonoInst *val;
10768                         MonoClass *enum_class;
10769                         MonoMethod *has_flag;
10770
10771                         CHECK_STACK (1);
10772                         --sp;
10773                         val = *sp;
10774                         CHECK_OPSIZE (5);
10775                         token = read32 (ip + 1);
10776                         klass = mini_get_class (method, token, generic_context);
10777                         CHECK_TYPELOAD (klass);
10778
10779                         mono_save_token_info (cfg, image, token, klass);
10780
10781                         context_used = mini_class_check_context_used (cfg, klass);
10782
10783                         if (generic_class_is_reference_type (cfg, klass)) {
10784                                 *sp++ = val;
10785                                 ip += 5;
10786                                 break;
10787                         }
10788
10789                         if (klass == mono_defaults.void_class)
10790                                 UNVERIFIED;
10791                         if (target_type_is_incompatible (cfg, &klass->byval_arg, *sp))
10792                                 UNVERIFIED;
10793                         /* frequent check in generic code: box (struct), brtrue */
10794
10795                         /*
10796                          * Look for:
10797                          *
10798                          *   <push int/long ptr>
10799                          *   <push int/long>
10800                          *   box MyFlags
10801                          *   constrained. MyFlags
10802                          *   callvirt instace bool class [mscorlib] System.Enum::HasFlag (class [mscorlib] System.Enum)
10803                          *
10804                          * If we find this sequence and the operand types on box and constrained
10805                          * are equal, we can emit a specialized instruction sequence instead of
10806                          * the very slow HasFlag () call.
10807                          */
10808                         if ((cfg->opt & MONO_OPT_INTRINS) &&
10809                             /* Cheap checks first. */
10810                             ip + 5 + 6 + 5 < end &&
10811                             ip [5] == CEE_PREFIX1 &&
10812                             ip [6] == CEE_CONSTRAINED_ &&
10813                             ip [11] == CEE_CALLVIRT &&
10814                             ip_in_bb (cfg, cfg->cbb, ip + 5 + 6 + 5) &&
10815                             mono_class_is_enum (klass) &&
10816                             (enum_class = mini_get_class (method, read32 (ip + 7), generic_context)) &&
10817                             (has_flag = mini_get_method (cfg, method, read32 (ip + 12), NULL, generic_context)) &&
10818                             has_flag->klass == mono_defaults.enum_class &&
10819                             !strcmp (has_flag->name, "HasFlag") &&
10820                             has_flag->signature->hasthis &&
10821                             has_flag->signature->param_count == 1) {
10822                                 CHECK_TYPELOAD (enum_class);
10823
10824                                 if (enum_class == klass) {
10825                                         MonoInst *enum_this, *enum_flag;
10826
10827                                         ip += 5 + 6 + 5;
10828                                         --sp;
10829
10830                                         enum_this = sp [0];
10831                                         enum_flag = sp [1];
10832
10833                                         *sp++ = handle_enum_has_flag (cfg, klass, enum_this, enum_flag);
10834                                         break;
10835                                 }
10836                         }
10837
10838                         // FIXME: LLVM can't handle the inconsistent bb linking
10839                         if (!mono_class_is_nullable (klass) &&
10840                                 !mini_is_gsharedvt_klass (klass) &&
10841                                 ip + 5 < end && ip_in_bb (cfg, cfg->cbb, ip + 5) &&
10842                                 (ip [5] == CEE_BRTRUE || 
10843                                  ip [5] == CEE_BRTRUE_S ||
10844                                  ip [5] == CEE_BRFALSE ||
10845                                  ip [5] == CEE_BRFALSE_S)) {
10846                                 gboolean is_true = ip [5] == CEE_BRTRUE || ip [5] == CEE_BRTRUE_S;
10847                                 int dreg;
10848                                 MonoBasicBlock *true_bb, *false_bb;
10849
10850                                 ip += 5;
10851
10852                                 if (cfg->verbose_level > 3) {
10853                                         printf ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
10854                                         printf ("<box+brtrue opt>\n");
10855                                 }
10856
10857                                 switch (*ip) {
10858                                 case CEE_BRTRUE_S:
10859                                 case CEE_BRFALSE_S:
10860                                         CHECK_OPSIZE (2);
10861                                         ip++;
10862                                         target = ip + 1 + (signed char)(*ip);
10863                                         ip++;
10864                                         break;
10865                                 case CEE_BRTRUE:
10866                                 case CEE_BRFALSE:
10867                                         CHECK_OPSIZE (5);
10868                                         ip++;
10869                                         target = ip + 4 + (gint)(read32 (ip));
10870                                         ip += 4;
10871                                         break;
10872                                 default:
10873                                         g_assert_not_reached ();
10874                                 }
10875
10876                                 /* 
10877                                  * We need to link both bblocks, since it is needed for handling stack
10878                                  * arguments correctly (See test_0_box_brtrue_opt_regress_81102).
10879                                  * Branching to only one of them would lead to inconsistencies, so
10880                                  * generate an ICONST+BRTRUE, the branch opts will get rid of them.
10881                                  */
10882                                 GET_BBLOCK (cfg, true_bb, target);
10883                                 GET_BBLOCK (cfg, false_bb, ip);
10884
10885                                 mono_link_bblock (cfg, cfg->cbb, true_bb);
10886                                 mono_link_bblock (cfg, cfg->cbb, false_bb);
10887
10888                                 if (sp != stack_start) {
10889                                         handle_stack_args (cfg, stack_start, sp - stack_start);
10890                                         sp = stack_start;
10891                                         CHECK_UNVERIFIABLE (cfg);
10892                                 }
10893
10894                                 if (COMPILE_LLVM (cfg)) {
10895                                         dreg = alloc_ireg (cfg);
10896                                         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
10897                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, dreg, is_true ? 0 : 1);
10898
10899                                         MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, OP_IBEQ, true_bb, false_bb);
10900                                 } else {
10901                                         /* The JIT can't eliminate the iconst+compare */
10902                                         MONO_INST_NEW (cfg, ins, OP_BR);
10903                                         ins->inst_target_bb = is_true ? true_bb : false_bb;
10904                                         MONO_ADD_INS (cfg->cbb, ins);
10905                                 }
10906
10907                                 start_new_bblock = 1;
10908                                 break;
10909                         }
10910
10911                         *sp++ = handle_box (cfg, val, klass, context_used);
10912
10913                         CHECK_CFG_EXCEPTION;
10914                         ip += 5;
10915                         inline_costs += 1;
10916                         break;
10917                 }
10918                 case CEE_UNBOX: {
10919                         CHECK_STACK (1);
10920                         --sp;
10921                         CHECK_OPSIZE (5);
10922                         token = read32 (ip + 1);
10923                         klass = mini_get_class (method, token, generic_context);
10924                         CHECK_TYPELOAD (klass);
10925
10926                         mono_save_token_info (cfg, image, token, klass);
10927
10928                         context_used = mini_class_check_context_used (cfg, klass);
10929
10930                         if (mono_class_is_nullable (klass)) {
10931                                 MonoInst *val;
10932
10933                                 val = handle_unbox_nullable (cfg, *sp, klass, context_used);
10934                                 EMIT_NEW_VARLOADA (cfg, ins, get_vreg_to_inst (cfg, val->dreg), &val->klass->byval_arg);
10935
10936                                 *sp++= ins;
10937                         } else {
10938                                 ins = handle_unbox (cfg, klass, sp, context_used);
10939                                 *sp++ = ins;
10940                         }
10941                         ip += 5;
10942                         inline_costs += 2;
10943                         break;
10944                 }
10945                 case CEE_LDFLD:
10946                 case CEE_LDFLDA:
10947                 case CEE_STFLD:
10948                 case CEE_LDSFLD:
10949                 case CEE_LDSFLDA:
10950                 case CEE_STSFLD: {
10951                         MonoClassField *field;
10952 #ifndef DISABLE_REMOTING
10953                         int costs;
10954 #endif
10955                         guint foffset;
10956                         gboolean is_instance;
10957                         int op;
10958                         gpointer addr = NULL;
10959                         gboolean is_special_static;
10960                         MonoType *ftype;
10961                         MonoInst *store_val = NULL;
10962                         MonoInst *thread_ins;
10963
10964                         op = *ip;
10965                         is_instance = (op == CEE_LDFLD || op == CEE_LDFLDA || op == CEE_STFLD);
10966                         if (is_instance) {
10967                                 if (op == CEE_STFLD) {
10968                                         CHECK_STACK (2);
10969                                         sp -= 2;
10970                                         store_val = sp [1];
10971                                 } else {
10972                                         CHECK_STACK (1);
10973                                         --sp;
10974                                 }
10975                                 if (sp [0]->type == STACK_I4 || sp [0]->type == STACK_I8 || sp [0]->type == STACK_R8)
10976                                         UNVERIFIED;
10977                                 if (*ip != CEE_LDFLD && sp [0]->type == STACK_VTYPE)
10978                                         UNVERIFIED;
10979                         } else {
10980                                 if (op == CEE_STSFLD) {
10981                                         CHECK_STACK (1);
10982                                         sp--;
10983                                         store_val = sp [0];
10984                                 }
10985                         }
10986
10987                         CHECK_OPSIZE (5);
10988                         token = read32 (ip + 1);
10989                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
10990                                 field = mono_method_get_wrapper_data (method, token);
10991                                 klass = field->parent;
10992                         }
10993                         else {
10994                                 field = mono_field_from_token_checked (image, token, &klass, generic_context, &cfg->error);
10995                                 CHECK_CFG_ERROR;
10996                         }
10997                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
10998                                 FIELD_ACCESS_FAILURE (method, field);
10999                         mono_class_init (klass);
11000
11001                         /* if the class is Critical then transparent code cannot access it's fields */
11002                         if (!is_instance && mono_security_core_clr_enabled ())
11003                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
11004
11005                         /* XXX this is technically required but, so far (SL2), no [SecurityCritical] types (not many exists) have
11006                            any visible *instance* field  (in fact there's a single case for a static field in Marshal) XXX
11007                         if (mono_security_core_clr_enabled ())
11008                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
11009                         */
11010
11011                         ftype = mono_field_get_type (field);
11012
11013                         /*
11014                          * LDFLD etc. is usable on static fields as well, so convert those cases to
11015                          * the static case.
11016                          */
11017                         if (is_instance && ftype->attrs & FIELD_ATTRIBUTE_STATIC) {
11018                                 switch (op) {
11019                                 case CEE_LDFLD:
11020                                         op = CEE_LDSFLD;
11021                                         break;
11022                                 case CEE_STFLD:
11023                                         op = CEE_STSFLD;
11024                                         break;
11025                                 case CEE_LDFLDA:
11026                                         op = CEE_LDSFLDA;
11027                                         break;
11028                                 default:
11029                                         g_assert_not_reached ();
11030                                 }
11031                                 is_instance = FALSE;
11032                         }
11033
11034                         context_used = mini_class_check_context_used (cfg, klass);
11035
11036                         /* INSTANCE CASE */
11037
11038                         foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
11039                         if (op == CEE_STFLD) {
11040                                 if (target_type_is_incompatible (cfg, field->type, sp [1]))
11041                                         UNVERIFIED;
11042 #ifndef DISABLE_REMOTING
11043                                 if ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class) {
11044                                         MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type); 
11045                                         MonoInst *iargs [5];
11046
11047                                         GSHAREDVT_FAILURE (op);
11048
11049                                         iargs [0] = sp [0];
11050                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11051                                         EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
11052                                         EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : 
11053                                                     field->offset);
11054                                         iargs [4] = sp [1];
11055
11056                                         if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
11057                                                 costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), 
11058                                                                                            iargs, ip, cfg->real_offset, TRUE);
11059                                                 CHECK_CFG_EXCEPTION;
11060                                                 g_assert (costs > 0);
11061                                                       
11062                                                 cfg->real_offset += 5;
11063
11064                                                 inline_costs += costs;
11065                                         } else {
11066                                                 mono_emit_method_call (cfg, stfld_wrapper, iargs, NULL);
11067                                         }
11068                                 } else
11069 #endif
11070                                 {
11071                                         MonoInst *store;
11072
11073                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
11074
11075                                         if (mini_is_gsharedvt_klass (klass)) {
11076                                                 MonoInst *offset_ins;
11077
11078                                                 context_used = mini_class_check_context_used (cfg, klass);
11079
11080                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11081                                                 dreg = alloc_ireg_mp (cfg);
11082                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11083                                                 /* The decomposition will call mini_emit_stobj () which will emit a wbarrier if needed */
11084                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, dreg, 0, sp [1]->dreg);
11085                                         } else {
11086                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, sp [0]->dreg, foffset, sp [1]->dreg);
11087                                         }
11088                                         if (sp [0]->opcode != OP_LDADDR)
11089                                                 store->flags |= MONO_INST_FAULT;
11090
11091                                 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)) {
11092                                         /* insert call to write barrier */
11093                                         MonoInst *ptr;
11094                                         int dreg;
11095
11096                                         dreg = alloc_ireg_mp (cfg);
11097                                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
11098                                         emit_write_barrier (cfg, ptr, sp [1]);
11099                                 }
11100
11101                                         store->flags |= ins_flag;
11102                                 }
11103                                 ins_flag = 0;
11104                                 ip += 5;
11105                                 break;
11106                         }
11107
11108 #ifndef DISABLE_REMOTING
11109                         if (is_instance && ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class)) {
11110                                 MonoMethod *wrapper = (op == CEE_LDFLDA) ? mono_marshal_get_ldflda_wrapper (field->type) : mono_marshal_get_ldfld_wrapper (field->type); 
11111                                 MonoInst *iargs [4];
11112
11113                                 GSHAREDVT_FAILURE (op);
11114
11115                                 iargs [0] = sp [0];
11116                                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11117                                 EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
11118                                 EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
11119                                 if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
11120                                         costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), 
11121                                                                                    iargs, ip, cfg->real_offset, TRUE);
11122                                         CHECK_CFG_EXCEPTION;
11123                                         g_assert (costs > 0);
11124                                                       
11125                                         cfg->real_offset += 5;
11126
11127                                         *sp++ = iargs [0];
11128
11129                                         inline_costs += costs;
11130                                 } else {
11131                                         ins = mono_emit_method_call (cfg, wrapper, iargs, NULL);
11132                                         *sp++ = ins;
11133                                 }
11134                         } else 
11135 #endif
11136                         if (is_instance) {
11137                                 if (sp [0]->type == STACK_VTYPE) {
11138                                         MonoInst *var;
11139
11140                                         /* Have to compute the address of the variable */
11141
11142                                         var = get_vreg_to_inst (cfg, sp [0]->dreg);
11143                                         if (!var)
11144                                                 var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, sp [0]->dreg);
11145                                         else
11146                                                 g_assert (var->klass == klass);
11147                                         
11148                                         EMIT_NEW_VARLOADA (cfg, ins, var, &var->klass->byval_arg);
11149                                         sp [0] = ins;
11150                                 }
11151
11152                                 if (op == CEE_LDFLDA) {
11153                                         if (sp [0]->type == STACK_OBJ) {
11154                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
11155                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "NullReferenceException");
11156                                         }
11157
11158                                         dreg = alloc_ireg_mp (cfg);
11159
11160                                         if (mini_is_gsharedvt_klass (klass)) {
11161                                                 MonoInst *offset_ins;
11162
11163                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11164                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11165                                         } else {
11166                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
11167                                         }
11168                                         ins->klass = mono_class_from_mono_type (field->type);
11169                                         ins->type = STACK_MP;
11170                                         *sp++ = ins;
11171                                 } else {
11172                                         MonoInst *load;
11173
11174                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
11175
11176                                         if (mini_is_gsharedvt_klass (klass)) {
11177                                                 MonoInst *offset_ins;
11178
11179                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11180                                                 dreg = alloc_ireg_mp (cfg);
11181                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11182                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, dreg, 0);
11183                                         } else {
11184                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, sp [0]->dreg, foffset);
11185                                         }
11186                                         load->flags |= ins_flag;
11187                                         if (sp [0]->opcode != OP_LDADDR)
11188                                                 load->flags |= MONO_INST_FAULT;
11189                                         *sp++ = load;
11190                                 }
11191                         }
11192
11193                         if (is_instance) {
11194                                 ins_flag = 0;
11195                                 ip += 5;
11196                                 break;
11197                         }
11198
11199                         /* STATIC CASE */
11200                         context_used = mini_class_check_context_used (cfg, klass);
11201
11202                         if (ftype->attrs & FIELD_ATTRIBUTE_LITERAL)
11203                                 UNVERIFIED;
11204
11205                         /* The special_static_fields field is init'd in mono_class_vtable, so it needs
11206                          * to be called here.
11207                          */
11208                         if (!context_used && !(cfg->opt & MONO_OPT_SHARED)) {
11209                                 mono_class_vtable (cfg->domain, klass);
11210                                 CHECK_TYPELOAD (klass);
11211                         }
11212                         mono_domain_lock (cfg->domain);
11213                         if (cfg->domain->special_static_fields)
11214                                 addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
11215                         mono_domain_unlock (cfg->domain);
11216
11217                         is_special_static = mono_class_field_is_special_static (field);
11218
11219                         if (is_special_static && ((gsize)addr & 0x80000000) == 0)
11220                                 thread_ins = mono_get_thread_intrinsic (cfg);
11221                         else
11222                                 thread_ins = NULL;
11223
11224                         /* Generate IR to compute the field address */
11225                         if (is_special_static && ((gsize)addr & 0x80000000) == 0 && thread_ins && !(cfg->opt & MONO_OPT_SHARED) && !context_used) {
11226                                 /*
11227                                  * Fast access to TLS data
11228                                  * Inline version of get_thread_static_data () in
11229                                  * threads.c.
11230                                  */
11231                                 guint32 offset;
11232                                 int idx, static_data_reg, array_reg, dreg;
11233
11234                                 GSHAREDVT_FAILURE (op);
11235
11236                                 MONO_ADD_INS (cfg->cbb, thread_ins);
11237                                 static_data_reg = alloc_ireg (cfg);
11238                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, MONO_STRUCT_OFFSET (MonoInternalThread, static_data));
11239
11240                                 if (cfg->compile_aot) {
11241                                         int offset_reg, offset2_reg, idx_reg;
11242
11243                                         /* For TLS variables, this will return the TLS offset */
11244                                         EMIT_NEW_SFLDACONST (cfg, ins, field);
11245                                         offset_reg = ins->dreg;
11246                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset_reg, offset_reg, 0x7fffffff);
11247                                         idx_reg = alloc_ireg (cfg);
11248                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, idx_reg, offset_reg, 0x3f);
11249                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
11250                                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
11251                                         array_reg = alloc_ireg (cfg);
11252                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
11253                                         offset2_reg = alloc_ireg (cfg);
11254                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, offset2_reg, offset_reg, 6);
11255                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset2_reg, 0x1ffffff);
11256                                         dreg = alloc_ireg (cfg);
11257                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, array_reg, offset2_reg);
11258                                 } else {
11259                                         offset = (gsize)addr & 0x7fffffff;
11260                                         idx = offset & 0x3f;
11261
11262                                         array_reg = alloc_ireg (cfg);
11263                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, idx * sizeof (gpointer));
11264                                         dreg = alloc_ireg (cfg);
11265                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_ADD_IMM, dreg, array_reg, ((offset >> 6) & 0x1ffffff));
11266                                 }
11267                         } else if ((cfg->opt & MONO_OPT_SHARED) ||
11268                                         (cfg->compile_aot && is_special_static) ||
11269                                         (context_used && is_special_static)) {
11270                                 MonoInst *iargs [2];
11271
11272                                 g_assert (field->parent);
11273                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11274                                 if (context_used) {
11275                                         iargs [1] = emit_get_rgctx_field (cfg, context_used,
11276                                                 field, MONO_RGCTX_INFO_CLASS_FIELD);
11277                                 } else {
11278                                         EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
11279                                 }
11280                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
11281                         } else if (context_used) {
11282                                 MonoInst *static_data;
11283
11284                                 /*
11285                                 g_print ("sharing static field access in %s.%s.%s - depth %d offset %d\n",
11286                                         method->klass->name_space, method->klass->name, method->name,
11287                                         depth, field->offset);
11288                                 */
11289
11290                                 if (mono_class_needs_cctor_run (klass, method))
11291                                         emit_class_init (cfg, klass);
11292
11293                                 /*
11294                                  * The pointer we're computing here is
11295                                  *
11296                                  *   super_info.static_data + field->offset
11297                                  */
11298                                 static_data = emit_get_rgctx_klass (cfg, context_used,
11299                                         klass, MONO_RGCTX_INFO_STATIC_DATA);
11300
11301                                 if (mini_is_gsharedvt_klass (klass)) {
11302                                         MonoInst *offset_ins;
11303
11304                                         offset_ins = emit_get_rgctx_field (cfg, context_used, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11305                                         dreg = alloc_ireg_mp (cfg);
11306                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, static_data->dreg, offset_ins->dreg);
11307                                 } else if (field->offset == 0) {
11308                                         ins = static_data;
11309                                 } else {
11310                                         int addr_reg = mono_alloc_preg (cfg);
11311                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, addr_reg, static_data->dreg, field->offset);
11312                                 }
11313                                 } else if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
11314                                 MonoInst *iargs [2];
11315
11316                                 g_assert (field->parent);
11317                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11318                                 EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
11319                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
11320                         } else {
11321                                 MonoVTable *vtable = NULL;
11322
11323                                 if (!cfg->compile_aot)
11324                                         vtable = mono_class_vtable (cfg->domain, klass);
11325                                 CHECK_TYPELOAD (klass);
11326
11327                                 if (!addr) {
11328                                         if (mini_field_access_needs_cctor_run (cfg, method, klass, vtable)) {
11329                                                 if (!(g_slist_find (class_inits, klass))) {
11330                                                         emit_class_init (cfg, klass);
11331                                                         if (cfg->verbose_level > 2)
11332                                                                 printf ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, mono_field_get_name (field));
11333                                                         class_inits = g_slist_prepend (class_inits, klass);
11334                                                 }
11335                                         } else {
11336                                                 if (cfg->run_cctors) {
11337                                                         MonoException *ex;
11338                                                         /* This makes so that inline cannot trigger */
11339                                                         /* .cctors: too many apps depend on them */
11340                                                         /* running with a specific order... */
11341                                                         g_assert (vtable);
11342                                                         if (! vtable->initialized)
11343                                                                 INLINE_FAILURE ("class init");
11344                                                         ex = mono_runtime_class_init_full (vtable, FALSE);
11345                                                         if (ex) {
11346                                                                 set_exception_object (cfg, ex);
11347                                                                 goto exception_exit;
11348                                                         }
11349                                                 }
11350                                         }
11351                                         if (cfg->compile_aot)
11352                                                 EMIT_NEW_SFLDACONST (cfg, ins, field);
11353                                         else {
11354                                                 g_assert (vtable);
11355                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11356                                                 g_assert (addr);
11357                                                 EMIT_NEW_PCONST (cfg, ins, addr);
11358                                         }
11359                                 } else {
11360                                         MonoInst *iargs [1];
11361                                         EMIT_NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
11362                                         ins = mono_emit_jit_icall (cfg, mono_get_special_static_data, iargs);
11363                                 }
11364                         }
11365
11366                         /* Generate IR to do the actual load/store operation */
11367
11368                         if ((op == CEE_STFLD || op == CEE_STSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11369                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11370                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11371                         }
11372
11373                         if (op == CEE_LDSFLDA) {
11374                                 ins->klass = mono_class_from_mono_type (ftype);
11375                                 ins->type = STACK_PTR;
11376                                 *sp++ = ins;
11377                         } else if (op == CEE_STSFLD) {
11378                                 MonoInst *store;
11379
11380                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, ftype, ins->dreg, 0, store_val->dreg);
11381                                 store->flags |= ins_flag;
11382                         } else {
11383                                 gboolean is_const = FALSE;
11384                                 MonoVTable *vtable = NULL;
11385                                 gpointer addr = NULL;
11386
11387                                 if (!context_used) {
11388                                         vtable = mono_class_vtable (cfg->domain, klass);
11389                                         CHECK_TYPELOAD (klass);
11390                                 }
11391                                 if ((ftype->attrs & FIELD_ATTRIBUTE_INIT_ONLY) && (((addr = mono_aot_readonly_field_override (field)) != NULL) ||
11392                                                 (!context_used && !((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && vtable->initialized))) {
11393                                         int ro_type = ftype->type;
11394                                         if (!addr)
11395                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11396                                         if (ro_type == MONO_TYPE_VALUETYPE && ftype->data.klass->enumtype) {
11397                                                 ro_type = mono_class_enum_basetype (ftype->data.klass)->type;
11398                                         }
11399
11400                                         GSHAREDVT_FAILURE (op);
11401
11402                                         /* printf ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, mono_field_get_name (field));*/
11403                                         is_const = TRUE;
11404                                         switch (ro_type) {
11405                                         case MONO_TYPE_BOOLEAN:
11406                                         case MONO_TYPE_U1:
11407                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint8 *)addr));
11408                                                 sp++;
11409                                                 break;
11410                                         case MONO_TYPE_I1:
11411                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint8 *)addr));
11412                                                 sp++;
11413                                                 break;                                          
11414                                         case MONO_TYPE_CHAR:
11415                                         case MONO_TYPE_U2:
11416                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint16 *)addr));
11417                                                 sp++;
11418                                                 break;
11419                                         case MONO_TYPE_I2:
11420                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint16 *)addr));
11421                                                 sp++;
11422                                                 break;
11423                                                 break;
11424                                         case MONO_TYPE_I4:
11425                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint32 *)addr));
11426                                                 sp++;
11427                                                 break;                                          
11428                                         case MONO_TYPE_U4:
11429                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint32 *)addr));
11430                                                 sp++;
11431                                                 break;
11432                                         case MONO_TYPE_I:
11433                                         case MONO_TYPE_U:
11434                                         case MONO_TYPE_PTR:
11435                                         case MONO_TYPE_FNPTR:
11436                                                 EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11437                                                 type_to_eval_stack_type ((cfg), field->type, *sp);
11438                                                 sp++;
11439                                                 break;
11440                                         case MONO_TYPE_STRING:
11441                                         case MONO_TYPE_OBJECT:
11442                                         case MONO_TYPE_CLASS:
11443                                         case MONO_TYPE_SZARRAY:
11444                                         case MONO_TYPE_ARRAY:
11445                                                 if (!mono_gc_is_moving ()) {
11446                                                         EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11447                                                         type_to_eval_stack_type ((cfg), field->type, *sp);
11448                                                         sp++;
11449                                                 } else {
11450                                                         is_const = FALSE;
11451                                                 }
11452                                                 break;
11453                                         case MONO_TYPE_I8:
11454                                         case MONO_TYPE_U8:
11455                                                 EMIT_NEW_I8CONST (cfg, *sp, *((gint64 *)addr));
11456                                                 sp++;
11457                                                 break;
11458                                         case MONO_TYPE_R4:
11459                                         case MONO_TYPE_R8:
11460                                         case MONO_TYPE_VALUETYPE:
11461                                         default:
11462                                                 is_const = FALSE;
11463                                                 break;
11464                                         }
11465                                 }
11466
11467                                 if (!is_const) {
11468                                         MonoInst *load;
11469
11470                                         CHECK_STACK_OVF (1);
11471
11472                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, ins->dreg, 0);
11473                                         load->flags |= ins_flag;
11474                                         ins_flag = 0;
11475                                         *sp++ = load;
11476                                 }
11477                         }
11478
11479                         if ((op == CEE_LDFLD || op == CEE_LDSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11480                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
11481                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
11482                         }
11483
11484                         ins_flag = 0;
11485                         ip += 5;
11486                         break;
11487                 }
11488                 case CEE_STOBJ:
11489                         CHECK_STACK (2);
11490                         sp -= 2;
11491                         CHECK_OPSIZE (5);
11492                         token = read32 (ip + 1);
11493                         klass = mini_get_class (method, token, generic_context);
11494                         CHECK_TYPELOAD (klass);
11495                         if (ins_flag & MONO_INST_VOLATILE) {
11496                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11497                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11498                         }
11499                         /* FIXME: should check item at sp [1] is compatible with the type of the store. */
11500                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0, sp [1]->dreg);
11501                         ins->flags |= ins_flag;
11502                         if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER &&
11503                                         generic_class_is_reference_type (cfg, klass)) {
11504                                 /* insert call to write barrier */
11505                                 emit_write_barrier (cfg, sp [0], sp [1]);
11506                         }
11507                         ins_flag = 0;
11508                         ip += 5;
11509                         inline_costs += 1;
11510                         break;
11511
11512                         /*
11513                          * Array opcodes
11514                          */
11515                 case CEE_NEWARR: {
11516                         MonoInst *len_ins;
11517                         const char *data_ptr;
11518                         int data_size = 0;
11519                         guint32 field_token;
11520
11521                         CHECK_STACK (1);
11522                         --sp;
11523
11524                         CHECK_OPSIZE (5);
11525                         token = read32 (ip + 1);
11526
11527                         klass = mini_get_class (method, token, generic_context);
11528                         CHECK_TYPELOAD (klass);
11529
11530                         context_used = mini_class_check_context_used (cfg, klass);
11531
11532                         if (sp [0]->type == STACK_I8 || (SIZEOF_VOID_P == 8 && sp [0]->type == STACK_PTR)) {
11533                                 MONO_INST_NEW (cfg, ins, OP_LCONV_TO_OVF_U4);
11534                                 ins->sreg1 = sp [0]->dreg;
11535                                 ins->type = STACK_I4;
11536                                 ins->dreg = alloc_ireg (cfg);
11537                                 MONO_ADD_INS (cfg->cbb, ins);
11538                                 *sp = mono_decompose_opcode (cfg, ins);
11539                         }
11540
11541                         if (context_used) {
11542                                 MonoInst *args [3];
11543                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11544                                 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
11545
11546                                 /* FIXME: Use OP_NEWARR and decompose later to help abcrem */
11547
11548                                 /* vtable */
11549                                 args [0] = emit_get_rgctx_klass (cfg, context_used,
11550                                         array_class, MONO_RGCTX_INFO_VTABLE);
11551                                 /* array len */
11552                                 args [1] = sp [0];
11553
11554                                 if (managed_alloc)
11555                                         ins = mono_emit_method_call (cfg, managed_alloc, args, NULL);
11556                                 else
11557                                         ins = mono_emit_jit_icall (cfg, mono_array_new_specific, args);
11558                         } else {
11559                                 if (cfg->opt & MONO_OPT_SHARED) {
11560                                         /* Decompose now to avoid problems with references to the domainvar */
11561                                         MonoInst *iargs [3];
11562
11563                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11564                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11565                                         iargs [2] = sp [0];
11566
11567                                         ins = mono_emit_jit_icall (cfg, mono_array_new, iargs);
11568                                 } else {
11569                                         /* Decompose later since it is needed by abcrem */
11570                                         MonoClass *array_type = mono_array_class_get (klass, 1);
11571                                         mono_class_vtable (cfg->domain, array_type);
11572                                         CHECK_TYPELOAD (array_type);
11573
11574                                         MONO_INST_NEW (cfg, ins, OP_NEWARR);
11575                                         ins->dreg = alloc_ireg_ref (cfg);
11576                                         ins->sreg1 = sp [0]->dreg;
11577                                         ins->inst_newa_class = klass;
11578                                         ins->type = STACK_OBJ;
11579                                         ins->klass = array_type;
11580                                         MONO_ADD_INS (cfg->cbb, ins);
11581                                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11582                                         cfg->cbb->has_array_access = TRUE;
11583
11584                                         /* Needed so mono_emit_load_get_addr () gets called */
11585                                         mono_get_got_var (cfg);
11586                                 }
11587                         }
11588
11589                         len_ins = sp [0];
11590                         ip += 5;
11591                         *sp++ = ins;
11592                         inline_costs += 1;
11593
11594                         /* 
11595                          * we inline/optimize the initialization sequence if possible.
11596                          * we should also allocate the array as not cleared, since we spend as much time clearing to 0 as initializing
11597                          * for small sizes open code the memcpy
11598                          * ensure the rva field is big enough
11599                          */
11600                         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))) {
11601                                 MonoMethod *memcpy_method = get_memcpy_method ();
11602                                 MonoInst *iargs [3];
11603                                 int add_reg = alloc_ireg_mp (cfg);
11604
11605                                 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, add_reg, ins->dreg, MONO_STRUCT_OFFSET (MonoArray, vector));
11606                                 if (cfg->compile_aot) {
11607                                         EMIT_NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(field_token), STACK_PTR, NULL);
11608                                 } else {
11609                                         EMIT_NEW_PCONST (cfg, iargs [1], (char*)data_ptr);
11610                                 }
11611                                 EMIT_NEW_ICONST (cfg, iargs [2], data_size);
11612                                 mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
11613                                 ip += 11;
11614                         }
11615
11616                         break;
11617                 }
11618                 case CEE_LDLEN:
11619                         CHECK_STACK (1);
11620                         --sp;
11621                         if (sp [0]->type != STACK_OBJ)
11622                                 UNVERIFIED;
11623
11624                         MONO_INST_NEW (cfg, ins, OP_LDLEN);
11625                         ins->dreg = alloc_preg (cfg);
11626                         ins->sreg1 = sp [0]->dreg;
11627                         ins->type = STACK_I4;
11628                         /* This flag will be inherited by the decomposition */
11629                         ins->flags |= MONO_INST_FAULT;
11630                         MONO_ADD_INS (cfg->cbb, ins);
11631                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11632                         cfg->cbb->has_array_access = TRUE;
11633                         ip ++;
11634                         *sp++ = ins;
11635                         break;
11636                 case CEE_LDELEMA:
11637                         CHECK_STACK (2);
11638                         sp -= 2;
11639                         CHECK_OPSIZE (5);
11640                         if (sp [0]->type != STACK_OBJ)
11641                                 UNVERIFIED;
11642
11643                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11644
11645                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11646                         CHECK_TYPELOAD (klass);
11647                         /* we need to make sure that this array is exactly the type it needs
11648                          * to be for correctness. the wrappers are lax with their usage
11649                          * so we need to ignore them here
11650                          */
11651                         if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE && !readonly) {
11652                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11653                                 mini_emit_check_array_type (cfg, sp [0], array_class);
11654                                 CHECK_TYPELOAD (array_class);
11655                         }
11656
11657                         readonly = FALSE;
11658                         ins = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11659                         *sp++ = ins;
11660                         ip += 5;
11661                         break;
11662                 case CEE_LDELEM:
11663                 case CEE_LDELEM_I1:
11664                 case CEE_LDELEM_U1:
11665                 case CEE_LDELEM_I2:
11666                 case CEE_LDELEM_U2:
11667                 case CEE_LDELEM_I4:
11668                 case CEE_LDELEM_U4:
11669                 case CEE_LDELEM_I8:
11670                 case CEE_LDELEM_I:
11671                 case CEE_LDELEM_R4:
11672                 case CEE_LDELEM_R8:
11673                 case CEE_LDELEM_REF: {
11674                         MonoInst *addr;
11675
11676                         CHECK_STACK (2);
11677                         sp -= 2;
11678
11679                         if (*ip == CEE_LDELEM) {
11680                                 CHECK_OPSIZE (5);
11681                                 token = read32 (ip + 1);
11682                                 klass = mini_get_class (method, token, generic_context);
11683                                 CHECK_TYPELOAD (klass);
11684                                 mono_class_init (klass);
11685                         }
11686                         else
11687                                 klass = array_access_to_klass (*ip);
11688
11689                         if (sp [0]->type != STACK_OBJ)
11690                                 UNVERIFIED;
11691
11692                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11693
11694                         if (mini_is_gsharedvt_variable_klass (klass)) {
11695                                 // FIXME-VT: OP_ICONST optimization
11696                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11697                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11698                                 ins->opcode = OP_LOADV_MEMBASE;
11699                         } else if (sp [1]->opcode == OP_ICONST) {
11700                                 int array_reg = sp [0]->dreg;
11701                                 int index_reg = sp [1]->dreg;
11702                                 int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
11703
11704                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
11705                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset);
11706                         } else {
11707                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11708                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11709                         }
11710                         *sp++ = ins;
11711                         if (*ip == CEE_LDELEM)
11712                                 ip += 5;
11713                         else
11714                                 ++ip;
11715                         break;
11716                 }
11717                 case CEE_STELEM_I:
11718                 case CEE_STELEM_I1:
11719                 case CEE_STELEM_I2:
11720                 case CEE_STELEM_I4:
11721                 case CEE_STELEM_I8:
11722                 case CEE_STELEM_R4:
11723                 case CEE_STELEM_R8:
11724                 case CEE_STELEM_REF:
11725                 case CEE_STELEM: {
11726                         CHECK_STACK (3);
11727                         sp -= 3;
11728
11729                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11730
11731                         if (*ip == CEE_STELEM) {
11732                                 CHECK_OPSIZE (5);
11733                                 token = read32 (ip + 1);
11734                                 klass = mini_get_class (method, token, generic_context);
11735                                 CHECK_TYPELOAD (klass);
11736                                 mono_class_init (klass);
11737                         }
11738                         else
11739                                 klass = array_access_to_klass (*ip);
11740
11741                         if (sp [0]->type != STACK_OBJ)
11742                                 UNVERIFIED;
11743
11744                         emit_array_store (cfg, klass, sp, TRUE);
11745
11746                         if (*ip == CEE_STELEM)
11747                                 ip += 5;
11748                         else
11749                                 ++ip;
11750                         inline_costs += 1;
11751                         break;
11752                 }
11753                 case CEE_CKFINITE: {
11754                         CHECK_STACK (1);
11755                         --sp;
11756
11757                         if (cfg->llvm_only) {
11758                                 MonoInst *iargs [1];
11759
11760                                 iargs [0] = sp [0];
11761                                 *sp++ = mono_emit_jit_icall (cfg, mono_ckfinite, iargs);
11762                         } else  {
11763                                 MONO_INST_NEW (cfg, ins, OP_CKFINITE);
11764                                 ins->sreg1 = sp [0]->dreg;
11765                                 ins->dreg = alloc_freg (cfg);
11766                                 ins->type = STACK_R8;
11767                                 MONO_ADD_INS (cfg->cbb, ins);
11768
11769                                 *sp++ = mono_decompose_opcode (cfg, ins);
11770                         }
11771
11772                         ++ip;
11773                         break;
11774                 }
11775                 case CEE_REFANYVAL: {
11776                         MonoInst *src_var, *src;
11777
11778                         int klass_reg = alloc_preg (cfg);
11779                         int dreg = alloc_preg (cfg);
11780
11781                         GSHAREDVT_FAILURE (*ip);
11782
11783                         CHECK_STACK (1);
11784                         MONO_INST_NEW (cfg, ins, *ip);
11785                         --sp;
11786                         CHECK_OPSIZE (5);
11787                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11788                         CHECK_TYPELOAD (klass);
11789
11790                         context_used = mini_class_check_context_used (cfg, klass);
11791
11792                         // FIXME:
11793                         src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
11794                         if (!src_var)
11795                                 src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
11796                         EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
11797                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass));
11798
11799                         if (context_used) {
11800                                 MonoInst *klass_ins;
11801
11802                                 klass_ins = emit_get_rgctx_klass (cfg, context_used,
11803                                                 klass, MONO_RGCTX_INFO_KLASS);
11804
11805                                 // FIXME:
11806                                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_ins->dreg);
11807                                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
11808                         } else {
11809                                 mini_emit_class_check (cfg, klass_reg, klass);
11810                         }
11811                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value));
11812                         ins->type = STACK_MP;
11813                         ins->klass = klass;
11814                         *sp++ = ins;
11815                         ip += 5;
11816                         break;
11817                 }
11818                 case CEE_MKREFANY: {
11819                         MonoInst *loc, *addr;
11820
11821                         GSHAREDVT_FAILURE (*ip);
11822
11823                         CHECK_STACK (1);
11824                         MONO_INST_NEW (cfg, ins, *ip);
11825                         --sp;
11826                         CHECK_OPSIZE (5);
11827                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11828                         CHECK_TYPELOAD (klass);
11829
11830                         context_used = mini_class_check_context_used (cfg, klass);
11831
11832                         loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
11833                         EMIT_NEW_TEMPLOADA (cfg, addr, loc->inst_c0);
11834
11835                         if (context_used) {
11836                                 MonoInst *const_ins;
11837                                 int type_reg = alloc_preg (cfg);
11838
11839                                 const_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
11840                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_ins->dreg);
11841                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_ins->dreg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
11842                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
11843                         } else if (cfg->compile_aot) {
11844                                 int const_reg = alloc_preg (cfg);
11845                                 int type_reg = alloc_preg (cfg);
11846
11847                                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
11848                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_reg);
11849                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_reg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
11850                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
11851                         } else {
11852                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), &klass->byval_arg);
11853                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), klass);
11854                         }
11855                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value), sp [0]->dreg);
11856
11857                         EMIT_NEW_TEMPLOAD (cfg, ins, loc->inst_c0);
11858                         ins->type = STACK_VTYPE;
11859                         ins->klass = mono_defaults.typed_reference_class;
11860                         *sp++ = ins;
11861                         ip += 5;
11862                         break;
11863                 }
11864                 case CEE_LDTOKEN: {
11865                         gpointer handle;
11866                         MonoClass *handle_class;
11867
11868                         CHECK_STACK_OVF (1);
11869
11870                         CHECK_OPSIZE (5);
11871                         n = read32 (ip + 1);
11872
11873                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD ||
11874                                         method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
11875                                 handle = mono_method_get_wrapper_data (method, n);
11876                                 handle_class = mono_method_get_wrapper_data (method, n + 1);
11877                                 if (handle_class == mono_defaults.typehandle_class)
11878                                         handle = &((MonoClass*)handle)->byval_arg;
11879                         }
11880                         else {
11881                                 handle = mono_ldtoken_checked (image, n, &handle_class, generic_context, &cfg->error);
11882                                 CHECK_CFG_ERROR;
11883                         }
11884                         if (!handle)
11885                                 LOAD_ERROR;
11886                         mono_class_init (handle_class);
11887                         if (cfg->gshared) {
11888                                 if (mono_metadata_token_table (n) == MONO_TABLE_TYPEDEF ||
11889                                                 mono_metadata_token_table (n) == MONO_TABLE_TYPEREF) {
11890                                         /* This case handles ldtoken
11891                                            of an open type, like for
11892                                            typeof(Gen<>). */
11893                                         context_used = 0;
11894                                 } else if (handle_class == mono_defaults.typehandle_class) {
11895                                         context_used = mini_class_check_context_used (cfg, mono_class_from_mono_type (handle));
11896                                 } else if (handle_class == mono_defaults.fieldhandle_class)
11897                                         context_used = mini_class_check_context_used (cfg, ((MonoClassField*)handle)->parent);
11898                                 else if (handle_class == mono_defaults.methodhandle_class)
11899                                         context_used = mini_method_check_context_used (cfg, handle);
11900                                 else
11901                                         g_assert_not_reached ();
11902                         }
11903
11904                         if ((cfg->opt & MONO_OPT_SHARED) &&
11905                                         method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD &&
11906                                         method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED) {
11907                                 MonoInst *addr, *vtvar, *iargs [3];
11908                                 int method_context_used;
11909
11910                                 method_context_used = mini_method_check_context_used (cfg, method);
11911
11912                                 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL); 
11913
11914                                 EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
11915                                 EMIT_NEW_ICONST (cfg, iargs [1], n);
11916                                 if (method_context_used) {
11917                                         iargs [2] = emit_get_rgctx_method (cfg, method_context_used,
11918                                                 method, MONO_RGCTX_INFO_METHOD);
11919                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper_generic_shared, iargs);
11920                                 } else {
11921                                         EMIT_NEW_PCONST (cfg, iargs [2], generic_context);
11922                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper, iargs);
11923                                 }
11924                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
11925
11926                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
11927
11928                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
11929                         } else {
11930                                 if ((ip + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 5) && 
11931                                         ((ip [5] == CEE_CALL) || (ip [5] == CEE_CALLVIRT)) && 
11932                                         (cmethod = mini_get_method (cfg, method, read32 (ip + 6), NULL, generic_context)) &&
11933                                         (cmethod->klass == mono_defaults.systemtype_class) &&
11934                                         (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
11935                                         MonoClass *tclass = mono_class_from_mono_type (handle);
11936
11937                                         mono_class_init (tclass);
11938                                         if (context_used) {
11939                                                 ins = emit_get_rgctx_klass (cfg, context_used,
11940                                                         tclass, MONO_RGCTX_INFO_REFLECTION_TYPE);
11941                                         } else if (cfg->compile_aot) {
11942                                                 if (method->wrapper_type) {
11943                                                         mono_error_init (&error); //got to do it since there are multiple conditionals below
11944                                                         if (mono_class_get_checked (tclass->image, tclass->type_token, &error) == tclass && !generic_context) {
11945                                                                 /* Special case for static synchronized wrappers */
11946                                                                 EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, tclass->image, tclass->type_token, generic_context);
11947                                                         } else {
11948                                                                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
11949                                                                 /* FIXME: n is not a normal token */
11950                                                                 DISABLE_AOT (cfg);
11951                                                                 EMIT_NEW_PCONST (cfg, ins, NULL);
11952                                                         }
11953                                                 } else {
11954                                                         EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n, generic_context);
11955                                                 }
11956                                         } else {
11957                                                 EMIT_NEW_PCONST (cfg, ins, mono_type_get_object (cfg->domain, handle));
11958                                         }
11959                                         ins->type = STACK_OBJ;
11960                                         ins->klass = cmethod->klass;
11961                                         ip += 5;
11962                                 } else {
11963                                         MonoInst *addr, *vtvar;
11964
11965                                         vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
11966
11967                                         if (context_used) {
11968                                                 if (handle_class == mono_defaults.typehandle_class) {
11969                                                         ins = emit_get_rgctx_klass (cfg, context_used,
11970                                                                         mono_class_from_mono_type (handle),
11971                                                                         MONO_RGCTX_INFO_TYPE);
11972                                                 } else if (handle_class == mono_defaults.methodhandle_class) {
11973                                                         ins = emit_get_rgctx_method (cfg, context_used,
11974                                                                         handle, MONO_RGCTX_INFO_METHOD);
11975                                                 } else if (handle_class == mono_defaults.fieldhandle_class) {
11976                                                         ins = emit_get_rgctx_field (cfg, context_used,
11977                                                                         handle, MONO_RGCTX_INFO_CLASS_FIELD);
11978                                                 } else {
11979                                                         g_assert_not_reached ();
11980                                                 }
11981                                         } else if (cfg->compile_aot) {
11982                                                 EMIT_NEW_LDTOKENCONST (cfg, ins, image, n, generic_context);
11983                                         } else {
11984                                                 EMIT_NEW_PCONST (cfg, ins, handle);
11985                                         }
11986                                         EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
11987                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
11988                                         EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
11989                                 }
11990                         }
11991
11992                         *sp++ = ins;
11993                         ip += 5;
11994                         break;
11995                 }
11996                 case CEE_THROW:
11997                         CHECK_STACK (1);
11998                         MONO_INST_NEW (cfg, ins, OP_THROW);
11999                         --sp;
12000                         ins->sreg1 = sp [0]->dreg;
12001                         ip++;
12002                         cfg->cbb->out_of_line = TRUE;
12003                         MONO_ADD_INS (cfg->cbb, ins);
12004                         MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
12005                         MONO_ADD_INS (cfg->cbb, ins);
12006                         sp = stack_start;
12007                         
12008                         link_bblock (cfg, cfg->cbb, end_bblock);
12009                         start_new_bblock = 1;
12010                         /* This can complicate code generation for llvm since the return value might not be defined */
12011                         if (COMPILE_LLVM (cfg))
12012                                 INLINE_FAILURE ("throw");
12013                         break;
12014                 case CEE_ENDFINALLY:
12015                         /* mono_save_seq_point_info () depends on this */
12016                         if (sp != stack_start)
12017                                 emit_seq_point (cfg, method, ip, FALSE, FALSE);
12018                         MONO_INST_NEW (cfg, ins, OP_ENDFINALLY);
12019                         MONO_ADD_INS (cfg->cbb, ins);
12020                         ip++;
12021                         start_new_bblock = 1;
12022
12023                         /*
12024                          * Control will leave the method so empty the stack, otherwise
12025                          * the next basic block will start with a nonempty stack.
12026                          */
12027                         while (sp != stack_start) {
12028                                 sp--;
12029                         }
12030                         break;
12031                 case CEE_LEAVE:
12032                 case CEE_LEAVE_S: {
12033                         GList *handlers;
12034
12035                         if (*ip == CEE_LEAVE) {
12036                                 CHECK_OPSIZE (5);
12037                                 target = ip + 5 + (gint32)read32(ip + 1);
12038                         } else {
12039                                 CHECK_OPSIZE (2);
12040                                 target = ip + 2 + (signed char)(ip [1]);
12041                         }
12042
12043                         /* empty the stack */
12044                         while (sp != stack_start) {
12045                                 sp--;
12046                         }
12047
12048                         /* 
12049                          * If this leave statement is in a catch block, check for a
12050                          * pending exception, and rethrow it if necessary.
12051                          * We avoid doing this in runtime invoke wrappers, since those are called
12052                          * by native code which excepts the wrapper to catch all exceptions.
12053                          */
12054                         for (i = 0; i < header->num_clauses; ++i) {
12055                                 MonoExceptionClause *clause = &header->clauses [i];
12056
12057                                 /* 
12058                                  * Use <= in the final comparison to handle clauses with multiple
12059                                  * leave statements, like in bug #78024.
12060                                  * The ordering of the exception clauses guarantees that we find the
12061                                  * innermost clause.
12062                                  */
12063                                 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) {
12064                                         MonoInst *exc_ins;
12065                                         MonoBasicBlock *dont_throw;
12066
12067                                         /*
12068                                           MonoInst *load;
12069
12070                                           NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, clause->handler_offset)->inst_c0);
12071                                         */
12072
12073                                         exc_ins = mono_emit_jit_icall (cfg, mono_thread_get_undeniable_exception, NULL);
12074
12075                                         NEW_BBLOCK (cfg, dont_throw);
12076
12077                                         /*
12078                                          * Currently, we always rethrow the abort exception, despite the 
12079                                          * fact that this is not correct. See thread6.cs for an example. 
12080                                          * But propagating the abort exception is more important than 
12081                                          * getting the sematics right.
12082                                          */
12083                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, exc_ins->dreg, 0);
12084                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, dont_throw);
12085                                         MONO_EMIT_NEW_UNALU (cfg, OP_THROW, -1, exc_ins->dreg);
12086
12087                                         MONO_START_BB (cfg, dont_throw);
12088                                 }
12089                         }
12090
12091 #ifdef ENABLE_LLVM
12092                         cfg->cbb->try_end = (intptr_t)(ip - header->code);
12093 #endif
12094
12095                         if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
12096                                 GList *tmp;
12097                                 MonoExceptionClause *clause;
12098
12099                                 for (tmp = handlers; tmp; tmp = tmp->next) {
12100                                         clause = tmp->data;
12101                                         tblock = cfg->cil_offset_to_bb [clause->handler_offset];
12102                                         g_assert (tblock);
12103                                         link_bblock (cfg, cfg->cbb, tblock);
12104                                         MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
12105                                         ins->inst_target_bb = tblock;
12106                                         ins->inst_eh_block = clause;
12107                                         MONO_ADD_INS (cfg->cbb, ins);
12108                                         cfg->cbb->has_call_handler = 1;
12109                                         if (COMPILE_LLVM (cfg)) {
12110                                                 MonoBasicBlock *target_bb;
12111
12112                                                 /* 
12113                                                  * Link the finally bblock with the target, since it will
12114                                                  * conceptually branch there.
12115                                                  * FIXME: Have to link the bblock containing the endfinally.
12116                                                  */
12117                                                 GET_BBLOCK (cfg, target_bb, target);
12118                                                 link_bblock (cfg, tblock, target_bb);
12119                                         }
12120                                 }
12121                                 g_list_free (handlers);
12122                         } 
12123
12124                         MONO_INST_NEW (cfg, ins, OP_BR);
12125                         MONO_ADD_INS (cfg->cbb, ins);
12126                         GET_BBLOCK (cfg, tblock, target);
12127                         link_bblock (cfg, cfg->cbb, tblock);
12128                         ins->inst_target_bb = tblock;
12129
12130                         start_new_bblock = 1;
12131
12132                         if (*ip == CEE_LEAVE)
12133                                 ip += 5;
12134                         else
12135                                 ip += 2;
12136
12137                         break;
12138                 }
12139
12140                         /*
12141                          * Mono specific opcodes
12142                          */
12143                 case MONO_CUSTOM_PREFIX: {
12144
12145                         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
12146
12147                         CHECK_OPSIZE (2);
12148                         switch (ip [1]) {
12149                         case CEE_MONO_ICALL: {
12150                                 gpointer func;
12151                                 MonoJitICallInfo *info;
12152
12153                                 token = read32 (ip + 2);
12154                                 func = mono_method_get_wrapper_data (method, token);
12155                                 info = mono_find_jit_icall_by_addr (func);
12156                                 if (!info)
12157                                         g_error ("Could not find icall address in wrapper %s", mono_method_full_name (method, 1));
12158                                 g_assert (info);
12159
12160                                 CHECK_STACK (info->sig->param_count);
12161                                 sp -= info->sig->param_count;
12162
12163                                 ins = mono_emit_jit_icall (cfg, info->func, sp);
12164                                 if (!MONO_TYPE_IS_VOID (info->sig->ret))
12165                                         *sp++ = ins;
12166
12167                                 ip += 6;
12168                                 inline_costs += 10 * num_calls++;
12169
12170                                 break;
12171                         }
12172                         case CEE_MONO_LDPTR_CARD_TABLE:
12173                         case CEE_MONO_LDPTR_NURSERY_START:
12174                         case CEE_MONO_LDPTR_NURSERY_BITS:
12175                         case CEE_MONO_LDPTR_INT_REQ_FLAG: {
12176                                 CHECK_STACK_OVF (1);
12177
12178                                 switch (ip [1]) {
12179                                         case CEE_MONO_LDPTR_CARD_TABLE:
12180                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR, NULL);
12181                                                 break;
12182                                         case CEE_MONO_LDPTR_NURSERY_START:
12183                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_NURSERY_START, NULL);
12184                                                 break;
12185                                         case CEE_MONO_LDPTR_NURSERY_BITS:
12186                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_NURSERY_BITS, NULL);
12187                                                 break;
12188                                         case CEE_MONO_LDPTR_INT_REQ_FLAG:
12189                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG, NULL);
12190                                                 break;
12191                                 }
12192
12193                                 *sp++ = ins;
12194                                 ip += 2;
12195                                 inline_costs += 10 * num_calls++;
12196                                 break;
12197                         }
12198                         case CEE_MONO_LDPTR: {
12199                                 gpointer ptr;
12200
12201                                 CHECK_STACK_OVF (1);
12202                                 CHECK_OPSIZE (6);
12203                                 token = read32 (ip + 2);
12204
12205                                 ptr = mono_method_get_wrapper_data (method, token);
12206                                 EMIT_NEW_PCONST (cfg, ins, ptr);
12207                                 *sp++ = ins;
12208                                 ip += 6;
12209                                 inline_costs += 10 * num_calls++;
12210                                 /* Can't embed random pointers into AOT code */
12211                                 DISABLE_AOT (cfg);
12212                                 break;
12213                         }
12214                         case CEE_MONO_JIT_ICALL_ADDR: {
12215                                 MonoJitICallInfo *callinfo;
12216                                 gpointer ptr;
12217
12218                                 CHECK_STACK_OVF (1);
12219                                 CHECK_OPSIZE (6);
12220                                 token = read32 (ip + 2);
12221
12222                                 ptr = mono_method_get_wrapper_data (method, token);
12223                                 callinfo = mono_find_jit_icall_by_addr (ptr);
12224                                 g_assert (callinfo);
12225                                 EMIT_NEW_JIT_ICALL_ADDRCONST (cfg, ins, (char*)callinfo->name);
12226                                 *sp++ = ins;
12227                                 ip += 6;
12228                                 inline_costs += 10 * num_calls++;
12229                                 break;
12230                         }
12231                         case CEE_MONO_ICALL_ADDR: {
12232                                 MonoMethod *cmethod;
12233                                 gpointer ptr;
12234
12235                                 CHECK_STACK_OVF (1);
12236                                 CHECK_OPSIZE (6);
12237                                 token = read32 (ip + 2);
12238
12239                                 cmethod = mono_method_get_wrapper_data (method, token);
12240
12241                                 if (cfg->compile_aot) {
12242                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, cmethod);
12243                                 } else {
12244                                         ptr = mono_lookup_internal_call (cmethod);
12245                                         g_assert (ptr);
12246                                         EMIT_NEW_PCONST (cfg, ins, ptr);
12247                                 }
12248                                 *sp++ = ins;
12249                                 ip += 6;
12250                                 break;
12251                         }
12252                         case CEE_MONO_VTADDR: {
12253                                 MonoInst *src_var, *src;
12254
12255                                 CHECK_STACK (1);
12256                                 --sp;
12257
12258                                 // FIXME:
12259                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
12260                                 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
12261                                 *sp++ = src;
12262                                 ip += 2;
12263                                 break;
12264                         }
12265                         case CEE_MONO_NEWOBJ: {
12266                                 MonoInst *iargs [2];
12267
12268                                 CHECK_STACK_OVF (1);
12269                                 CHECK_OPSIZE (6);
12270                                 token = read32 (ip + 2);
12271                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12272                                 mono_class_init (klass);
12273                                 NEW_DOMAINCONST (cfg, iargs [0]);
12274                                 MONO_ADD_INS (cfg->cbb, iargs [0]);
12275                                 NEW_CLASSCONST (cfg, iargs [1], klass);
12276                                 MONO_ADD_INS (cfg->cbb, iargs [1]);
12277                                 *sp++ = mono_emit_jit_icall (cfg, mono_object_new, iargs);
12278                                 ip += 6;
12279                                 inline_costs += 10 * num_calls++;
12280                                 break;
12281                         }
12282                         case CEE_MONO_OBJADDR:
12283                                 CHECK_STACK (1);
12284                                 --sp;
12285                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
12286                                 ins->dreg = alloc_ireg_mp (cfg);
12287                                 ins->sreg1 = sp [0]->dreg;
12288                                 ins->type = STACK_MP;
12289                                 MONO_ADD_INS (cfg->cbb, ins);
12290                                 *sp++ = ins;
12291                                 ip += 2;
12292                                 break;
12293                         case CEE_MONO_LDNATIVEOBJ:
12294                                 /*
12295                                  * Similar to LDOBJ, but instead load the unmanaged 
12296                                  * representation of the vtype to the stack.
12297                                  */
12298                                 CHECK_STACK (1);
12299                                 CHECK_OPSIZE (6);
12300                                 --sp;
12301                                 token = read32 (ip + 2);
12302                                 klass = mono_method_get_wrapper_data (method, token);
12303                                 g_assert (klass->valuetype);
12304                                 mono_class_init (klass);
12305
12306                                 {
12307                                         MonoInst *src, *dest, *temp;
12308
12309                                         src = sp [0];
12310                                         temp = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
12311                                         temp->backend.is_pinvoke = 1;
12312                                         EMIT_NEW_TEMPLOADA (cfg, dest, temp->inst_c0);
12313                                         mini_emit_stobj (cfg, dest, src, klass, TRUE);
12314
12315                                         EMIT_NEW_TEMPLOAD (cfg, dest, temp->inst_c0);
12316                                         dest->type = STACK_VTYPE;
12317                                         dest->klass = klass;
12318
12319                                         *sp ++ = dest;
12320                                         ip += 6;
12321                                 }
12322                                 break;
12323                         case CEE_MONO_RETOBJ: {
12324                                 /*
12325                                  * Same as RET, but return the native representation of a vtype
12326                                  * to the caller.
12327                                  */
12328                                 g_assert (cfg->ret);
12329                                 g_assert (mono_method_signature (method)->pinvoke); 
12330                                 CHECK_STACK (1);
12331                                 --sp;
12332                                 
12333                                 CHECK_OPSIZE (6);
12334                                 token = read32 (ip + 2);    
12335                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12336
12337                                 if (!cfg->vret_addr) {
12338                                         g_assert (cfg->ret_var_is_local);
12339
12340                                         EMIT_NEW_VARLOADA (cfg, ins, cfg->ret, cfg->ret->inst_vtype);
12341                                 } else {
12342                                         EMIT_NEW_RETLOADA (cfg, ins);
12343                                 }
12344                                 mini_emit_stobj (cfg, ins, sp [0], klass, TRUE);
12345                                 
12346                                 if (sp != stack_start)
12347                                         UNVERIFIED;
12348                                 
12349                                 MONO_INST_NEW (cfg, ins, OP_BR);
12350                                 ins->inst_target_bb = end_bblock;
12351                                 MONO_ADD_INS (cfg->cbb, ins);
12352                                 link_bblock (cfg, cfg->cbb, end_bblock);
12353                                 start_new_bblock = 1;
12354                                 ip += 6;
12355                                 break;
12356                         }
12357                         case CEE_MONO_CISINST:
12358                         case CEE_MONO_CCASTCLASS: {
12359                                 int token;
12360                                 CHECK_STACK (1);
12361                                 --sp;
12362                                 CHECK_OPSIZE (6);
12363                                 token = read32 (ip + 2);
12364                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12365                                 if (ip [1] == CEE_MONO_CISINST)
12366                                         ins = handle_cisinst (cfg, klass, sp [0]);
12367                                 else
12368                                         ins = handle_ccastclass (cfg, klass, sp [0]);
12369                                 *sp++ = ins;
12370                                 ip += 6;
12371                                 break;
12372                         }
12373                         case CEE_MONO_SAVE_LMF:
12374                         case CEE_MONO_RESTORE_LMF:
12375                                 ip += 2;
12376                                 break;
12377                         case CEE_MONO_CLASSCONST:
12378                                 CHECK_STACK_OVF (1);
12379                                 CHECK_OPSIZE (6);
12380                                 token = read32 (ip + 2);
12381                                 EMIT_NEW_CLASSCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
12382                                 *sp++ = ins;
12383                                 ip += 6;
12384                                 inline_costs += 10 * num_calls++;
12385                                 break;
12386                         case CEE_MONO_NOT_TAKEN:
12387                                 cfg->cbb->out_of_line = TRUE;
12388                                 ip += 2;
12389                                 break;
12390                         case CEE_MONO_TLS: {
12391                                 int key;
12392
12393                                 CHECK_STACK_OVF (1);
12394                                 CHECK_OPSIZE (6);
12395                                 key = (gint32)read32 (ip + 2);
12396                                 g_assert (key < TLS_KEY_NUM);
12397
12398                                 ins = mono_create_tls_get (cfg, key);
12399                                 if (!ins) {
12400                                         if (cfg->compile_aot) {
12401                                                 DISABLE_AOT (cfg);
12402                                                 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
12403                                                 ins->dreg = alloc_preg (cfg);
12404                                                 ins->type = STACK_PTR;
12405                                         } else {
12406                                                 g_assert_not_reached ();
12407                                         }
12408                                 }
12409                                 ins->type = STACK_PTR;
12410                                 MONO_ADD_INS (cfg->cbb, ins);
12411                                 *sp++ = ins;
12412                                 ip += 6;
12413                                 break;
12414                         }
12415                         case CEE_MONO_DYN_CALL: {
12416                                 MonoCallInst *call;
12417
12418                                 /* It would be easier to call a trampoline, but that would put an
12419                                  * extra frame on the stack, confusing exception handling. So
12420                                  * implement it inline using an opcode for now.
12421                                  */
12422
12423                                 if (!cfg->dyn_call_var) {
12424                                         cfg->dyn_call_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12425                                         /* prevent it from being register allocated */
12426                                         cfg->dyn_call_var->flags |= MONO_INST_VOLATILE;
12427                                 }
12428
12429                                 /* Has to use a call inst since it local regalloc expects it */
12430                                 MONO_INST_NEW_CALL (cfg, call, OP_DYN_CALL);
12431                                 ins = (MonoInst*)call;
12432                                 sp -= 2;
12433                                 ins->sreg1 = sp [0]->dreg;
12434                                 ins->sreg2 = sp [1]->dreg;
12435                                 MONO_ADD_INS (cfg->cbb, ins);
12436
12437                                 cfg->param_area = MAX (cfg->param_area, cfg->backend->dyn_call_param_area);
12438
12439                                 ip += 2;
12440                                 inline_costs += 10 * num_calls++;
12441
12442                                 break;
12443                         }
12444                         case CEE_MONO_MEMORY_BARRIER: {
12445                                 CHECK_OPSIZE (6);
12446                                 emit_memory_barrier (cfg, (int)read32 (ip + 2));
12447                                 ip += 6;
12448                                 break;
12449                         }
12450                         case CEE_MONO_JIT_ATTACH: {
12451                                 MonoInst *args [16], *domain_ins;
12452                                 MonoInst *ad_ins, *jit_tls_ins;
12453                                 MonoBasicBlock *next_bb = NULL, *call_bb = NULL;
12454
12455                                 cfg->orig_domain_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12456
12457                                 EMIT_NEW_PCONST (cfg, ins, NULL);
12458                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12459
12460                                 ad_ins = mono_get_domain_intrinsic (cfg);
12461                                 jit_tls_ins = mono_get_jit_tls_intrinsic (cfg);
12462
12463                                 if (cfg->backend->have_tls_get && ad_ins && jit_tls_ins) {
12464                                         NEW_BBLOCK (cfg, next_bb);
12465                                         NEW_BBLOCK (cfg, call_bb);
12466
12467                                         if (cfg->compile_aot) {
12468                                                 /* AOT code is only used in the root domain */
12469                                                 EMIT_NEW_PCONST (cfg, domain_ins, NULL);
12470                                         } else {
12471                                                 EMIT_NEW_PCONST (cfg, domain_ins, cfg->domain);
12472                                         }
12473                                         MONO_ADD_INS (cfg->cbb, ad_ins);
12474                                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, ad_ins->dreg, domain_ins->dreg);
12475                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, call_bb);
12476
12477                                         MONO_ADD_INS (cfg->cbb, jit_tls_ins);
12478                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, jit_tls_ins->dreg, 0);
12479                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, call_bb);
12480
12481                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, next_bb);
12482                                         MONO_START_BB (cfg, call_bb);
12483                                 }
12484
12485                                 if (cfg->compile_aot) {
12486                                         /* AOT code is only used in the root domain */
12487                                         EMIT_NEW_PCONST (cfg, args [0], NULL);
12488                                 } else {
12489                                         EMIT_NEW_PCONST (cfg, args [0], cfg->domain);
12490                                 }
12491                                 ins = mono_emit_jit_icall (cfg, mono_jit_thread_attach, args);
12492                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12493
12494                                 if (next_bb)
12495                                         MONO_START_BB (cfg, next_bb);
12496                                 ip += 2;
12497                                 break;
12498                         }
12499                         case CEE_MONO_JIT_DETACH: {
12500                                 MonoInst *args [16];
12501
12502                                 /* Restore the original domain */
12503                                 dreg = alloc_ireg (cfg);
12504                                 EMIT_NEW_UNALU (cfg, args [0], OP_MOVE, dreg, cfg->orig_domain_var->dreg);
12505                                 mono_emit_jit_icall (cfg, mono_jit_set_domain, args);
12506                                 ip += 2;
12507                                 break;
12508                         }
12509                         default:
12510                                 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
12511                                 break;
12512                         }
12513                         break;
12514                 }
12515
12516                 case CEE_PREFIX1: {
12517                         CHECK_OPSIZE (2);
12518                         switch (ip [1]) {
12519                         case CEE_ARGLIST: {
12520                                 /* somewhat similar to LDTOKEN */
12521                                 MonoInst *addr, *vtvar;
12522                                 CHECK_STACK_OVF (1);
12523                                 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL); 
12524
12525                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
12526                                 EMIT_NEW_UNALU (cfg, ins, OP_ARGLIST, -1, addr->dreg);
12527
12528                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
12529                                 ins->type = STACK_VTYPE;
12530                                 ins->klass = mono_defaults.argumenthandle_class;
12531                                 *sp++ = ins;
12532                                 ip += 2;
12533                                 break;
12534                         }
12535                         case CEE_CEQ:
12536                         case CEE_CGT:
12537                         case CEE_CGT_UN:
12538                         case CEE_CLT:
12539                         case CEE_CLT_UN: {
12540                                 MonoInst *cmp, *arg1, *arg2;
12541
12542                                 CHECK_STACK (2);
12543                                 sp -= 2;
12544                                 arg1 = sp [0];
12545                                 arg2 = sp [1];
12546
12547                                 /*
12548                                  * The following transforms:
12549                                  *    CEE_CEQ    into OP_CEQ
12550                                  *    CEE_CGT    into OP_CGT
12551                                  *    CEE_CGT_UN into OP_CGT_UN
12552                                  *    CEE_CLT    into OP_CLT
12553                                  *    CEE_CLT_UN into OP_CLT_UN
12554                                  */
12555                                 MONO_INST_NEW (cfg, cmp, (OP_CEQ - CEE_CEQ) + ip [1]);
12556
12557                                 MONO_INST_NEW (cfg, ins, cmp->opcode);
12558                                 cmp->sreg1 = arg1->dreg;
12559                                 cmp->sreg2 = arg2->dreg;
12560                                 type_from_op (cfg, cmp, arg1, arg2);
12561                                 CHECK_TYPE (cmp);
12562                                 add_widen_op (cfg, cmp, &arg1, &arg2);
12563                                 if ((arg1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((arg1->type == STACK_PTR) || (arg1->type == STACK_OBJ) || (arg1->type == STACK_MP))))
12564                                         cmp->opcode = OP_LCOMPARE;
12565                                 else if (arg1->type == STACK_R4)
12566                                         cmp->opcode = OP_RCOMPARE;
12567                                 else if (arg1->type == STACK_R8)
12568                                         cmp->opcode = OP_FCOMPARE;
12569                                 else
12570                                         cmp->opcode = OP_ICOMPARE;
12571                                 MONO_ADD_INS (cfg->cbb, cmp);
12572                                 ins->type = STACK_I4;
12573                                 ins->dreg = alloc_dreg (cfg, ins->type);
12574                                 type_from_op (cfg, ins, arg1, arg2);
12575
12576                                 if (cmp->opcode == OP_FCOMPARE || cmp->opcode == OP_RCOMPARE) {
12577                                         /*
12578                                          * The backends expect the fceq opcodes to do the
12579                                          * comparison too.
12580                                          */
12581                                         ins->sreg1 = cmp->sreg1;
12582                                         ins->sreg2 = cmp->sreg2;
12583                                         NULLIFY_INS (cmp);
12584                                 }
12585                                 MONO_ADD_INS (cfg->cbb, ins);
12586                                 *sp++ = ins;
12587                                 ip += 2;
12588                                 break;
12589                         }
12590                         case CEE_LDFTN: {
12591                                 MonoInst *argconst;
12592                                 MonoMethod *cil_method;
12593
12594                                 CHECK_STACK_OVF (1);
12595                                 CHECK_OPSIZE (6);
12596                                 n = read32 (ip + 2);
12597                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
12598                                 if (!cmethod || mono_loader_get_last_error ())
12599                                         LOAD_ERROR;
12600                                 mono_class_init (cmethod->klass);
12601
12602                                 mono_save_token_info (cfg, image, n, cmethod);
12603
12604                                 context_used = mini_method_check_context_used (cfg, cmethod);
12605
12606                                 cil_method = cmethod;
12607                                 if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
12608                                         METHOD_ACCESS_FAILURE (method, cil_method);
12609
12610                                 if (mono_security_core_clr_enabled ())
12611                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
12612
12613                                 /* 
12614                                  * Optimize the common case of ldftn+delegate creation
12615                                  */
12616                                 if ((sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 6) && (ip [6] == CEE_NEWOBJ)) {
12617                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
12618                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
12619                                                 MonoInst *target_ins, *handle_ins;
12620                                                 MonoMethod *invoke;
12621                                                 int invoke_context_used;
12622
12623                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
12624                                                 if (!invoke || !mono_method_signature (invoke))
12625                                                         LOAD_ERROR;
12626
12627                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
12628
12629                                                 target_ins = sp [-1];
12630
12631                                                 if (mono_security_core_clr_enabled ())
12632                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
12633
12634                                                 if (!(cmethod->flags & METHOD_ATTRIBUTE_STATIC)) {
12635                                                         /*LAME IMPL: We must not add a null check for virtual invoke delegates.*/
12636                                                         if (mono_method_signature (invoke)->param_count == mono_method_signature (cmethod)->param_count) {
12637                                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, target_ins->dreg, 0);
12638                                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "ArgumentException");
12639                                                         }
12640                                                 }
12641
12642                                                 /* FIXME: SGEN support */
12643                                                 if (invoke_context_used == 0) {
12644                                                         ip += 6;
12645                                                         if (cfg->verbose_level > 3)
12646                                                                 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));
12647                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, FALSE))) {
12648                                                                 sp --;
12649                                                                 *sp = handle_ins;
12650                                                                 CHECK_CFG_EXCEPTION;
12651                                                                 ip += 5;
12652                                                                 sp ++;
12653                                                                 break;
12654                                                         }
12655                                                         ip -= 6;
12656                                                 }
12657                                         }
12658                                 }
12659
12660                                 argconst = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD);
12661                                 ins = mono_emit_jit_icall (cfg, mono_ldftn, &argconst);
12662                                 *sp++ = ins;
12663                                 
12664                                 ip += 6;
12665                                 inline_costs += 10 * num_calls++;
12666                                 break;
12667                         }
12668                         case CEE_LDVIRTFTN: {
12669                                 MonoInst *args [2];
12670
12671                                 CHECK_STACK (1);
12672                                 CHECK_OPSIZE (6);
12673                                 n = read32 (ip + 2);
12674                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
12675                                 if (!cmethod || mono_loader_get_last_error ())
12676                                         LOAD_ERROR;
12677                                 mono_class_init (cmethod->klass);
12678  
12679                                 context_used = mini_method_check_context_used (cfg, cmethod);
12680
12681                                 if (mono_security_core_clr_enabled ())
12682                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
12683
12684                                 /*
12685                                  * Optimize the common case of ldvirtftn+delegate creation
12686                                  */
12687                                 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)) {
12688                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
12689                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
12690                                                 MonoInst *target_ins, *handle_ins;
12691                                                 MonoMethod *invoke;
12692                                                 int invoke_context_used;
12693                                                 gboolean is_virtual = cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL;
12694
12695                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
12696                                                 if (!invoke || !mono_method_signature (invoke))
12697                                                         LOAD_ERROR;
12698
12699                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
12700
12701                                                 target_ins = sp [-1];
12702
12703                                                 if (mono_security_core_clr_enabled ())
12704                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
12705
12706                                                 /* FIXME: SGEN support */
12707                                                 if (invoke_context_used == 0 || cfg->llvm_only) {
12708                                                         ip += 6;
12709                                                         if (cfg->verbose_level > 3)
12710                                                                 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));
12711                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, is_virtual))) {
12712                                                                 sp -= 2;
12713                                                                 *sp = handle_ins;
12714                                                                 CHECK_CFG_EXCEPTION;
12715                                                                 ip += 5;
12716                                                                 sp ++;
12717                                                                 break;
12718                                                         }
12719                                                         ip -= 6;
12720                                                 }
12721                                         }
12722                                 }
12723
12724                                 --sp;
12725                                 args [0] = *sp;
12726
12727                                 args [1] = emit_get_rgctx_method (cfg, context_used,
12728                                                                                                   cmethod, MONO_RGCTX_INFO_METHOD);
12729
12730                                 if (context_used)
12731                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn_gshared, args);
12732                                 else
12733                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn, args);
12734
12735                                 ip += 6;
12736                                 inline_costs += 10 * num_calls++;
12737                                 break;
12738                         }
12739                         case CEE_LDARG:
12740                                 CHECK_STACK_OVF (1);
12741                                 CHECK_OPSIZE (4);
12742                                 n = read16 (ip + 2);
12743                                 CHECK_ARG (n);
12744                                 EMIT_NEW_ARGLOAD (cfg, ins, n);
12745                                 *sp++ = ins;
12746                                 ip += 4;
12747                                 break;
12748                         case CEE_LDARGA:
12749                                 CHECK_STACK_OVF (1);
12750                                 CHECK_OPSIZE (4);
12751                                 n = read16 (ip + 2);
12752                                 CHECK_ARG (n);
12753                                 NEW_ARGLOADA (cfg, ins, n);
12754                                 MONO_ADD_INS (cfg->cbb, ins);
12755                                 *sp++ = ins;
12756                                 ip += 4;
12757                                 break;
12758                         case CEE_STARG:
12759                                 CHECK_STACK (1);
12760                                 --sp;
12761                                 CHECK_OPSIZE (4);
12762                                 n = read16 (ip + 2);
12763                                 CHECK_ARG (n);
12764                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
12765                                         UNVERIFIED;
12766                                 EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
12767                                 ip += 4;
12768                                 break;
12769                         case CEE_LDLOC:
12770                                 CHECK_STACK_OVF (1);
12771                                 CHECK_OPSIZE (4);
12772                                 n = read16 (ip + 2);
12773                                 CHECK_LOCAL (n);
12774                                 EMIT_NEW_LOCLOAD (cfg, ins, n);
12775                                 *sp++ = ins;
12776                                 ip += 4;
12777                                 break;
12778                         case CEE_LDLOCA: {
12779                                 unsigned char *tmp_ip;
12780                                 CHECK_STACK_OVF (1);
12781                                 CHECK_OPSIZE (4);
12782                                 n = read16 (ip + 2);
12783                                 CHECK_LOCAL (n);
12784
12785                                 if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 2))) {
12786                                         ip = tmp_ip;
12787                                         inline_costs += 1;
12788                                         break;
12789                                 }                       
12790                                 
12791                                 EMIT_NEW_LOCLOADA (cfg, ins, n);
12792                                 *sp++ = ins;
12793                                 ip += 4;
12794                                 break;
12795                         }
12796                         case CEE_STLOC:
12797                                 CHECK_STACK (1);
12798                                 --sp;
12799                                 CHECK_OPSIZE (4);
12800                                 n = read16 (ip + 2);
12801                                 CHECK_LOCAL (n);
12802                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
12803                                         UNVERIFIED;
12804                                 emit_stloc_ir (cfg, sp, header, n);
12805                                 ip += 4;
12806                                 inline_costs += 1;
12807                                 break;
12808                         case CEE_LOCALLOC:
12809                                 CHECK_STACK (1);
12810                                 --sp;
12811                                 if (sp != stack_start) 
12812                                         UNVERIFIED;
12813                                 if (cfg->method != method) 
12814                                         /* 
12815                                          * Inlining this into a loop in a parent could lead to 
12816                                          * stack overflows which is different behavior than the
12817                                          * non-inlined case, thus disable inlining in this case.
12818                                          */
12819                                         INLINE_FAILURE("localloc");
12820
12821                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
12822                                 ins->dreg = alloc_preg (cfg);
12823                                 ins->sreg1 = sp [0]->dreg;
12824                                 ins->type = STACK_PTR;
12825                                 MONO_ADD_INS (cfg->cbb, ins);
12826
12827                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12828                                 if (init_locals)
12829                                         ins->flags |= MONO_INST_INIT;
12830
12831                                 *sp++ = ins;
12832                                 ip += 2;
12833                                 break;
12834                         case CEE_ENDFILTER: {
12835                                 MonoExceptionClause *clause, *nearest;
12836                                 int cc;
12837
12838                                 CHECK_STACK (1);
12839                                 --sp;
12840                                 if ((sp != stack_start) || (sp [0]->type != STACK_I4)) 
12841                                         UNVERIFIED;
12842                                 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
12843                                 ins->sreg1 = (*sp)->dreg;
12844                                 MONO_ADD_INS (cfg->cbb, ins);
12845                                 start_new_bblock = 1;
12846                                 ip += 2;
12847
12848                                 nearest = NULL;
12849                                 for (cc = 0; cc < header->num_clauses; ++cc) {
12850                                         clause = &header->clauses [cc];
12851                                         if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
12852                                                 ((ip - header->code) > clause->data.filter_offset && (ip - header->code) <= clause->handler_offset) &&
12853                                             (!nearest || (clause->data.filter_offset < nearest->data.filter_offset)))
12854                                                 nearest = clause;
12855                                 }
12856                                 g_assert (nearest);
12857                                 if ((ip - header->code) != nearest->handler_offset)
12858                                         UNVERIFIED;
12859
12860                                 break;
12861                         }
12862                         case CEE_UNALIGNED_:
12863                                 ins_flag |= MONO_INST_UNALIGNED;
12864                                 /* FIXME: record alignment? we can assume 1 for now */
12865                                 CHECK_OPSIZE (3);
12866                                 ip += 3;
12867                                 break;
12868                         case CEE_VOLATILE_:
12869                                 ins_flag |= MONO_INST_VOLATILE;
12870                                 ip += 2;
12871                                 break;
12872                         case CEE_TAIL_:
12873                                 ins_flag   |= MONO_INST_TAILCALL;
12874                                 cfg->flags |= MONO_CFG_HAS_TAIL;
12875                                 /* Can't inline tail calls at this time */
12876                                 inline_costs += 100000;
12877                                 ip += 2;
12878                                 break;
12879                         case CEE_INITOBJ:
12880                                 CHECK_STACK (1);
12881                                 --sp;
12882                                 CHECK_OPSIZE (6);
12883                                 token = read32 (ip + 2);
12884                                 klass = mini_get_class (method, token, generic_context);
12885                                 CHECK_TYPELOAD (klass);
12886                                 if (generic_class_is_reference_type (cfg, klass))
12887                                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, sp [0]->dreg, 0, 0);
12888                                 else
12889                                         mini_emit_initobj (cfg, *sp, NULL, klass);
12890                                 ip += 6;
12891                                 inline_costs += 1;
12892                                 break;
12893                         case CEE_CONSTRAINED_:
12894                                 CHECK_OPSIZE (6);
12895                                 token = read32 (ip + 2);
12896                                 constrained_class = mini_get_class (method, token, generic_context);
12897                                 CHECK_TYPELOAD (constrained_class);
12898                                 ip += 6;
12899                                 break;
12900                         case CEE_CPBLK:
12901                         case CEE_INITBLK: {
12902                                 MonoInst *iargs [3];
12903                                 CHECK_STACK (3);
12904                                 sp -= 3;
12905
12906                                 /* Skip optimized paths for volatile operations. */
12907                                 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)) {
12908                                         mini_emit_memcpy (cfg, sp [0]->dreg, 0, sp [1]->dreg, 0, sp [2]->inst_c0, 0);
12909                                 } 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)) {
12910                                         /* emit_memset only works when val == 0 */
12911                                         mini_emit_memset (cfg, sp [0]->dreg, 0, sp [2]->inst_c0, sp [1]->inst_c0, 0);
12912                                 } else {
12913                                         MonoInst *call;
12914                                         iargs [0] = sp [0];
12915                                         iargs [1] = sp [1];
12916                                         iargs [2] = sp [2];
12917                                         if (ip [1] == CEE_CPBLK) {
12918                                                 /*
12919                                                  * FIXME: It's unclear whether we should be emitting both the acquire
12920                                                  * and release barriers for cpblk. It is technically both a load and
12921                                                  * store operation, so it seems like that's the sensible thing to do.
12922                                                  *
12923                                                  * FIXME: We emit full barriers on both sides of the operation for
12924                                                  * simplicity. We should have a separate atomic memcpy method instead.
12925                                                  */
12926                                                 MonoMethod *memcpy_method = get_memcpy_method ();
12927
12928                                                 if (ins_flag & MONO_INST_VOLATILE)
12929                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
12930
12931                                                 call = mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
12932                                                 call->flags |= ins_flag;
12933
12934                                                 if (ins_flag & MONO_INST_VOLATILE)
12935                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
12936                                         } else {
12937                                                 MonoMethod *memset_method = get_memset_method ();
12938                                                 if (ins_flag & MONO_INST_VOLATILE) {
12939                                                         /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
12940                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
12941                                                 }
12942                                                 call = mono_emit_method_call (cfg, memset_method, iargs, NULL);
12943                                                 call->flags |= ins_flag;
12944                                         }
12945                                 }
12946                                 ip += 2;
12947                                 ins_flag = 0;
12948                                 inline_costs += 1;
12949                                 break;
12950                         }
12951                         case CEE_NO_:
12952                                 CHECK_OPSIZE (3);
12953                                 if (ip [2] & 0x1)
12954                                         ins_flag |= MONO_INST_NOTYPECHECK;
12955                                 if (ip [2] & 0x2)
12956                                         ins_flag |= MONO_INST_NORANGECHECK;
12957                                 /* we ignore the no-nullcheck for now since we
12958                                  * really do it explicitly only when doing callvirt->call
12959                                  */
12960                                 ip += 3;
12961                                 break;
12962                         case CEE_RETHROW: {
12963                                 MonoInst *load;
12964                                 int handler_offset = -1;
12965
12966                                 for (i = 0; i < header->num_clauses; ++i) {
12967                                         MonoExceptionClause *clause = &header->clauses [i];
12968                                         if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
12969                                                 handler_offset = clause->handler_offset;
12970                                                 break;
12971                                         }
12972                                 }
12973
12974                                 cfg->cbb->flags |= BB_EXCEPTION_UNSAFE;
12975
12976                                 if (handler_offset == -1)
12977                                         UNVERIFIED;
12978
12979                                 EMIT_NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
12980                                 MONO_INST_NEW (cfg, ins, OP_RETHROW);
12981                                 ins->sreg1 = load->dreg;
12982                                 MONO_ADD_INS (cfg->cbb, ins);
12983
12984                                 MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
12985                                 MONO_ADD_INS (cfg->cbb, ins);
12986
12987                                 sp = stack_start;
12988                                 link_bblock (cfg, cfg->cbb, end_bblock);
12989                                 start_new_bblock = 1;
12990                                 ip += 2;
12991                                 break;
12992                         }
12993                         case CEE_SIZEOF: {
12994                                 guint32 val;
12995                                 int ialign;
12996
12997                                 CHECK_STACK_OVF (1);
12998                                 CHECK_OPSIZE (6);
12999                                 token = read32 (ip + 2);
13000                                 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC && !image_is_dynamic (method->klass->image) && !generic_context) {
13001                                         MonoType *type = mono_type_create_from_typespec_checked (image, token, &cfg->error);
13002                                         CHECK_CFG_ERROR;
13003
13004                                         val = mono_type_size (type, &ialign);
13005                                 } else {
13006                                         MonoClass *klass = mini_get_class (method, token, generic_context);
13007                                         CHECK_TYPELOAD (klass);
13008
13009                                         val = mono_type_size (&klass->byval_arg, &ialign);
13010
13011                                         if (mini_is_gsharedvt_klass (klass))
13012                                                 GSHAREDVT_FAILURE (*ip);
13013                                 }
13014                                 EMIT_NEW_ICONST (cfg, ins, val);
13015                                 *sp++= ins;
13016                                 ip += 6;
13017                                 break;
13018                         }
13019                         case CEE_REFANYTYPE: {
13020                                 MonoInst *src_var, *src;
13021
13022                                 GSHAREDVT_FAILURE (*ip);
13023
13024                                 CHECK_STACK (1);
13025                                 --sp;
13026
13027                                 // FIXME:
13028                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
13029                                 if (!src_var)
13030                                         src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
13031                                 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
13032                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &mono_defaults.typehandle_class->byval_arg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type));
13033                                 *sp++ = ins;
13034                                 ip += 2;
13035                                 break;
13036                         }
13037                         case CEE_READONLY_:
13038                                 readonly = TRUE;
13039                                 ip += 2;
13040                                 break;
13041
13042                         case CEE_UNUSED56:
13043                         case CEE_UNUSED57:
13044                         case CEE_UNUSED70:
13045                         case CEE_UNUSED:
13046                         case CEE_UNUSED99:
13047                                 UNVERIFIED;
13048                                 
13049                         default:
13050                                 g_warning ("opcode 0xfe 0x%02x not handled", ip [1]);
13051                                 UNVERIFIED;
13052                         }
13053                         break;
13054                 }
13055                 case CEE_UNUSED58:
13056                 case CEE_UNUSED1:
13057                         UNVERIFIED;
13058
13059                 default:
13060                         g_warning ("opcode 0x%02x not handled", *ip);
13061                         UNVERIFIED;
13062                 }
13063         }
13064         if (start_new_bblock != 1)
13065                 UNVERIFIED;
13066
13067         cfg->cbb->cil_length = ip - cfg->cbb->cil_code;
13068         if (cfg->cbb->next_bb) {
13069                 /* This could already be set because of inlining, #693905 */
13070                 MonoBasicBlock *bb = cfg->cbb;
13071
13072                 while (bb->next_bb)
13073                         bb = bb->next_bb;
13074                 bb->next_bb = end_bblock;
13075         } else {
13076                 cfg->cbb->next_bb = end_bblock;
13077         }
13078
13079         if (cfg->method == method && cfg->domainvar) {
13080                 MonoInst *store;
13081                 MonoInst *get_domain;
13082
13083                 cfg->cbb = init_localsbb;
13084
13085                 if ((get_domain = mono_get_domain_intrinsic (cfg))) {
13086                         MONO_ADD_INS (cfg->cbb, get_domain);
13087                 } else {
13088                         get_domain = mono_emit_jit_icall (cfg, mono_domain_get, NULL);
13089                 }
13090                 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, get_domain);
13091                 MONO_ADD_INS (cfg->cbb, store);
13092         }
13093
13094 #if defined(TARGET_POWERPC) || defined(TARGET_X86)
13095         if (cfg->compile_aot)
13096                 /* FIXME: The plt slots require a GOT var even if the method doesn't use it */
13097                 mono_get_got_var (cfg);
13098 #endif
13099
13100         if (cfg->method == method && cfg->got_var)
13101                 mono_emit_load_got_addr (cfg);
13102
13103         if (init_localsbb) {
13104                 cfg->cbb = init_localsbb;
13105                 cfg->ip = NULL;
13106                 for (i = 0; i < header->num_locals; ++i) {
13107                         emit_init_local (cfg, i, header->locals [i], init_locals);
13108                 }
13109         }
13110
13111         if (cfg->init_ref_vars && cfg->method == method) {
13112                 /* Emit initialization for ref vars */
13113                 // FIXME: Avoid duplication initialization for IL locals.
13114                 for (i = 0; i < cfg->num_varinfo; ++i) {
13115                         MonoInst *ins = cfg->varinfo [i];
13116
13117                         if (ins->opcode == OP_LOCAL && ins->type == STACK_OBJ)
13118                                 MONO_EMIT_NEW_PCONST (cfg, ins->dreg, NULL);
13119                 }
13120         }
13121
13122         if (cfg->lmf_var && cfg->method == method && !cfg->llvm_only) {
13123                 cfg->cbb = init_localsbb;
13124                 emit_push_lmf (cfg);
13125         }
13126
13127         cfg->cbb = init_localsbb;
13128         emit_instrumentation_call (cfg, mono_profiler_method_enter);
13129
13130         if (seq_points) {
13131                 MonoBasicBlock *bb;
13132
13133                 /*
13134                  * Make seq points at backward branch targets interruptable.
13135                  */
13136                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
13137                         if (bb->code && bb->in_count > 1 && bb->code->opcode == OP_SEQ_POINT)
13138                                 bb->code->flags |= MONO_INST_SINGLE_STEP_LOC;
13139         }
13140
13141         /* Add a sequence point for method entry/exit events */
13142         if (seq_points && cfg->gen_sdb_seq_points) {
13143                 NEW_SEQ_POINT (cfg, ins, METHOD_ENTRY_IL_OFFSET, FALSE);
13144                 MONO_ADD_INS (init_localsbb, ins);
13145                 NEW_SEQ_POINT (cfg, ins, METHOD_EXIT_IL_OFFSET, FALSE);
13146                 MONO_ADD_INS (cfg->bb_exit, ins);
13147         }
13148
13149         /*
13150          * Add seq points for IL offsets which have line number info, but wasn't generated a seq point during JITting because
13151          * the code they refer to was dead (#11880).
13152          */
13153         if (sym_seq_points) {
13154                 for (i = 0; i < header->code_size; ++i) {
13155                         if (mono_bitset_test_fast (seq_point_locs, i) && !mono_bitset_test_fast (seq_point_set_locs, i)) {
13156                                 MonoInst *ins;
13157
13158                                 NEW_SEQ_POINT (cfg, ins, i, FALSE);
13159                                 mono_add_seq_point (cfg, NULL, ins, SEQ_POINT_NATIVE_OFFSET_DEAD_CODE);
13160                         }
13161                 }
13162         }
13163
13164         cfg->ip = NULL;
13165
13166         if (cfg->method == method) {
13167                 MonoBasicBlock *bb;
13168                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13169                         bb->region = mono_find_block_region (cfg, bb->real_offset);
13170                         if (cfg->spvars)
13171                                 mono_create_spvar_for_region (cfg, bb->region);
13172                         if (cfg->verbose_level > 2)
13173                                 printf ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
13174                 }
13175         }
13176
13177         if (inline_costs < 0) {
13178                 char *mname;
13179
13180                 /* Method is too large */
13181                 mname = mono_method_full_name (method, TRUE);
13182                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
13183                 cfg->exception_message = g_strdup_printf ("Method %s is too complex.", mname);
13184                 g_free (mname);
13185         }
13186
13187         if ((cfg->verbose_level > 2) && (cfg->method == method)) 
13188                 mono_print_code (cfg, "AFTER METHOD-TO-IR");
13189
13190         goto cleanup;
13191
13192 mono_error_exit:
13193         g_assert (!mono_error_ok (&cfg->error));
13194         goto cleanup;
13195  
13196  exception_exit:
13197         g_assert (cfg->exception_type != MONO_EXCEPTION_NONE);
13198         goto cleanup;
13199
13200  unverified:
13201         set_exception_type_from_invalid_il (cfg, method, ip);
13202         goto cleanup;
13203
13204  cleanup:
13205         g_slist_free (class_inits);
13206         mono_basic_block_free (original_bb);
13207         cfg->dont_inline = g_list_remove (cfg->dont_inline, method);
13208         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
13209         if (cfg->exception_type)
13210                 return -1;
13211         else
13212                 return inline_costs;
13213 }
13214
13215 static int
13216 store_membase_reg_to_store_membase_imm (int opcode)
13217 {
13218         switch (opcode) {
13219         case OP_STORE_MEMBASE_REG:
13220                 return OP_STORE_MEMBASE_IMM;
13221         case OP_STOREI1_MEMBASE_REG:
13222                 return OP_STOREI1_MEMBASE_IMM;
13223         case OP_STOREI2_MEMBASE_REG:
13224                 return OP_STOREI2_MEMBASE_IMM;
13225         case OP_STOREI4_MEMBASE_REG:
13226                 return OP_STOREI4_MEMBASE_IMM;
13227         case OP_STOREI8_MEMBASE_REG:
13228                 return OP_STOREI8_MEMBASE_IMM;
13229         default:
13230                 g_assert_not_reached ();
13231         }
13232
13233         return -1;
13234 }               
13235
13236 int
13237 mono_op_to_op_imm (int opcode)
13238 {
13239         switch (opcode) {
13240         case OP_IADD:
13241                 return OP_IADD_IMM;
13242         case OP_ISUB:
13243                 return OP_ISUB_IMM;
13244         case OP_IDIV:
13245                 return OP_IDIV_IMM;
13246         case OP_IDIV_UN:
13247                 return OP_IDIV_UN_IMM;
13248         case OP_IREM:
13249                 return OP_IREM_IMM;
13250         case OP_IREM_UN:
13251                 return OP_IREM_UN_IMM;
13252         case OP_IMUL:
13253                 return OP_IMUL_IMM;
13254         case OP_IAND:
13255                 return OP_IAND_IMM;
13256         case OP_IOR:
13257                 return OP_IOR_IMM;
13258         case OP_IXOR:
13259                 return OP_IXOR_IMM;
13260         case OP_ISHL:
13261                 return OP_ISHL_IMM;
13262         case OP_ISHR:
13263                 return OP_ISHR_IMM;
13264         case OP_ISHR_UN:
13265                 return OP_ISHR_UN_IMM;
13266
13267         case OP_LADD:
13268                 return OP_LADD_IMM;
13269         case OP_LSUB:
13270                 return OP_LSUB_IMM;
13271         case OP_LAND:
13272                 return OP_LAND_IMM;
13273         case OP_LOR:
13274                 return OP_LOR_IMM;
13275         case OP_LXOR:
13276                 return OP_LXOR_IMM;
13277         case OP_LSHL:
13278                 return OP_LSHL_IMM;
13279         case OP_LSHR:
13280                 return OP_LSHR_IMM;
13281         case OP_LSHR_UN:
13282                 return OP_LSHR_UN_IMM;
13283 #if SIZEOF_REGISTER == 8
13284         case OP_LREM:
13285                 return OP_LREM_IMM;
13286 #endif
13287
13288         case OP_COMPARE:
13289                 return OP_COMPARE_IMM;
13290         case OP_ICOMPARE:
13291                 return OP_ICOMPARE_IMM;
13292         case OP_LCOMPARE:
13293                 return OP_LCOMPARE_IMM;
13294
13295         case OP_STORE_MEMBASE_REG:
13296                 return OP_STORE_MEMBASE_IMM;
13297         case OP_STOREI1_MEMBASE_REG:
13298                 return OP_STOREI1_MEMBASE_IMM;
13299         case OP_STOREI2_MEMBASE_REG:
13300                 return OP_STOREI2_MEMBASE_IMM;
13301         case OP_STOREI4_MEMBASE_REG:
13302                 return OP_STOREI4_MEMBASE_IMM;
13303
13304 #if defined(TARGET_X86) || defined (TARGET_AMD64)
13305         case OP_X86_PUSH:
13306                 return OP_X86_PUSH_IMM;
13307         case OP_X86_COMPARE_MEMBASE_REG:
13308                 return OP_X86_COMPARE_MEMBASE_IMM;
13309 #endif
13310 #if defined(TARGET_AMD64)
13311         case OP_AMD64_ICOMPARE_MEMBASE_REG:
13312                 return OP_AMD64_ICOMPARE_MEMBASE_IMM;
13313 #endif
13314         case OP_VOIDCALL_REG:
13315                 return OP_VOIDCALL;
13316         case OP_CALL_REG:
13317                 return OP_CALL;
13318         case OP_LCALL_REG:
13319                 return OP_LCALL;
13320         case OP_FCALL_REG:
13321                 return OP_FCALL;
13322         case OP_LOCALLOC:
13323                 return OP_LOCALLOC_IMM;
13324         }
13325
13326         return -1;
13327 }
13328
13329 static int
13330 ldind_to_load_membase (int opcode)
13331 {
13332         switch (opcode) {
13333         case CEE_LDIND_I1:
13334                 return OP_LOADI1_MEMBASE;
13335         case CEE_LDIND_U1:
13336                 return OP_LOADU1_MEMBASE;
13337         case CEE_LDIND_I2:
13338                 return OP_LOADI2_MEMBASE;
13339         case CEE_LDIND_U2:
13340                 return OP_LOADU2_MEMBASE;
13341         case CEE_LDIND_I4:
13342                 return OP_LOADI4_MEMBASE;
13343         case CEE_LDIND_U4:
13344                 return OP_LOADU4_MEMBASE;
13345         case CEE_LDIND_I:
13346                 return OP_LOAD_MEMBASE;
13347         case CEE_LDIND_REF:
13348                 return OP_LOAD_MEMBASE;
13349         case CEE_LDIND_I8:
13350                 return OP_LOADI8_MEMBASE;
13351         case CEE_LDIND_R4:
13352                 return OP_LOADR4_MEMBASE;
13353         case CEE_LDIND_R8:
13354                 return OP_LOADR8_MEMBASE;
13355         default:
13356                 g_assert_not_reached ();
13357         }
13358
13359         return -1;
13360 }
13361
13362 static int
13363 stind_to_store_membase (int opcode)
13364 {
13365         switch (opcode) {
13366         case CEE_STIND_I1:
13367                 return OP_STOREI1_MEMBASE_REG;
13368         case CEE_STIND_I2:
13369                 return OP_STOREI2_MEMBASE_REG;
13370         case CEE_STIND_I4:
13371                 return OP_STOREI4_MEMBASE_REG;
13372         case CEE_STIND_I:
13373         case CEE_STIND_REF:
13374                 return OP_STORE_MEMBASE_REG;
13375         case CEE_STIND_I8:
13376                 return OP_STOREI8_MEMBASE_REG;
13377         case CEE_STIND_R4:
13378                 return OP_STORER4_MEMBASE_REG;
13379         case CEE_STIND_R8:
13380                 return OP_STORER8_MEMBASE_REG;
13381         default:
13382                 g_assert_not_reached ();
13383         }
13384
13385         return -1;
13386 }
13387
13388 int
13389 mono_load_membase_to_load_mem (int opcode)
13390 {
13391         // FIXME: Add a MONO_ARCH_HAVE_LOAD_MEM macro
13392 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13393         switch (opcode) {
13394         case OP_LOAD_MEMBASE:
13395                 return OP_LOAD_MEM;
13396         case OP_LOADU1_MEMBASE:
13397                 return OP_LOADU1_MEM;
13398         case OP_LOADU2_MEMBASE:
13399                 return OP_LOADU2_MEM;
13400         case OP_LOADI4_MEMBASE:
13401                 return OP_LOADI4_MEM;
13402         case OP_LOADU4_MEMBASE:
13403                 return OP_LOADU4_MEM;
13404 #if SIZEOF_REGISTER == 8
13405         case OP_LOADI8_MEMBASE:
13406                 return OP_LOADI8_MEM;
13407 #endif
13408         }
13409 #endif
13410
13411         return -1;
13412 }
13413
13414 static inline int
13415 op_to_op_dest_membase (int store_opcode, int opcode)
13416 {
13417 #if defined(TARGET_X86)
13418         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG)))
13419                 return -1;
13420
13421         switch (opcode) {
13422         case OP_IADD:
13423                 return OP_X86_ADD_MEMBASE_REG;
13424         case OP_ISUB:
13425                 return OP_X86_SUB_MEMBASE_REG;
13426         case OP_IAND:
13427                 return OP_X86_AND_MEMBASE_REG;
13428         case OP_IOR:
13429                 return OP_X86_OR_MEMBASE_REG;
13430         case OP_IXOR:
13431                 return OP_X86_XOR_MEMBASE_REG;
13432         case OP_ADD_IMM:
13433         case OP_IADD_IMM:
13434                 return OP_X86_ADD_MEMBASE_IMM;
13435         case OP_SUB_IMM:
13436         case OP_ISUB_IMM:
13437                 return OP_X86_SUB_MEMBASE_IMM;
13438         case OP_AND_IMM:
13439         case OP_IAND_IMM:
13440                 return OP_X86_AND_MEMBASE_IMM;
13441         case OP_OR_IMM:
13442         case OP_IOR_IMM:
13443                 return OP_X86_OR_MEMBASE_IMM;
13444         case OP_XOR_IMM:
13445         case OP_IXOR_IMM:
13446                 return OP_X86_XOR_MEMBASE_IMM;
13447         case OP_MOVE:
13448                 return OP_NOP;
13449         }
13450 #endif
13451
13452 #if defined(TARGET_AMD64)
13453         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG) || (store_opcode == OP_STOREI8_MEMBASE_REG)))
13454                 return -1;
13455
13456         switch (opcode) {
13457         case OP_IADD:
13458                 return OP_X86_ADD_MEMBASE_REG;
13459         case OP_ISUB:
13460                 return OP_X86_SUB_MEMBASE_REG;
13461         case OP_IAND:
13462                 return OP_X86_AND_MEMBASE_REG;
13463         case OP_IOR:
13464                 return OP_X86_OR_MEMBASE_REG;
13465         case OP_IXOR:
13466                 return OP_X86_XOR_MEMBASE_REG;
13467         case OP_IADD_IMM:
13468                 return OP_X86_ADD_MEMBASE_IMM;
13469         case OP_ISUB_IMM:
13470                 return OP_X86_SUB_MEMBASE_IMM;
13471         case OP_IAND_IMM:
13472                 return OP_X86_AND_MEMBASE_IMM;
13473         case OP_IOR_IMM:
13474                 return OP_X86_OR_MEMBASE_IMM;
13475         case OP_IXOR_IMM:
13476                 return OP_X86_XOR_MEMBASE_IMM;
13477         case OP_LADD:
13478                 return OP_AMD64_ADD_MEMBASE_REG;
13479         case OP_LSUB:
13480                 return OP_AMD64_SUB_MEMBASE_REG;
13481         case OP_LAND:
13482                 return OP_AMD64_AND_MEMBASE_REG;
13483         case OP_LOR:
13484                 return OP_AMD64_OR_MEMBASE_REG;
13485         case OP_LXOR:
13486                 return OP_AMD64_XOR_MEMBASE_REG;
13487         case OP_ADD_IMM:
13488         case OP_LADD_IMM:
13489                 return OP_AMD64_ADD_MEMBASE_IMM;
13490         case OP_SUB_IMM:
13491         case OP_LSUB_IMM:
13492                 return OP_AMD64_SUB_MEMBASE_IMM;
13493         case OP_AND_IMM:
13494         case OP_LAND_IMM:
13495                 return OP_AMD64_AND_MEMBASE_IMM;
13496         case OP_OR_IMM:
13497         case OP_LOR_IMM:
13498                 return OP_AMD64_OR_MEMBASE_IMM;
13499         case OP_XOR_IMM:
13500         case OP_LXOR_IMM:
13501                 return OP_AMD64_XOR_MEMBASE_IMM;
13502         case OP_MOVE:
13503                 return OP_NOP;
13504         }
13505 #endif
13506
13507         return -1;
13508 }
13509
13510 static inline int
13511 op_to_op_store_membase (int store_opcode, int opcode)
13512 {
13513 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13514         switch (opcode) {
13515         case OP_ICEQ:
13516                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13517                         return OP_X86_SETEQ_MEMBASE;
13518         case OP_CNE:
13519                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13520                         return OP_X86_SETNE_MEMBASE;
13521         }
13522 #endif
13523
13524         return -1;
13525 }
13526
13527 static inline int
13528 op_to_op_src1_membase (MonoCompile *cfg, int load_opcode, int opcode)
13529 {
13530 #ifdef TARGET_X86
13531         /* FIXME: This has sign extension issues */
13532         /*
13533         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
13534                 return OP_X86_COMPARE_MEMBASE8_IMM;
13535         */
13536
13537         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
13538                 return -1;
13539
13540         switch (opcode) {
13541         case OP_X86_PUSH:
13542                 return OP_X86_PUSH_MEMBASE;
13543         case OP_COMPARE_IMM:
13544         case OP_ICOMPARE_IMM:
13545                 return OP_X86_COMPARE_MEMBASE_IMM;
13546         case OP_COMPARE:
13547         case OP_ICOMPARE:
13548                 return OP_X86_COMPARE_MEMBASE_REG;
13549         }
13550 #endif
13551
13552 #ifdef TARGET_AMD64
13553         /* FIXME: This has sign extension issues */
13554         /*
13555         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
13556                 return OP_X86_COMPARE_MEMBASE8_IMM;
13557         */
13558
13559         switch (opcode) {
13560         case OP_X86_PUSH:
13561                 if ((load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32) || (load_opcode == OP_LOADI8_MEMBASE))
13562                         return OP_X86_PUSH_MEMBASE;
13563                 break;
13564                 /* FIXME: This only works for 32 bit immediates
13565         case OP_COMPARE_IMM:
13566         case OP_LCOMPARE_IMM:
13567                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
13568                         return OP_AMD64_COMPARE_MEMBASE_IMM;
13569                 */
13570         case OP_ICOMPARE_IMM:
13571                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
13572                         return OP_AMD64_ICOMPARE_MEMBASE_IMM;
13573                 break;
13574         case OP_COMPARE:
13575         case OP_LCOMPARE:
13576                 if (cfg->backend->ilp32 && load_opcode == OP_LOAD_MEMBASE)
13577                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
13578                 if ((load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32) || (load_opcode == OP_LOADI8_MEMBASE))
13579                         return OP_AMD64_COMPARE_MEMBASE_REG;
13580                 break;
13581         case OP_ICOMPARE:
13582                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
13583                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
13584                 break;
13585         }
13586 #endif
13587
13588         return -1;
13589 }
13590
13591 static inline int
13592 op_to_op_src2_membase (MonoCompile *cfg, int load_opcode, int opcode)
13593 {
13594 #ifdef TARGET_X86
13595         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
13596                 return -1;
13597         
13598         switch (opcode) {
13599         case OP_COMPARE:
13600         case OP_ICOMPARE:
13601                 return OP_X86_COMPARE_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 #endif
13614
13615 #ifdef TARGET_AMD64
13616         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE && cfg->backend->ilp32)) {
13617                 switch (opcode) {
13618                 case OP_ICOMPARE:
13619                         return OP_AMD64_ICOMPARE_REG_MEMBASE;
13620                 case OP_IADD:
13621                         return OP_X86_ADD_REG_MEMBASE;
13622                 case OP_ISUB:
13623                         return OP_X86_SUB_REG_MEMBASE;
13624                 case OP_IAND:
13625                         return OP_X86_AND_REG_MEMBASE;
13626                 case OP_IOR:
13627                         return OP_X86_OR_REG_MEMBASE;
13628                 case OP_IXOR:
13629                         return OP_X86_XOR_REG_MEMBASE;
13630                 }
13631         } else if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32)) {
13632                 switch (opcode) {
13633                 case OP_COMPARE:
13634                 case OP_LCOMPARE:
13635                         return OP_AMD64_COMPARE_REG_MEMBASE;
13636                 case OP_LADD:
13637                         return OP_AMD64_ADD_REG_MEMBASE;
13638                 case OP_LSUB:
13639                         return OP_AMD64_SUB_REG_MEMBASE;
13640                 case OP_LAND:
13641                         return OP_AMD64_AND_REG_MEMBASE;
13642                 case OP_LOR:
13643                         return OP_AMD64_OR_REG_MEMBASE;
13644                 case OP_LXOR:
13645                         return OP_AMD64_XOR_REG_MEMBASE;
13646                 }
13647         }
13648 #endif
13649
13650         return -1;
13651 }
13652
13653 int
13654 mono_op_to_op_imm_noemul (int opcode)
13655 {
13656         switch (opcode) {
13657 #if SIZEOF_REGISTER == 4 && !defined(MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS)
13658         case OP_LSHR:
13659         case OP_LSHL:
13660         case OP_LSHR_UN:
13661                 return -1;
13662 #endif
13663 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
13664         case OP_IDIV:
13665         case OP_IDIV_UN:
13666         case OP_IREM:
13667         case OP_IREM_UN:
13668                 return -1;
13669 #endif
13670 #if defined(MONO_ARCH_EMULATE_MUL_DIV)
13671         case OP_IMUL:
13672                 return -1;
13673 #endif
13674         default:
13675                 return mono_op_to_op_imm (opcode);
13676         }
13677 }
13678
13679 /**
13680  * mono_handle_global_vregs:
13681  *
13682  *   Make vregs used in more than one bblock 'global', i.e. allocate a variable
13683  * for them.
13684  */
13685 void
13686 mono_handle_global_vregs (MonoCompile *cfg)
13687 {
13688         gint32 *vreg_to_bb;
13689         MonoBasicBlock *bb;
13690         int i, pos;
13691
13692         vreg_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (gint32*) * cfg->next_vreg + 1);
13693
13694 #ifdef MONO_ARCH_SIMD_INTRINSICS
13695         if (cfg->uses_simd_intrinsics)
13696                 mono_simd_simplify_indirection (cfg);
13697 #endif
13698
13699         /* Find local vregs used in more than one bb */
13700         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13701                 MonoInst *ins = bb->code;       
13702                 int block_num = bb->block_num;
13703
13704                 if (cfg->verbose_level > 2)
13705                         printf ("\nHANDLE-GLOBAL-VREGS BLOCK %d:\n", bb->block_num);
13706
13707                 cfg->cbb = bb;
13708                 for (; ins; ins = ins->next) {
13709                         const char *spec = INS_INFO (ins->opcode);
13710                         int regtype = 0, regindex;
13711                         gint32 prev_bb;
13712
13713                         if (G_UNLIKELY (cfg->verbose_level > 2))
13714                                 mono_print_ins (ins);
13715
13716                         g_assert (ins->opcode >= MONO_CEE_LAST);
13717
13718                         for (regindex = 0; regindex < 4; regindex ++) {
13719                                 int vreg = 0;
13720
13721                                 if (regindex == 0) {
13722                                         regtype = spec [MONO_INST_DEST];
13723                                         if (regtype == ' ')
13724                                                 continue;
13725                                         vreg = ins->dreg;
13726                                 } else if (regindex == 1) {
13727                                         regtype = spec [MONO_INST_SRC1];
13728                                         if (regtype == ' ')
13729                                                 continue;
13730                                         vreg = ins->sreg1;
13731                                 } else if (regindex == 2) {
13732                                         regtype = spec [MONO_INST_SRC2];
13733                                         if (regtype == ' ')
13734                                                 continue;
13735                                         vreg = ins->sreg2;
13736                                 } else if (regindex == 3) {
13737                                         regtype = spec [MONO_INST_SRC3];
13738                                         if (regtype == ' ')
13739                                                 continue;
13740                                         vreg = ins->sreg3;
13741                                 }
13742
13743 #if SIZEOF_REGISTER == 4
13744                                 /* In the LLVM case, the long opcodes are not decomposed */
13745                                 if (regtype == 'l' && !COMPILE_LLVM (cfg)) {
13746                                         /*
13747                                          * Since some instructions reference the original long vreg,
13748                                          * and some reference the two component vregs, it is quite hard
13749                                          * to determine when it needs to be global. So be conservative.
13750                                          */
13751                                         if (!get_vreg_to_inst (cfg, vreg)) {
13752                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
13753
13754                                                 if (cfg->verbose_level > 2)
13755                                                         printf ("LONG VREG R%d made global.\n", vreg);
13756                                         }
13757
13758                                         /*
13759                                          * Make the component vregs volatile since the optimizations can
13760                                          * get confused otherwise.
13761                                          */
13762                                         get_vreg_to_inst (cfg, vreg + 1)->flags |= MONO_INST_VOLATILE;
13763                                         get_vreg_to_inst (cfg, vreg + 2)->flags |= MONO_INST_VOLATILE;
13764                                 }
13765 #endif
13766
13767                                 g_assert (vreg != -1);
13768
13769                                 prev_bb = vreg_to_bb [vreg];
13770                                 if (prev_bb == 0) {
13771                                         /* 0 is a valid block num */
13772                                         vreg_to_bb [vreg] = block_num + 1;
13773                                 } else if ((prev_bb != block_num + 1) && (prev_bb != -1)) {
13774                                         if (((regtype == 'i' && (vreg < MONO_MAX_IREGS))) || (regtype == 'f' && (vreg < MONO_MAX_FREGS)))
13775                                                 continue;
13776
13777                                         if (!get_vreg_to_inst (cfg, vreg)) {
13778                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
13779                                                         printf ("VREG R%d used in BB%d and BB%d made global.\n", vreg, vreg_to_bb [vreg], block_num);
13780
13781                                                 switch (regtype) {
13782                                                 case 'i':
13783                                                         if (vreg_is_ref (cfg, vreg))
13784                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL, vreg);
13785                                                         else
13786                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL, vreg);
13787                                                         break;
13788                                                 case 'l':
13789                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
13790                                                         break;
13791                                                 case 'f':
13792                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL, vreg);
13793                                                         break;
13794                                                 case 'v':
13795                                                         mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, vreg);
13796                                                         break;
13797                                                 default:
13798                                                         g_assert_not_reached ();
13799                                                 }
13800                                         }
13801
13802                                         /* Flag as having been used in more than one bb */
13803                                         vreg_to_bb [vreg] = -1;
13804                                 }
13805                         }
13806                 }
13807         }
13808
13809         /* If a variable is used in only one bblock, convert it into a local vreg */
13810         for (i = 0; i < cfg->num_varinfo; i++) {
13811                 MonoInst *var = cfg->varinfo [i];
13812                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
13813
13814                 switch (var->type) {
13815                 case STACK_I4:
13816                 case STACK_OBJ:
13817                 case STACK_PTR:
13818                 case STACK_MP:
13819                 case STACK_VTYPE:
13820 #if SIZEOF_REGISTER == 8
13821                 case STACK_I8:
13822 #endif
13823 #if !defined(TARGET_X86)
13824                 /* Enabling this screws up the fp stack on x86 */
13825                 case STACK_R8:
13826 #endif
13827                         if (mono_arch_is_soft_float ())
13828                                 break;
13829
13830                         /* Arguments are implicitly global */
13831                         /* Putting R4 vars into registers doesn't work currently */
13832                         /* The gsharedvt vars are implicitly referenced by ldaddr opcodes, but those opcodes are only generated later */
13833                         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) {
13834                                 /* 
13835                                  * Make that the variable's liveness interval doesn't contain a call, since
13836                                  * that would cause the lvreg to be spilled, making the whole optimization
13837                                  * useless.
13838                                  */
13839                                 /* This is too slow for JIT compilation */
13840 #if 0
13841                                 if (cfg->compile_aot && vreg_to_bb [var->dreg]) {
13842                                         MonoInst *ins;
13843                                         int def_index, call_index, ins_index;
13844                                         gboolean spilled = FALSE;
13845
13846                                         def_index = -1;
13847                                         call_index = -1;
13848                                         ins_index = 0;
13849                                         for (ins = vreg_to_bb [var->dreg]->code; ins; ins = ins->next) {
13850                                                 const char *spec = INS_INFO (ins->opcode);
13851
13852                                                 if ((spec [MONO_INST_DEST] != ' ') && (ins->dreg == var->dreg))
13853                                                         def_index = ins_index;
13854
13855                                                 if (((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg)) ||
13856                                                         ((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg))) {
13857                                                         if (call_index > def_index) {
13858                                                                 spilled = TRUE;
13859                                                                 break;
13860                                                         }
13861                                                 }
13862
13863                                                 if (MONO_IS_CALL (ins))
13864                                                         call_index = ins_index;
13865
13866                                                 ins_index ++;
13867                                         }
13868
13869                                         if (spilled)
13870                                                 break;
13871                                 }
13872 #endif
13873
13874                                 if (G_UNLIKELY (cfg->verbose_level > 2))
13875                                         printf ("CONVERTED R%d(%d) TO VREG.\n", var->dreg, vmv->idx);
13876                                 var->flags |= MONO_INST_IS_DEAD;
13877                                 cfg->vreg_to_inst [var->dreg] = NULL;
13878                         }
13879                         break;
13880                 }
13881         }
13882
13883         /* 
13884          * Compress the varinfo and vars tables so the liveness computation is faster and
13885          * takes up less space.
13886          */
13887         pos = 0;
13888         for (i = 0; i < cfg->num_varinfo; ++i) {
13889                 MonoInst *var = cfg->varinfo [i];
13890                 if (pos < i && cfg->locals_start == i)
13891                         cfg->locals_start = pos;
13892                 if (!(var->flags & MONO_INST_IS_DEAD)) {
13893                         if (pos < i) {
13894                                 cfg->varinfo [pos] = cfg->varinfo [i];
13895                                 cfg->varinfo [pos]->inst_c0 = pos;
13896                                 memcpy (&cfg->vars [pos], &cfg->vars [i], sizeof (MonoMethodVar));
13897                                 cfg->vars [pos].idx = pos;
13898 #if SIZEOF_REGISTER == 4
13899                                 if (cfg->varinfo [pos]->type == STACK_I8) {
13900                                         /* Modify the two component vars too */
13901                                         MonoInst *var1;
13902
13903                                         var1 = get_vreg_to_inst (cfg, cfg->varinfo [pos]->dreg + 1);
13904                                         var1->inst_c0 = pos;
13905                                         var1 = get_vreg_to_inst (cfg, cfg->varinfo [pos]->dreg + 2);
13906                                         var1->inst_c0 = pos;
13907                                 }
13908 #endif
13909                         }
13910                         pos ++;
13911                 }
13912         }
13913         cfg->num_varinfo = pos;
13914         if (cfg->locals_start > cfg->num_varinfo)
13915                 cfg->locals_start = cfg->num_varinfo;
13916 }
13917
13918 /**
13919  * mono_spill_global_vars:
13920  *
13921  *   Generate spill code for variables which are not allocated to registers, 
13922  * and replace vregs with their allocated hregs. *need_local_opts is set to TRUE if
13923  * code is generated which could be optimized by the local optimization passes.
13924  */
13925 void
13926 mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
13927 {
13928         MonoBasicBlock *bb;
13929         char spec2 [16];
13930         int orig_next_vreg;
13931         guint32 *vreg_to_lvreg;
13932         guint32 *lvregs;
13933         guint32 i, lvregs_len;
13934         gboolean dest_has_lvreg = FALSE;
13935         guint32 stacktypes [128];
13936         MonoInst **live_range_start, **live_range_end;
13937         MonoBasicBlock **live_range_start_bb, **live_range_end_bb;
13938         int *gsharedvt_vreg_to_idx = NULL;
13939
13940         *need_local_opts = FALSE;
13941
13942         memset (spec2, 0, sizeof (spec2));
13943
13944         /* FIXME: Move this function to mini.c */
13945         stacktypes ['i'] = STACK_PTR;
13946         stacktypes ['l'] = STACK_I8;
13947         stacktypes ['f'] = STACK_R8;
13948 #ifdef MONO_ARCH_SIMD_INTRINSICS
13949         stacktypes ['x'] = STACK_VTYPE;
13950 #endif
13951
13952 #if SIZEOF_REGISTER == 4
13953         /* Create MonoInsts for longs */
13954         for (i = 0; i < cfg->num_varinfo; i++) {
13955                 MonoInst *ins = cfg->varinfo [i];
13956
13957                 if ((ins->opcode != OP_REGVAR) && !(ins->flags & MONO_INST_IS_DEAD)) {
13958                         switch (ins->type) {
13959                         case STACK_R8:
13960                         case STACK_I8: {
13961                                 MonoInst *tree;
13962
13963                                 if (ins->type == STACK_R8 && !COMPILE_SOFT_FLOAT (cfg))
13964                                         break;
13965
13966                                 g_assert (ins->opcode == OP_REGOFFSET);
13967
13968                                 tree = get_vreg_to_inst (cfg, ins->dreg + 1);
13969                                 g_assert (tree);
13970                                 tree->opcode = OP_REGOFFSET;
13971                                 tree->inst_basereg = ins->inst_basereg;
13972                                 tree->inst_offset = ins->inst_offset + MINI_LS_WORD_OFFSET;
13973
13974                                 tree = get_vreg_to_inst (cfg, ins->dreg + 2);
13975                                 g_assert (tree);
13976                                 tree->opcode = OP_REGOFFSET;
13977                                 tree->inst_basereg = ins->inst_basereg;
13978                                 tree->inst_offset = ins->inst_offset + MINI_MS_WORD_OFFSET;
13979                                 break;
13980                         }
13981                         default:
13982                                 break;
13983                         }
13984                 }
13985         }
13986 #endif
13987
13988         if (cfg->compute_gc_maps) {
13989                 /* registers need liveness info even for !non refs */
13990                 for (i = 0; i < cfg->num_varinfo; i++) {
13991                         MonoInst *ins = cfg->varinfo [i];
13992
13993                         if (ins->opcode == OP_REGVAR)
13994                                 ins->flags |= MONO_INST_GC_TRACK;
13995                 }
13996         }
13997
13998         if (cfg->gsharedvt) {
13999                 gsharedvt_vreg_to_idx = mono_mempool_alloc0 (cfg->mempool, sizeof (int) * cfg->next_vreg);
14000
14001                 for (i = 0; i < cfg->num_varinfo; ++i) {
14002                         MonoInst *ins = cfg->varinfo [i];
14003                         int idx;
14004
14005                         if (mini_is_gsharedvt_variable_type (ins->inst_vtype)) {
14006                                 if (i >= cfg->locals_start) {
14007                                         /* Local */
14008                                         idx = get_gsharedvt_info_slot (cfg, ins->inst_vtype, MONO_RGCTX_INFO_LOCAL_OFFSET);
14009                                         gsharedvt_vreg_to_idx [ins->dreg] = idx + 1;
14010                                         ins->opcode = OP_GSHAREDVT_LOCAL;
14011                                         ins->inst_imm = idx;
14012                                 } else {
14013                                         /* Arg */
14014                                         gsharedvt_vreg_to_idx [ins->dreg] = -1;
14015                                         ins->opcode = OP_GSHAREDVT_ARG_REGOFFSET;
14016                                 }
14017                         }
14018                 }
14019         }
14020                 
14021         /* FIXME: widening and truncation */
14022
14023         /*
14024          * As an optimization, when a variable allocated to the stack is first loaded into 
14025          * an lvreg, we will remember the lvreg and use it the next time instead of loading
14026          * the variable again.
14027          */
14028         orig_next_vreg = cfg->next_vreg;
14029         vreg_to_lvreg = mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * cfg->next_vreg);
14030         lvregs = mono_mempool_alloc (cfg->mempool, sizeof (guint32) * 1024);
14031         lvregs_len = 0;
14032
14033         /* 
14034          * These arrays contain the first and last instructions accessing a given
14035          * variable.
14036          * Since we emit bblocks in the same order we process them here, and we
14037          * don't split live ranges, these will precisely describe the live range of
14038          * the variable, i.e. the instruction range where a valid value can be found
14039          * in the variables location.
14040          * The live range is computed using the liveness info computed by the liveness pass.
14041          * We can't use vmv->range, since that is an abstract live range, and we need
14042          * one which is instruction precise.
14043          * FIXME: Variables used in out-of-line bblocks have a hole in their live range.
14044          */
14045         /* FIXME: Only do this if debugging info is requested */
14046         live_range_start = g_new0 (MonoInst*, cfg->next_vreg);
14047         live_range_end = g_new0 (MonoInst*, cfg->next_vreg);
14048         live_range_start_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
14049         live_range_end_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
14050         
14051         /* Add spill loads/stores */
14052         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
14053                 MonoInst *ins;
14054
14055                 if (cfg->verbose_level > 2)
14056                         printf ("\nSPILL BLOCK %d:\n", bb->block_num);
14057
14058                 /* Clear vreg_to_lvreg array */
14059                 for (i = 0; i < lvregs_len; i++)
14060                         vreg_to_lvreg [lvregs [i]] = 0;
14061                 lvregs_len = 0;
14062
14063                 cfg->cbb = bb;
14064                 MONO_BB_FOR_EACH_INS (bb, ins) {
14065                         const char *spec = INS_INFO (ins->opcode);
14066                         int regtype, srcindex, sreg, tmp_reg, prev_dreg, num_sregs;
14067                         gboolean store, no_lvreg;
14068                         int sregs [MONO_MAX_SRC_REGS];
14069
14070                         if (G_UNLIKELY (cfg->verbose_level > 2))
14071                                 mono_print_ins (ins);
14072
14073                         if (ins->opcode == OP_NOP)
14074                                 continue;
14075
14076                         /* 
14077                          * We handle LDADDR here as well, since it can only be decomposed
14078                          * when variable addresses are known.
14079                          */
14080                         if (ins->opcode == OP_LDADDR) {
14081                                 MonoInst *var = ins->inst_p0;
14082
14083                                 if (var->opcode == OP_VTARG_ADDR) {
14084                                         /* Happens on SPARC/S390 where vtypes are passed by reference */
14085                                         MonoInst *vtaddr = var->inst_left;
14086                                         if (vtaddr->opcode == OP_REGVAR) {
14087                                                 ins->opcode = OP_MOVE;
14088                                                 ins->sreg1 = vtaddr->dreg;
14089                                         }
14090                                         else if (var->inst_left->opcode == OP_REGOFFSET) {
14091                                                 ins->opcode = OP_LOAD_MEMBASE;
14092                                                 ins->inst_basereg = vtaddr->inst_basereg;
14093                                                 ins->inst_offset = vtaddr->inst_offset;
14094                                         } else
14095                                                 NOT_IMPLEMENTED;
14096                                 } else if (cfg->gsharedvt && gsharedvt_vreg_to_idx [var->dreg] < 0) {
14097                                         /* gsharedvt arg passed by ref */
14098                                         g_assert (var->opcode == OP_GSHAREDVT_ARG_REGOFFSET);
14099
14100                                         ins->opcode = OP_LOAD_MEMBASE;
14101                                         ins->inst_basereg = var->inst_basereg;
14102                                         ins->inst_offset = var->inst_offset;
14103                                 } else if (cfg->gsharedvt && gsharedvt_vreg_to_idx [var->dreg]) {
14104                                         MonoInst *load, *load2, *load3;
14105                                         int idx = gsharedvt_vreg_to_idx [var->dreg] - 1;
14106                                         int reg1, reg2, reg3;
14107                                         MonoInst *info_var = cfg->gsharedvt_info_var;
14108                                         MonoInst *locals_var = cfg->gsharedvt_locals_var;
14109
14110                                         /*
14111                                          * gsharedvt local.
14112                                          * Compute the address of the local as gsharedvt_locals_var + gsharedvt_info_var->locals_offsets [idx].
14113                                          */
14114
14115                                         g_assert (var->opcode == OP_GSHAREDVT_LOCAL);
14116
14117                                         g_assert (info_var);
14118                                         g_assert (locals_var);
14119
14120                                         /* Mark the instruction used to compute the locals var as used */
14121                                         cfg->gsharedvt_locals_var_ins = NULL;
14122
14123                                         /* Load the offset */
14124                                         if (info_var->opcode == OP_REGOFFSET) {
14125                                                 reg1 = alloc_ireg (cfg);
14126                                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, reg1, info_var->inst_basereg, info_var->inst_offset);
14127                                         } else if (info_var->opcode == OP_REGVAR) {
14128                                                 load = NULL;
14129                                                 reg1 = info_var->dreg;
14130                                         } else {
14131                                                 g_assert_not_reached ();
14132                                         }
14133                                         reg2 = alloc_ireg (cfg);
14134                                         NEW_LOAD_MEMBASE (cfg, load2, OP_LOADI4_MEMBASE, reg2, reg1, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
14135                                         /* Load the locals area address */
14136                                         reg3 = alloc_ireg (cfg);
14137                                         if (locals_var->opcode == OP_REGOFFSET) {
14138                                                 NEW_LOAD_MEMBASE (cfg, load3, OP_LOAD_MEMBASE, reg3, locals_var->inst_basereg, locals_var->inst_offset);
14139                                         } else if (locals_var->opcode == OP_REGVAR) {
14140                                                 NEW_UNALU (cfg, load3, OP_MOVE, reg3, locals_var->dreg);
14141                                         } else {
14142                                                 g_assert_not_reached ();
14143                                         }
14144                                         /* Compute the address */
14145                                         ins->opcode = OP_PADD;
14146                                         ins->sreg1 = reg3;
14147                                         ins->sreg2 = reg2;
14148
14149                                         mono_bblock_insert_before_ins (bb, ins, load3);
14150                                         mono_bblock_insert_before_ins (bb, load3, load2);
14151                                         if (load)
14152                                                 mono_bblock_insert_before_ins (bb, load2, load);
14153                                 } else {
14154                                         g_assert (var->opcode == OP_REGOFFSET);
14155
14156                                         ins->opcode = OP_ADD_IMM;
14157                                         ins->sreg1 = var->inst_basereg;
14158                                         ins->inst_imm = var->inst_offset;
14159                                 }
14160
14161                                 *need_local_opts = TRUE;
14162                                 spec = INS_INFO (ins->opcode);
14163                         }
14164
14165                         if (ins->opcode < MONO_CEE_LAST) {
14166                                 mono_print_ins (ins);
14167                                 g_assert_not_reached ();
14168                         }
14169
14170                         /*
14171                          * Store opcodes have destbasereg in the dreg, but in reality, it is an
14172                          * src register.
14173                          * FIXME:
14174                          */
14175                         if (MONO_IS_STORE_MEMBASE (ins)) {
14176                                 tmp_reg = ins->dreg;
14177                                 ins->dreg = ins->sreg2;
14178                                 ins->sreg2 = tmp_reg;
14179                                 store = TRUE;
14180
14181                                 spec2 [MONO_INST_DEST] = ' ';
14182                                 spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14183                                 spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14184                                 spec2 [MONO_INST_SRC3] = ' ';
14185                                 spec = spec2;
14186                         } else if (MONO_IS_STORE_MEMINDEX (ins))
14187                                 g_assert_not_reached ();
14188                         else
14189                                 store = FALSE;
14190                         no_lvreg = FALSE;
14191
14192                         if (G_UNLIKELY (cfg->verbose_level > 2)) {
14193                                 printf ("\t %.3s %d", spec, ins->dreg);
14194                                 num_sregs = mono_inst_get_src_registers (ins, sregs);
14195                                 for (srcindex = 0; srcindex < num_sregs; ++srcindex)
14196                                         printf (" %d", sregs [srcindex]);
14197                                 printf ("\n");
14198                         }
14199
14200                         /***************/
14201                         /*    DREG     */
14202                         /***************/
14203                         regtype = spec [MONO_INST_DEST];
14204                         g_assert (((ins->dreg == -1) && (regtype == ' ')) || ((ins->dreg != -1) && (regtype != ' ')));
14205                         prev_dreg = -1;
14206
14207                         if ((ins->dreg != -1) && get_vreg_to_inst (cfg, ins->dreg)) {
14208                                 MonoInst *var = get_vreg_to_inst (cfg, ins->dreg);
14209                                 MonoInst *store_ins;
14210                                 int store_opcode;
14211                                 MonoInst *def_ins = ins;
14212                                 int dreg = ins->dreg; /* The original vreg */
14213
14214                                 store_opcode = mono_type_to_store_membase (cfg, var->inst_vtype);
14215
14216                                 if (var->opcode == OP_REGVAR) {
14217                                         ins->dreg = var->dreg;
14218                                 } 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)) {
14219                                         /* 
14220                                          * Instead of emitting a load+store, use a _membase opcode.
14221                                          */
14222                                         g_assert (var->opcode == OP_REGOFFSET);
14223                                         if (ins->opcode == OP_MOVE) {
14224                                                 NULLIFY_INS (ins);
14225                                                 def_ins = NULL;
14226                                         } else {
14227                                                 ins->opcode = op_to_op_dest_membase (store_opcode, ins->opcode);
14228                                                 ins->inst_basereg = var->inst_basereg;
14229                                                 ins->inst_offset = var->inst_offset;
14230                                                 ins->dreg = -1;
14231                                         }
14232                                         spec = INS_INFO (ins->opcode);
14233                                 } else {
14234                                         guint32 lvreg;
14235
14236                                         g_assert (var->opcode == OP_REGOFFSET);
14237
14238                                         prev_dreg = ins->dreg;
14239
14240                                         /* Invalidate any previous lvreg for this vreg */
14241                                         vreg_to_lvreg [ins->dreg] = 0;
14242
14243                                         lvreg = 0;
14244
14245                                         if (COMPILE_SOFT_FLOAT (cfg) && store_opcode == OP_STORER8_MEMBASE_REG) {
14246                                                 regtype = 'l';
14247                                                 store_opcode = OP_STOREI8_MEMBASE_REG;
14248                                         }
14249
14250                                         ins->dreg = alloc_dreg (cfg, stacktypes [regtype]);
14251
14252 #if SIZEOF_REGISTER != 8
14253                                         if (regtype == 'l') {
14254                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET, ins->dreg + 1);
14255                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14256                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET, ins->dreg + 2);
14257                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14258                                                 def_ins = store_ins;
14259                                         }
14260                                         else
14261 #endif
14262                                         {
14263                                                 g_assert (store_opcode != OP_STOREV_MEMBASE);
14264
14265                                                 /* Try to fuse the store into the instruction itself */
14266                                                 /* FIXME: Add more instructions */
14267                                                 if (!lvreg && ((ins->opcode == OP_ICONST) || ((ins->opcode == OP_I8CONST) && (ins->inst_c0 == 0)))) {
14268                                                         ins->opcode = store_membase_reg_to_store_membase_imm (store_opcode);
14269                                                         ins->inst_imm = ins->inst_c0;
14270                                                         ins->inst_destbasereg = var->inst_basereg;
14271                                                         ins->inst_offset = var->inst_offset;
14272                                                         spec = INS_INFO (ins->opcode);
14273                                                 } else if (!lvreg && ((ins->opcode == OP_MOVE) || (ins->opcode == OP_FMOVE) || (ins->opcode == OP_LMOVE) || (ins->opcode == OP_RMOVE))) {
14274                                                         ins->opcode = store_opcode;
14275                                                         ins->inst_destbasereg = var->inst_basereg;
14276                                                         ins->inst_offset = var->inst_offset;
14277
14278                                                         no_lvreg = TRUE;
14279
14280                                                         tmp_reg = ins->dreg;
14281                                                         ins->dreg = ins->sreg2;
14282                                                         ins->sreg2 = tmp_reg;
14283                                                         store = TRUE;
14284
14285                                                         spec2 [MONO_INST_DEST] = ' ';
14286                                                         spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14287                                                         spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14288                                                         spec2 [MONO_INST_SRC3] = ' ';
14289                                                         spec = spec2;
14290                                                 } else if (!lvreg && (op_to_op_store_membase (store_opcode, ins->opcode) != -1)) {
14291                                                         // FIXME: The backends expect the base reg to be in inst_basereg
14292                                                         ins->opcode = op_to_op_store_membase (store_opcode, ins->opcode);
14293                                                         ins->dreg = -1;
14294                                                         ins->inst_basereg = var->inst_basereg;
14295                                                         ins->inst_offset = var->inst_offset;
14296                                                         spec = INS_INFO (ins->opcode);
14297                                                 } else {
14298                                                         /* printf ("INS: "); mono_print_ins (ins); */
14299                                                         /* Create a store instruction */
14300                                                         NEW_STORE_MEMBASE (cfg, store_ins, store_opcode, var->inst_basereg, var->inst_offset, ins->dreg);
14301
14302                                                         /* Insert it after the instruction */
14303                                                         mono_bblock_insert_after_ins (bb, ins, store_ins);
14304
14305                                                         def_ins = store_ins;
14306
14307                                                         /* 
14308                                                          * We can't assign ins->dreg to var->dreg here, since the
14309                                                          * sregs could use it. So set a flag, and do it after
14310                                                          * the sregs.
14311                                                          */
14312                                                         if ((!cfg->backend->use_fpstack || ((store_opcode != OP_STORER8_MEMBASE_REG) && (store_opcode != OP_STORER4_MEMBASE_REG))) && !((var)->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT)))
14313                                                                 dest_has_lvreg = TRUE;
14314                                                 }
14315                                         }
14316                                 }
14317
14318                                 if (def_ins && !live_range_start [dreg]) {
14319                                         live_range_start [dreg] = def_ins;
14320                                         live_range_start_bb [dreg] = bb;
14321                                 }
14322
14323                                 if (cfg->compute_gc_maps && def_ins && (var->flags & MONO_INST_GC_TRACK)) {
14324                                         MonoInst *tmp;
14325
14326                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
14327                                         tmp->inst_c1 = dreg;
14328                                         mono_bblock_insert_after_ins (bb, def_ins, tmp);
14329                                 }
14330                         }
14331
14332                         /************/
14333                         /*  SREGS   */
14334                         /************/
14335                         num_sregs = mono_inst_get_src_registers (ins, sregs);
14336                         for (srcindex = 0; srcindex < 3; ++srcindex) {
14337                                 regtype = spec [MONO_INST_SRC1 + srcindex];
14338                                 sreg = sregs [srcindex];
14339
14340                                 g_assert (((sreg == -1) && (regtype == ' ')) || ((sreg != -1) && (regtype != ' ')));
14341                                 if ((sreg != -1) && get_vreg_to_inst (cfg, sreg)) {
14342                                         MonoInst *var = get_vreg_to_inst (cfg, sreg);
14343                                         MonoInst *use_ins = ins;
14344                                         MonoInst *load_ins;
14345                                         guint32 load_opcode;
14346
14347                                         if (var->opcode == OP_REGVAR) {
14348                                                 sregs [srcindex] = var->dreg;
14349                                                 //mono_inst_set_src_registers (ins, sregs);
14350                                                 live_range_end [sreg] = use_ins;
14351                                                 live_range_end_bb [sreg] = bb;
14352
14353                                                 if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14354                                                         MonoInst *tmp;
14355
14356                                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14357                                                         /* var->dreg is a hreg */
14358                                                         tmp->inst_c1 = sreg;
14359                                                         mono_bblock_insert_after_ins (bb, ins, tmp);
14360                                                 }
14361
14362                                                 continue;
14363                                         }
14364
14365                                         g_assert (var->opcode == OP_REGOFFSET);
14366                                                 
14367                                         load_opcode = mono_type_to_load_membase (cfg, var->inst_vtype);
14368
14369                                         g_assert (load_opcode != OP_LOADV_MEMBASE);
14370
14371                                         if (vreg_to_lvreg [sreg]) {
14372                                                 g_assert (vreg_to_lvreg [sreg] != -1);
14373
14374                                                 /* The variable is already loaded to an lvreg */
14375                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
14376                                                         printf ("\t\tUse lvreg R%d for R%d.\n", vreg_to_lvreg [sreg], sreg);
14377                                                 sregs [srcindex] = vreg_to_lvreg [sreg];
14378                                                 //mono_inst_set_src_registers (ins, sregs);
14379                                                 continue;
14380                                         }
14381
14382                                         /* Try to fuse the load into the instruction */
14383                                         if ((srcindex == 0) && (op_to_op_src1_membase (cfg, load_opcode, ins->opcode) != -1)) {
14384                                                 ins->opcode = op_to_op_src1_membase (cfg, load_opcode, ins->opcode);
14385                                                 sregs [0] = var->inst_basereg;
14386                                                 //mono_inst_set_src_registers (ins, sregs);
14387                                                 ins->inst_offset = var->inst_offset;
14388                                         } else if ((srcindex == 1) && (op_to_op_src2_membase (cfg, load_opcode, ins->opcode) != -1)) {
14389                                                 ins->opcode = op_to_op_src2_membase (cfg, load_opcode, ins->opcode);
14390                                                 sregs [1] = var->inst_basereg;
14391                                                 //mono_inst_set_src_registers (ins, sregs);
14392                                                 ins->inst_offset = var->inst_offset;
14393                                         } else {
14394                                                 if (MONO_IS_REAL_MOVE (ins)) {
14395                                                         ins->opcode = OP_NOP;
14396                                                         sreg = ins->dreg;
14397                                                 } else {
14398                                                         //printf ("%d ", srcindex); mono_print_ins (ins);
14399
14400                                                         sreg = alloc_dreg (cfg, stacktypes [regtype]);
14401
14402                                                         if ((!cfg->backend->use_fpstack || ((load_opcode != OP_LOADR8_MEMBASE) && (load_opcode != OP_LOADR4_MEMBASE))) && !((var)->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT)) && !no_lvreg) {
14403                                                                 if (var->dreg == prev_dreg) {
14404                                                                         /*
14405                                                                          * sreg refers to the value loaded by the load
14406                                                                          * emitted below, but we need to use ins->dreg
14407                                                                          * since it refers to the store emitted earlier.
14408                                                                          */
14409                                                                         sreg = ins->dreg;
14410                                                                 }
14411                                                                 g_assert (sreg != -1);
14412                                                                 vreg_to_lvreg [var->dreg] = sreg;
14413                                                                 g_assert (lvregs_len < 1024);
14414                                                                 lvregs [lvregs_len ++] = var->dreg;
14415                                                         }
14416                                                 }
14417
14418                                                 sregs [srcindex] = sreg;
14419                                                 //mono_inst_set_src_registers (ins, sregs);
14420
14421 #if SIZEOF_REGISTER != 8
14422                                                 if (regtype == 'l') {
14423                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 2, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET);
14424                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14425                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 1, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET);
14426                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14427                                                         use_ins = load_ins;
14428                                                 }
14429                                                 else
14430 #endif
14431                                                 {
14432 #if SIZEOF_REGISTER == 4
14433                                                         g_assert (load_opcode != OP_LOADI8_MEMBASE);
14434 #endif
14435                                                         NEW_LOAD_MEMBASE (cfg, load_ins, load_opcode, sreg, var->inst_basereg, var->inst_offset);
14436                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14437                                                         use_ins = load_ins;
14438                                                 }
14439                                         }
14440
14441                                         if (var->dreg < orig_next_vreg) {
14442                                                 live_range_end [var->dreg] = use_ins;
14443                                                 live_range_end_bb [var->dreg] = bb;
14444                                         }
14445
14446                                         if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14447                                                 MonoInst *tmp;
14448
14449                                                 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14450                                                 tmp->inst_c1 = var->dreg;
14451                                                 mono_bblock_insert_after_ins (bb, ins, tmp);
14452                                         }
14453                                 }
14454                         }
14455                         mono_inst_set_src_registers (ins, sregs);
14456
14457                         if (dest_has_lvreg) {
14458                                 g_assert (ins->dreg != -1);
14459                                 vreg_to_lvreg [prev_dreg] = ins->dreg;
14460                                 g_assert (lvregs_len < 1024);
14461                                 lvregs [lvregs_len ++] = prev_dreg;
14462                                 dest_has_lvreg = FALSE;
14463                         }
14464
14465                         if (store) {
14466                                 tmp_reg = ins->dreg;
14467                                 ins->dreg = ins->sreg2;
14468                                 ins->sreg2 = tmp_reg;
14469                         }
14470
14471                         if (MONO_IS_CALL (ins)) {
14472                                 /* Clear vreg_to_lvreg array */
14473                                 for (i = 0; i < lvregs_len; i++)
14474                                         vreg_to_lvreg [lvregs [i]] = 0;
14475                                 lvregs_len = 0;
14476                         } else if (ins->opcode == OP_NOP) {
14477                                 ins->dreg = -1;
14478                                 MONO_INST_NULLIFY_SREGS (ins);
14479                         }
14480
14481                         if (cfg->verbose_level > 2)
14482                                 mono_print_ins_index (1, ins);
14483                 }
14484
14485                 /* Extend the live range based on the liveness info */
14486                 if (cfg->compute_precise_live_ranges && bb->live_out_set && bb->code) {
14487                         for (i = 0; i < cfg->num_varinfo; i ++) {
14488                                 MonoMethodVar *vi = MONO_VARINFO (cfg, i);
14489
14490                                 if (vreg_is_volatile (cfg, vi->vreg))
14491                                         /* The liveness info is incomplete */
14492                                         continue;
14493
14494                                 if (mono_bitset_test_fast (bb->live_in_set, i) && !live_range_start [vi->vreg]) {
14495                                         /* Live from at least the first ins of this bb */
14496                                         live_range_start [vi->vreg] = bb->code;
14497                                         live_range_start_bb [vi->vreg] = bb;
14498                                 }
14499
14500                                 if (mono_bitset_test_fast (bb->live_out_set, i)) {
14501                                         /* Live at least until the last ins of this bb */
14502                                         live_range_end [vi->vreg] = bb->last_ins;
14503                                         live_range_end_bb [vi->vreg] = bb;
14504                                 }
14505                         }
14506                 }
14507         }
14508         
14509         /*
14510          * Emit LIVERANGE_START/LIVERANGE_END opcodes, the backend will implement them
14511          * by storing the current native offset into MonoMethodVar->live_range_start/end.
14512          */
14513         if (cfg->backend->have_liverange_ops && cfg->compute_precise_live_ranges && cfg->comp_done & MONO_COMP_LIVENESS) {
14514                 for (i = 0; i < cfg->num_varinfo; ++i) {
14515                         int vreg = MONO_VARINFO (cfg, i)->vreg;
14516                         MonoInst *ins;
14517
14518                         if (live_range_start [vreg]) {
14519                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_START);
14520                                 ins->inst_c0 = i;
14521                                 ins->inst_c1 = vreg;
14522                                 mono_bblock_insert_after_ins (live_range_start_bb [vreg], live_range_start [vreg], ins);
14523                         }
14524                         if (live_range_end [vreg]) {
14525                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_END);
14526                                 ins->inst_c0 = i;
14527                                 ins->inst_c1 = vreg;
14528                                 if (live_range_end [vreg] == live_range_end_bb [vreg]->last_ins)
14529                                         mono_add_ins_to_end (live_range_end_bb [vreg], ins);
14530                                 else
14531                                         mono_bblock_insert_after_ins (live_range_end_bb [vreg], live_range_end [vreg], ins);
14532                         }
14533                 }
14534         }
14535
14536         if (cfg->gsharedvt_locals_var_ins) {
14537                 /* Nullify if unused */
14538                 cfg->gsharedvt_locals_var_ins->opcode = OP_PCONST;
14539                 cfg->gsharedvt_locals_var_ins->inst_imm = 0;
14540         }
14541
14542         g_free (live_range_start);
14543         g_free (live_range_end);
14544         g_free (live_range_start_bb);
14545         g_free (live_range_end_bb);
14546 }
14547
14548 /**
14549  * FIXME:
14550  * - use 'iadd' instead of 'int_add'
14551  * - handling ovf opcodes: decompose in method_to_ir.
14552  * - unify iregs/fregs
14553  *   -> partly done, the missing parts are:
14554  *   - a more complete unification would involve unifying the hregs as well, so
14555  *     code wouldn't need if (fp) all over the place. but that would mean the hregs
14556  *     would no longer map to the machine hregs, so the code generators would need to
14557  *     be modified. Also, on ia64 for example, niregs + nfregs > 256 -> bitmasks
14558  *     wouldn't work any more. Duplicating the code in mono_local_regalloc () into
14559  *     fp/non-fp branches speeds it up by about 15%.
14560  * - use sext/zext opcodes instead of shifts
14561  * - add OP_ICALL
14562  * - get rid of TEMPLOADs if possible and use vregs instead
14563  * - clean up usage of OP_P/OP_ opcodes
14564  * - cleanup usage of DUMMY_USE
14565  * - cleanup the setting of ins->type for MonoInst's which are pushed on the 
14566  *   stack
14567  * - set the stack type and allocate a dreg in the EMIT_NEW macros
14568  * - get rid of all the <foo>2 stuff when the new JIT is ready.
14569  * - make sure handle_stack_args () is called before the branch is emitted
14570  * - when the new IR is done, get rid of all unused stuff
14571  * - COMPARE/BEQ as separate instructions or unify them ?
14572  *   - keeping them separate allows specialized compare instructions like
14573  *     compare_imm, compare_membase
14574  *   - most back ends unify fp compare+branch, fp compare+ceq
14575  * - integrate mono_save_args into inline_method
14576  * - get rid of the empty bblocks created by MONO_EMIT_NEW_BRACH_BLOCK2
14577  * - handle long shift opts on 32 bit platforms somehow: they require 
14578  *   3 sregs (2 for arg1 and 1 for arg2)
14579  * - make byref a 'normal' type.
14580  * - use vregs for bb->out_stacks if possible, handle_global_vreg will make them a
14581  *   variable if needed.
14582  * - do not start a new IL level bblock when cfg->cbb is changed by a function call
14583  *   like inline_method.
14584  * - remove inlining restrictions
14585  * - fix LNEG and enable cfold of INEG
14586  * - generalize x86 optimizations like ldelema as a peephole optimization
14587  * - add store_mem_imm for amd64
14588  * - optimize the loading of the interruption flag in the managed->native wrappers
14589  * - avoid special handling of OP_NOP in passes
14590  * - move code inserting instructions into one function/macro.
14591  * - try a coalescing phase after liveness analysis
14592  * - add float -> vreg conversion + local optimizations on !x86
14593  * - figure out how to handle decomposed branches during optimizations, ie.
14594  *   compare+branch, op_jump_table+op_br etc.
14595  * - promote RuntimeXHandles to vregs
14596  * - vtype cleanups:
14597  *   - add a NEW_VARLOADA_VREG macro
14598  * - the vtype optimizations are blocked by the LDADDR opcodes generated for 
14599  *   accessing vtype fields.
14600  * - get rid of I8CONST on 64 bit platforms
14601  * - dealing with the increase in code size due to branches created during opcode
14602  *   decomposition:
14603  *   - use extended basic blocks
14604  *     - all parts of the JIT
14605  *     - handle_global_vregs () && local regalloc
14606  *   - avoid introducing global vregs during decomposition, like 'vtable' in isinst
14607  * - sources of increase in code size:
14608  *   - vtypes
14609  *   - long compares
14610  *   - isinst and castclass
14611  *   - lvregs not allocated to global registers even if used multiple times
14612  * - call cctors outside the JIT, to make -v output more readable and JIT timings more
14613  *   meaningful.
14614  * - check for fp stack leakage in other opcodes too. (-> 'exceptions' optimization)
14615  * - add all micro optimizations from the old JIT
14616  * - put tree optimizations into the deadce pass
14617  * - decompose op_start_handler/op_endfilter/op_endfinally earlier using an arch
14618  *   specific function.
14619  * - unify the float comparison opcodes with the other comparison opcodes, i.e.
14620  *   fcompare + branchCC.
14621  * - create a helper function for allocating a stack slot, taking into account 
14622  *   MONO_CFG_HAS_SPILLUP.
14623  * - merge r68207.
14624  * - merge the ia64 switch changes.
14625  * - optimize mono_regstate2_alloc_int/float.
14626  * - fix the pessimistic handling of variables accessed in exception handler blocks.
14627  * - need to write a tree optimization pass, but the creation of trees is difficult, i.e.
14628  *   parts of the tree could be separated by other instructions, killing the tree
14629  *   arguments, or stores killing loads etc. Also, should we fold loads into other
14630  *   instructions if the result of the load is used multiple times ?
14631  * - make the REM_IMM optimization in mini-x86.c arch-independent.
14632  * - LAST MERGE: 108395.
14633  * - when returning vtypes in registers, generate IR and append it to the end of the
14634  *   last bb instead of doing it in the epilog.
14635  * - change the store opcodes so they use sreg1 instead of dreg to store the base register.
14636  */
14637
14638 /*
14639
14640 NOTES
14641 -----
14642
14643 - When to decompose opcodes:
14644   - earlier: this makes some optimizations hard to implement, since the low level IR
14645   no longer contains the neccessary information. But it is easier to do.
14646   - later: harder to implement, enables more optimizations.
14647 - Branches inside bblocks:
14648   - created when decomposing complex opcodes. 
14649     - branches to another bblock: harmless, but not tracked by the branch 
14650       optimizations, so need to branch to a label at the start of the bblock.
14651     - branches to inside the same bblock: very problematic, trips up the local
14652       reg allocator. Can be fixed by spitting the current bblock, but that is a
14653       complex operation, since some local vregs can become global vregs etc.
14654 - Local/global vregs:
14655   - local vregs: temporary vregs used inside one bblock. Assigned to hregs by the
14656     local register allocator.
14657   - global vregs: used in more than one bblock. Have an associated MonoMethodVar
14658     structure, created by mono_create_var (). Assigned to hregs or the stack by
14659     the global register allocator.
14660 - When to do optimizations like alu->alu_imm:
14661   - earlier -> saves work later on since the IR will be smaller/simpler
14662   - later -> can work on more instructions
14663 - Handling of valuetypes:
14664   - When a vtype is pushed on the stack, a new temporary is created, an 
14665     instruction computing its address (LDADDR) is emitted and pushed on
14666     the stack. Need to optimize cases when the vtype is used immediately as in
14667     argument passing, stloc etc.
14668 - Instead of the to_end stuff in the old JIT, simply call the function handling
14669   the values on the stack before emitting the last instruction of the bb.
14670 */
14671
14672 #endif /* DISABLE_JIT */