[ji] Add a mini-llvm.h header file for the functions implemented by the LLVM backend.
[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 #include "mini-llvm.h"
74
75 #define BRANCH_COST 10
76 #define INLINE_LENGTH_LIMIT 20
77
78 /* These have 'cfg' as an implicit argument */
79 #define INLINE_FAILURE(msg) do {                                                                        \
80         if ((cfg->method != cfg->current_method) && (cfg->current_method->wrapper_type == MONO_WRAPPER_NONE)) { \
81                 inline_failure (cfg, msg);                                                                              \
82                 goto exception_exit;                                                                                    \
83         } \
84         } while (0)
85 #define CHECK_CFG_EXCEPTION do {\
86                 if (cfg->exception_type != MONO_EXCEPTION_NONE) \
87                         goto exception_exit;                                            \
88         } while (0)
89 #define METHOD_ACCESS_FAILURE(method, cmethod) do {                     \
90                 method_access_failure ((cfg), (method), (cmethod));                     \
91                 goto exception_exit;                                                                            \
92         } while (0)
93 #define FIELD_ACCESS_FAILURE(method, field) do {                                        \
94                 field_access_failure ((cfg), (method), (field));                        \
95                 goto exception_exit;    \
96         } while (0)
97 #define GENERIC_SHARING_FAILURE(opcode) do {            \
98                 if (cfg->gshared) {                                                                     \
99                         gshared_failure (cfg, opcode, __FILE__, __LINE__);      \
100                         goto exception_exit;    \
101                 }                       \
102         } while (0)
103 #define GSHAREDVT_FAILURE(opcode) do {          \
104         if (cfg->gsharedvt) {                                                                                           \
105                 gsharedvt_failure (cfg, opcode, __FILE__, __LINE__);                    \
106                 goto exception_exit;                                                                                    \
107         }                                                                                                                                       \
108         } while (0)
109 #define OUT_OF_MEMORY_FAILURE do {      \
110                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_OUT_OF_MEMORY);             \
111                 goto exception_exit;    \
112         } while (0)
113 #define DISABLE_AOT(cfg) do { \
114                 if ((cfg)->verbose_level >= 2)                                            \
115                         printf ("AOT disabled: %s:%d\n", __FILE__, __LINE__);   \
116                 (cfg)->disable_aot = TRUE;                                                        \
117         } while (0)
118 #define LOAD_ERROR do { \
119                 break_on_unverified ();                                                         \
120                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD); \
121                 goto exception_exit;                                                                    \
122         } while (0)
123
124 #define TYPE_LOAD_ERROR(klass) do { \
125                 cfg->exception_ptr = klass; \
126                 LOAD_ERROR;                                     \
127         } while (0)
128
129 #define CHECK_CFG_ERROR do {\
130                 if (!mono_error_ok (&cfg->error)) { \
131                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);        \
132                         goto mono_error_exit; \
133                 } \
134         } while (0)
135
136 /* Determine whenever 'ins' represents a load of the 'this' argument */
137 #define MONO_CHECK_THIS(ins) (mono_method_signature (cfg->method)->hasthis && ((ins)->opcode == OP_MOVE) && ((ins)->sreg1 == cfg->args [0]->dreg))
138
139 static int ldind_to_load_membase (int opcode);
140 static int stind_to_store_membase (int opcode);
141
142 int mono_op_to_op_imm (int opcode);
143 int mono_op_to_op_imm_noemul (int opcode);
144
145 MONO_API MonoInst* mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig, MonoInst **args);
146
147 static int inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
148                                                   guchar *ip, guint real_offset, gboolean inline_always);
149
150 /* helper methods signatures */
151 static MonoMethodSignature *helper_sig_domain_get;
152 static MonoMethodSignature *helper_sig_rgctx_lazy_fetch_trampoline;
153
154 /*
155  * Instruction metadata
156  */
157 #ifdef MINI_OP
158 #undef MINI_OP
159 #endif
160 #ifdef MINI_OP3
161 #undef MINI_OP3
162 #endif
163 #define MINI_OP(a,b,dest,src1,src2) dest, src1, src2, ' ',
164 #define MINI_OP3(a,b,dest,src1,src2,src3) dest, src1, src2, src3,
165 #define NONE ' '
166 #define IREG 'i'
167 #define FREG 'f'
168 #define VREG 'v'
169 #define XREG 'x'
170 #if SIZEOF_REGISTER == 8 && SIZEOF_REGISTER == SIZEOF_VOID_P
171 #define LREG IREG
172 #else
173 #define LREG 'l'
174 #endif
175 /* keep in sync with the enum in mini.h */
176 const char
177 ins_info[] = {
178 #include "mini-ops.h"
179 };
180 #undef MINI_OP
181 #undef MINI_OP3
182
183 #define MINI_OP(a,b,dest,src1,src2) ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0)),
184 #define MINI_OP3(a,b,dest,src1,src2,src3) ((src3) != NONE ? 3 : ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0))),
185 /* 
186  * This should contain the index of the last sreg + 1. This is not the same
187  * as the number of sregs for opcodes like IA64_CMP_EQ_IMM.
188  */
189 const gint8 ins_sreg_counts[] = {
190 #include "mini-ops.h"
191 };
192 #undef MINI_OP
193 #undef MINI_OP3
194
195 #define MONO_INIT_VARINFO(vi,id) do { \
196         (vi)->range.first_use.pos.bid = 0xffff; \
197         (vi)->reg = -1; \
198         (vi)->idx = (id); \
199 } while (0)
200
201 guint32
202 mono_alloc_ireg (MonoCompile *cfg)
203 {
204         return alloc_ireg (cfg);
205 }
206
207 guint32
208 mono_alloc_lreg (MonoCompile *cfg)
209 {
210         return alloc_lreg (cfg);
211 }
212
213 guint32
214 mono_alloc_freg (MonoCompile *cfg)
215 {
216         return alloc_freg (cfg);
217 }
218
219 guint32
220 mono_alloc_preg (MonoCompile *cfg)
221 {
222         return alloc_preg (cfg);
223 }
224
225 guint32
226 mono_alloc_dreg (MonoCompile *cfg, MonoStackType stack_type)
227 {
228         return alloc_dreg (cfg, stack_type);
229 }
230
231 /*
232  * mono_alloc_ireg_ref:
233  *
234  *   Allocate an IREG, and mark it as holding a GC ref.
235  */
236 guint32
237 mono_alloc_ireg_ref (MonoCompile *cfg)
238 {
239         return alloc_ireg_ref (cfg);
240 }
241
242 /*
243  * mono_alloc_ireg_mp:
244  *
245  *   Allocate an IREG, and mark it as holding a managed pointer.
246  */
247 guint32
248 mono_alloc_ireg_mp (MonoCompile *cfg)
249 {
250         return alloc_ireg_mp (cfg);
251 }
252
253 /*
254  * mono_alloc_ireg_copy:
255  *
256  *   Allocate an IREG with the same GC type as VREG.
257  */
258 guint32
259 mono_alloc_ireg_copy (MonoCompile *cfg, guint32 vreg)
260 {
261         if (vreg_is_ref (cfg, vreg))
262                 return alloc_ireg_ref (cfg);
263         else if (vreg_is_mp (cfg, vreg))
264                 return alloc_ireg_mp (cfg);
265         else
266                 return alloc_ireg (cfg);
267 }
268
269 guint
270 mono_type_to_regmove (MonoCompile *cfg, MonoType *type)
271 {
272         if (type->byref)
273                 return OP_MOVE;
274
275         type = mini_get_underlying_type (type);
276 handle_enum:
277         switch (type->type) {
278         case MONO_TYPE_I1:
279         case MONO_TYPE_U1:
280                 return OP_MOVE;
281         case MONO_TYPE_I2:
282         case MONO_TYPE_U2:
283                 return OP_MOVE;
284         case MONO_TYPE_I4:
285         case MONO_TYPE_U4:
286                 return OP_MOVE;
287         case MONO_TYPE_I:
288         case MONO_TYPE_U:
289         case MONO_TYPE_PTR:
290         case MONO_TYPE_FNPTR:
291                 return OP_MOVE;
292         case MONO_TYPE_CLASS:
293         case MONO_TYPE_STRING:
294         case MONO_TYPE_OBJECT:
295         case MONO_TYPE_SZARRAY:
296         case MONO_TYPE_ARRAY:    
297                 return OP_MOVE;
298         case MONO_TYPE_I8:
299         case MONO_TYPE_U8:
300 #if SIZEOF_REGISTER == 8
301                 return OP_MOVE;
302 #else
303                 return OP_LMOVE;
304 #endif
305         case MONO_TYPE_R4:
306                 return cfg->r4fp ? OP_RMOVE : OP_FMOVE;
307         case MONO_TYPE_R8:
308                 return OP_FMOVE;
309         case MONO_TYPE_VALUETYPE:
310                 if (type->data.klass->enumtype) {
311                         type = mono_class_enum_basetype (type->data.klass);
312                         goto handle_enum;
313                 }
314                 if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (type)))
315                         return OP_XMOVE;
316                 return OP_VMOVE;
317         case MONO_TYPE_TYPEDBYREF:
318                 return OP_VMOVE;
319         case MONO_TYPE_GENERICINST:
320                 type = &type->data.generic_class->container_class->byval_arg;
321                 goto handle_enum;
322         case MONO_TYPE_VAR:
323         case MONO_TYPE_MVAR:
324                 g_assert (cfg->gshared);
325                 if (mini_type_var_is_vt (type))
326                         return OP_VMOVE;
327                 else
328                         return mono_type_to_regmove (cfg, mini_get_underlying_type (type));
329         default:
330                 g_error ("unknown type 0x%02x in type_to_regstore", type->type);
331         }
332         return -1;
333 }
334
335 void
336 mono_print_bb (MonoBasicBlock *bb, const char *msg)
337 {
338         int i;
339         MonoInst *tree;
340
341         printf ("\n%s %d: [IN: ", msg, bb->block_num);
342         for (i = 0; i < bb->in_count; ++i)
343                 printf (" BB%d(%d)", bb->in_bb [i]->block_num, bb->in_bb [i]->dfn);
344         printf (", OUT: ");
345         for (i = 0; i < bb->out_count; ++i)
346                 printf (" BB%d(%d)", bb->out_bb [i]->block_num, bb->out_bb [i]->dfn);
347         printf (" ]\n");
348         for (tree = bb->code; tree; tree = tree->next)
349                 mono_print_ins_index (-1, tree);
350 }
351
352 void
353 mono_create_helper_signatures (void)
354 {
355         helper_sig_domain_get = mono_create_icall_signature ("ptr");
356         helper_sig_rgctx_lazy_fetch_trampoline = mono_create_icall_signature ("ptr ptr");
357 }
358
359 static MONO_NEVER_INLINE void
360 break_on_unverified (void)
361 {
362         if (mini_get_debug_options ()->break_on_unverified)
363                 G_BREAKPOINT ();
364 }
365
366 static MONO_NEVER_INLINE void
367 method_access_failure (MonoCompile *cfg, MonoMethod *method, MonoMethod *cil_method)
368 {
369         char *method_fname = mono_method_full_name (method, TRUE);
370         char *cil_method_fname = mono_method_full_name (cil_method, TRUE);
371         mono_cfg_set_exception (cfg, MONO_EXCEPTION_METHOD_ACCESS);
372         cfg->exception_message = g_strdup_printf ("Method `%s' is inaccessible from method `%s'\n", cil_method_fname, method_fname);
373         g_free (method_fname);
374         g_free (cil_method_fname);
375 }
376
377 static MONO_NEVER_INLINE void
378 field_access_failure (MonoCompile *cfg, MonoMethod *method, MonoClassField *field)
379 {
380         char *method_fname = mono_method_full_name (method, TRUE);
381         char *field_fname = mono_field_full_name (field);
382         mono_cfg_set_exception (cfg, MONO_EXCEPTION_FIELD_ACCESS);
383         cfg->exception_message = g_strdup_printf ("Field `%s' is inaccessible from method `%s'\n", field_fname, method_fname);
384         g_free (method_fname);
385         g_free (field_fname);
386 }
387
388 static MONO_NEVER_INLINE void
389 inline_failure (MonoCompile *cfg, const char *msg)
390 {
391         if (cfg->verbose_level >= 2)
392                 printf ("inline failed: %s\n", msg);
393         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INLINE_FAILED);
394 }
395
396 static MONO_NEVER_INLINE void
397 gshared_failure (MonoCompile *cfg, int opcode, const char *file, int line)
398 {
399         if (cfg->verbose_level > 2)                                                                                     \
400                 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);
401         mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED);
402 }
403
404 static MONO_NEVER_INLINE void
405 gsharedvt_failure (MonoCompile *cfg, int opcode, const char *file, int line)
406 {
407         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);
408         if (cfg->verbose_level >= 2)
409                 printf ("%s\n", cfg->exception_message);
410         mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED);
411 }
412
413 /*
414  * When using gsharedvt, some instatiations might be verifiable, and some might be not. i.e. 
415  * foo<T> (int i) { ldarg.0; box T; }
416  */
417 #define UNVERIFIED do { \
418         if (cfg->gsharedvt) { \
419                 if (cfg->verbose_level > 2)                                                                     \
420                         printf ("gsharedvt method failed to verify, falling back to instantiation.\n"); \
421                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED); \
422                 goto exception_exit;                                                                                    \
423         }                                                                                                                                       \
424         break_on_unverified ();                                                                                         \
425         goto unverified;                                                                                                        \
426 } while (0)
427
428 #define GET_BBLOCK(cfg,tblock,ip) do {  \
429                 (tblock) = cfg->cil_offset_to_bb [(ip) - cfg->cil_start]; \
430                 if (!(tblock)) {        \
431                         if ((ip) >= end || (ip) < header->code) UNVERIFIED; \
432             NEW_BBLOCK (cfg, (tblock)); \
433                         (tblock)->cil_code = (ip);      \
434                         ADD_BBLOCK (cfg, (tblock));     \
435                 } \
436         } while (0)
437
438 #if defined(TARGET_X86) || defined(TARGET_AMD64)
439 #define EMIT_NEW_X86_LEA(cfg,dest,sr1,sr2,shift,imm) do { \
440                 MONO_INST_NEW (cfg, dest, OP_X86_LEA); \
441                 (dest)->dreg = alloc_ireg_mp ((cfg)); \
442                 (dest)->sreg1 = (sr1); \
443                 (dest)->sreg2 = (sr2); \
444                 (dest)->inst_imm = (imm); \
445                 (dest)->backend.shift_amount = (shift); \
446                 MONO_ADD_INS ((cfg)->cbb, (dest)); \
447         } while (0)
448 #endif
449
450 /* Emit conversions so both operands of a binary opcode are of the same type */
451 static void
452 add_widen_op (MonoCompile *cfg, MonoInst *ins, MonoInst **arg1_ref, MonoInst **arg2_ref)
453 {
454         MonoInst *arg1 = *arg1_ref;
455         MonoInst *arg2 = *arg2_ref;
456
457         if (cfg->r4fp &&
458                 ((arg1->type == STACK_R4 && arg2->type == STACK_R8) ||
459                  (arg1->type == STACK_R8 && arg2->type == STACK_R4))) {
460                 MonoInst *conv;
461
462                 /* Mixing r4/r8 is allowed by the spec */
463                 if (arg1->type == STACK_R4) {
464                         int dreg = alloc_freg (cfg);
465
466                         EMIT_NEW_UNALU (cfg, conv, OP_RCONV_TO_R8, dreg, arg1->dreg);
467                         conv->type = STACK_R8;
468                         ins->sreg1 = dreg;
469                         *arg1_ref = conv;
470                 }
471                 if (arg2->type == STACK_R4) {
472                         int dreg = alloc_freg (cfg);
473
474                         EMIT_NEW_UNALU (cfg, conv, OP_RCONV_TO_R8, dreg, arg2->dreg);
475                         conv->type = STACK_R8;
476                         ins->sreg2 = dreg;
477                         *arg2_ref = conv;
478                 }
479         }
480
481 #if SIZEOF_REGISTER == 8
482         /* FIXME: Need to add many more cases */
483         if ((arg1)->type == STACK_PTR && (arg2)->type == STACK_I4) {
484                 MonoInst *widen;
485
486                 int dr = alloc_preg (cfg);
487                 EMIT_NEW_UNALU (cfg, widen, OP_SEXT_I4, dr, (arg2)->dreg);
488                 (ins)->sreg2 = widen->dreg;
489         }
490 #endif
491 }
492
493 #define ADD_BINOP(op) do {      \
494                 MONO_INST_NEW (cfg, ins, (op)); \
495                 sp -= 2;        \
496                 ins->sreg1 = sp [0]->dreg;      \
497                 ins->sreg2 = sp [1]->dreg;      \
498                 type_from_op (cfg, ins, sp [0], sp [1]);        \
499                 CHECK_TYPE (ins);       \
500                 /* Have to insert a widening op */               \
501         add_widen_op (cfg, ins, &sp [0], &sp [1]);               \
502         ins->dreg = alloc_dreg ((cfg), (ins)->type); \
503         MONO_ADD_INS ((cfg)->cbb, (ins)); \
504         *sp++ = mono_decompose_opcode ((cfg), (ins));   \
505         } while (0)
506
507 #define ADD_UNOP(op) do {       \
508                 MONO_INST_NEW (cfg, ins, (op)); \
509                 sp--;   \
510                 ins->sreg1 = sp [0]->dreg;      \
511                 type_from_op (cfg, ins, sp [0], NULL);  \
512                 CHECK_TYPE (ins);       \
513         (ins)->dreg = alloc_dreg ((cfg), (ins)->type); \
514         MONO_ADD_INS ((cfg)->cbb, (ins)); \
515                 *sp++ = mono_decompose_opcode (cfg, ins);       \
516         } while (0)
517
518 #define ADD_BINCOND(next_block) do {    \
519                 MonoInst *cmp;  \
520                 sp -= 2; \
521                 MONO_INST_NEW(cfg, cmp, OP_COMPARE);    \
522                 cmp->sreg1 = sp [0]->dreg;      \
523                 cmp->sreg2 = sp [1]->dreg;      \
524                 type_from_op (cfg, cmp, sp [0], sp [1]);        \
525                 CHECK_TYPE (cmp);       \
526                 add_widen_op (cfg, cmp, &sp [0], &sp [1]);                                              \
527                 type_from_op (cfg, ins, sp [0], sp [1]);                                                        \
528                 ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);      \
529                 GET_BBLOCK (cfg, tblock, target);               \
530                 link_bblock (cfg, cfg->cbb, tblock);    \
531                 ins->inst_true_bb = tblock;     \
532                 if ((next_block)) {     \
533                         link_bblock (cfg, cfg->cbb, (next_block));      \
534                         ins->inst_false_bb = (next_block);      \
535                         start_new_bblock = 1;   \
536                 } else {        \
537                         GET_BBLOCK (cfg, tblock, ip);           \
538                         link_bblock (cfg, cfg->cbb, tblock);    \
539                         ins->inst_false_bb = tblock;    \
540                         start_new_bblock = 2;   \
541                 }       \
542                 if (sp != stack_start) {                                                                        \
543                     handle_stack_args (cfg, stack_start, sp - stack_start); \
544                         CHECK_UNVERIFIABLE (cfg); \
545                 } \
546         MONO_ADD_INS (cfg->cbb, cmp); \
547                 MONO_ADD_INS (cfg->cbb, ins);   \
548         } while (0)
549
550 /* *
551  * link_bblock: Links two basic blocks
552  *
553  * links two basic blocks in the control flow graph, the 'from'
554  * argument is the starting block and the 'to' argument is the block
555  * the control flow ends to after 'from'.
556  */
557 static void
558 link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
559 {
560         MonoBasicBlock **newa;
561         int i, found;
562
563 #if 0
564         if (from->cil_code) {
565                 if (to->cil_code)
566                         printf ("edge from IL%04x to IL_%04x\n", from->cil_code - cfg->cil_code, to->cil_code - cfg->cil_code);
567                 else
568                         printf ("edge from IL%04x to exit\n", from->cil_code - cfg->cil_code);
569         } else {
570                 if (to->cil_code)
571                         printf ("edge from entry to IL_%04x\n", to->cil_code - cfg->cil_code);
572                 else
573                         printf ("edge from entry to exit\n");
574         }
575 #endif
576
577         found = FALSE;
578         for (i = 0; i < from->out_count; ++i) {
579                 if (to == from->out_bb [i]) {
580                         found = TRUE;
581                         break;
582                 }
583         }
584         if (!found) {
585                 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (from->out_count + 1));
586                 for (i = 0; i < from->out_count; ++i) {
587                         newa [i] = from->out_bb [i];
588                 }
589                 newa [i] = to;
590                 from->out_count++;
591                 from->out_bb = newa;
592         }
593
594         found = FALSE;
595         for (i = 0; i < to->in_count; ++i) {
596                 if (from == to->in_bb [i]) {
597                         found = TRUE;
598                         break;
599                 }
600         }
601         if (!found) {
602                 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (to->in_count + 1));
603                 for (i = 0; i < to->in_count; ++i) {
604                         newa [i] = to->in_bb [i];
605                 }
606                 newa [i] = from;
607                 to->in_count++;
608                 to->in_bb = newa;
609         }
610 }
611
612 void
613 mono_link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
614 {
615         link_bblock (cfg, from, to);
616 }
617
618 /**
619  * mono_find_block_region:
620  *
621  *   We mark each basic block with a region ID. We use that to avoid BB
622  *   optimizations when blocks are in different regions.
623  *
624  * Returns:
625  *   A region token that encodes where this region is, and information
626  *   about the clause owner for this block.
627  *
628  *   The region encodes the try/catch/filter clause that owns this block
629  *   as well as the type.  -1 is a special value that represents a block
630  *   that is in none of try/catch/filter.
631  */
632 static int
633 mono_find_block_region (MonoCompile *cfg, int offset)
634 {
635         MonoMethodHeader *header = cfg->header;
636         MonoExceptionClause *clause;
637         int i;
638
639         for (i = 0; i < header->num_clauses; ++i) {
640                 clause = &header->clauses [i];
641                 if ((clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) && (offset >= clause->data.filter_offset) &&
642                     (offset < (clause->handler_offset)))
643                         return ((i + 1) << 8) | MONO_REGION_FILTER | clause->flags;
644                            
645                 if (MONO_OFFSET_IN_HANDLER (clause, offset)) {
646                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY)
647                                 return ((i + 1) << 8) | MONO_REGION_FINALLY | clause->flags;
648                         else if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
649                                 return ((i + 1) << 8) | MONO_REGION_FAULT | clause->flags;
650                         else
651                                 return ((i + 1) << 8) | MONO_REGION_CATCH | clause->flags;
652                 }
653         }
654         for (i = 0; i < header->num_clauses; ++i) {
655                 clause = &header->clauses [i];
656
657                 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
658                         return ((i + 1) << 8) | clause->flags;
659         }
660
661         return -1;
662 }
663
664 static GList*
665 mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *target, int type)
666 {
667         MonoMethodHeader *header = cfg->header;
668         MonoExceptionClause *clause;
669         int i;
670         GList *res = NULL;
671
672         for (i = 0; i < header->num_clauses; ++i) {
673                 clause = &header->clauses [i];
674                 if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) && 
675                     (!MONO_OFFSET_IN_CLAUSE (clause, (target - header->code)))) {
676                         if (clause->flags == type)
677                                 res = g_list_append (res, clause);
678                 }
679         }
680         return res;
681 }
682
683 static void
684 mono_create_spvar_for_region (MonoCompile *cfg, int region)
685 {
686         MonoInst *var;
687
688         var = g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
689         if (var)
690                 return;
691
692         var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
693         /* prevent it from being register allocated */
694         var->flags |= MONO_INST_VOLATILE;
695
696         g_hash_table_insert (cfg->spvars, GINT_TO_POINTER (region), var);
697 }
698
699 MonoInst *
700 mono_find_exvar_for_offset (MonoCompile *cfg, int offset)
701 {
702         return g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
703 }
704
705 static MonoInst*
706 mono_create_exvar_for_offset (MonoCompile *cfg, int offset)
707 {
708         MonoInst *var;
709
710         var = g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
711         if (var)
712                 return var;
713
714         var = mono_compile_create_var (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL);
715         /* prevent it from being register allocated */
716         var->flags |= MONO_INST_VOLATILE;
717
718         g_hash_table_insert (cfg->exvars, GINT_TO_POINTER (offset), var);
719
720         return var;
721 }
722
723 /*
724  * Returns the type used in the eval stack when @type is loaded.
725  * FIXME: return a MonoType/MonoClass for the byref and VALUETYPE cases.
726  */
727 void
728 type_to_eval_stack_type (MonoCompile *cfg, MonoType *type, MonoInst *inst)
729 {
730         MonoClass *klass;
731
732         type = mini_get_underlying_type (type);
733         inst->klass = klass = mono_class_from_mono_type (type);
734         if (type->byref) {
735                 inst->type = STACK_MP;
736                 return;
737         }
738
739 handle_enum:
740         switch (type->type) {
741         case MONO_TYPE_VOID:
742                 inst->type = STACK_INV;
743                 return;
744         case MONO_TYPE_I1:
745         case MONO_TYPE_U1:
746         case MONO_TYPE_I2:
747         case MONO_TYPE_U2:
748         case MONO_TYPE_I4:
749         case MONO_TYPE_U4:
750                 inst->type = STACK_I4;
751                 return;
752         case MONO_TYPE_I:
753         case MONO_TYPE_U:
754         case MONO_TYPE_PTR:
755         case MONO_TYPE_FNPTR:
756                 inst->type = STACK_PTR;
757                 return;
758         case MONO_TYPE_CLASS:
759         case MONO_TYPE_STRING:
760         case MONO_TYPE_OBJECT:
761         case MONO_TYPE_SZARRAY:
762         case MONO_TYPE_ARRAY:    
763                 inst->type = STACK_OBJ;
764                 return;
765         case MONO_TYPE_I8:
766         case MONO_TYPE_U8:
767                 inst->type = STACK_I8;
768                 return;
769         case MONO_TYPE_R4:
770                 inst->type = cfg->r4_stack_type;
771                 break;
772         case MONO_TYPE_R8:
773                 inst->type = STACK_R8;
774                 return;
775         case MONO_TYPE_VALUETYPE:
776                 if (type->data.klass->enumtype) {
777                         type = mono_class_enum_basetype (type->data.klass);
778                         goto handle_enum;
779                 } else {
780                         inst->klass = klass;
781                         inst->type = STACK_VTYPE;
782                         return;
783                 }
784         case MONO_TYPE_TYPEDBYREF:
785                 inst->klass = mono_defaults.typed_reference_class;
786                 inst->type = STACK_VTYPE;
787                 return;
788         case MONO_TYPE_GENERICINST:
789                 type = &type->data.generic_class->container_class->byval_arg;
790                 goto handle_enum;
791         case MONO_TYPE_VAR:
792         case MONO_TYPE_MVAR:
793                 g_assert (cfg->gshared);
794                 if (mini_is_gsharedvt_type (type)) {
795                         g_assert (cfg->gsharedvt);
796                         inst->type = STACK_VTYPE;
797                 } else {
798                         type_to_eval_stack_type (cfg, mini_get_underlying_type (type), inst);
799                 }
800                 return;
801         default:
802                 g_error ("unknown type 0x%02x in eval stack type", type->type);
803         }
804 }
805
806 /*
807  * The following tables are used to quickly validate the IL code in type_from_op ().
808  */
809 static const char
810 bin_num_table [STACK_MAX] [STACK_MAX] = {
811         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
812         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
813         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
814         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
815         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8,  STACK_INV, STACK_INV, STACK_INV, STACK_R8},
816         {STACK_INV, STACK_MP,  STACK_INV, STACK_MP,  STACK_INV, STACK_PTR, 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_INV, STACK_INV, STACK_INV, STACK_INV},
819         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8, STACK_INV, STACK_INV, STACK_INV, STACK_R4}
820 };
821
822 static const char 
823 neg_table [] = {
824         STACK_INV, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_INV, STACK_INV, STACK_INV, STACK_R4
825 };
826
827 /* reduce the size of this table */
828 static const char
829 bin_int_table [STACK_MAX] [STACK_MAX] = {
830         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
831         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
832         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
833         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, 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         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
838 };
839
840 static const char
841 bin_comp_table [STACK_MAX] [STACK_MAX] = {
842 /*      Inv i  L  p  F  &  O  vt r4 */
843         {0},
844         {0, 1, 0, 1, 0, 0, 0, 0}, /* i, int32 */
845         {0, 0, 1, 0, 0, 0, 0, 0}, /* L, int64 */
846         {0, 1, 0, 1, 0, 2, 4, 0}, /* p, ptr */
847         {0, 0, 0, 0, 1, 0, 0, 0, 1}, /* F, R8 */
848         {0, 0, 0, 2, 0, 1, 0, 0}, /* &, managed pointer */
849         {0, 0, 0, 4, 0, 0, 3, 0}, /* O, reference */
850         {0, 0, 0, 0, 0, 0, 0, 0}, /* vt value type */
851         {0, 0, 0, 0, 1, 0, 0, 0, 1}, /* r, r4 */
852 };
853
854 /* reduce the size of this table */
855 static const char
856 shift_table [STACK_MAX] [STACK_MAX] = {
857         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
858         {STACK_INV, STACK_I4,  STACK_INV, STACK_I4,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
859         {STACK_INV, STACK_I8,  STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
860         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, 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         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
865 };
866
867 /*
868  * Tables to map from the non-specific opcode to the matching
869  * type-specific opcode.
870  */
871 /* handles from CEE_ADD to CEE_SHR_UN (CEE_REM_UN for floats) */
872 static const guint16
873 binops_op_map [STACK_MAX] = {
874         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
875 };
876
877 /* handles from CEE_NEG to CEE_CONV_U8 */
878 static const guint16
879 unops_op_map [STACK_MAX] = {
880         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
881 };
882
883 /* handles from CEE_CONV_U2 to CEE_SUB_OVF_UN */
884 static const guint16
885 ovfops_op_map [STACK_MAX] = {
886         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
887 };
888
889 /* handles from CEE_CONV_OVF_I1_UN to CEE_CONV_OVF_U_UN */
890 static const guint16
891 ovf2ops_op_map [STACK_MAX] = {
892         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
893 };
894
895 /* handles from CEE_CONV_OVF_I1 to CEE_CONV_OVF_U8 */
896 static const guint16
897 ovf3ops_op_map [STACK_MAX] = {
898         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
899 };
900
901 /* handles from CEE_BEQ to CEE_BLT_UN */
902 static const guint16
903 beqops_op_map [STACK_MAX] = {
904         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
905 };
906
907 /* handles from CEE_CEQ to CEE_CLT_UN */
908 static const guint16
909 ceqops_op_map [STACK_MAX] = {
910         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
911 };
912
913 /*
914  * Sets ins->type (the type on the eval stack) according to the
915  * type of the opcode and the arguments to it.
916  * Invalid IL code is marked by setting ins->type to the invalid value STACK_INV.
917  *
918  * FIXME: this function sets ins->type unconditionally in some cases, but
919  * it should set it to invalid for some types (a conv.x on an object)
920  */
921 static void
922 type_from_op (MonoCompile *cfg, MonoInst *ins, MonoInst *src1, MonoInst *src2)
923 {
924         switch (ins->opcode) {
925         /* binops */
926         case CEE_ADD:
927         case CEE_SUB:
928         case CEE_MUL:
929         case CEE_DIV:
930         case CEE_REM:
931                 /* FIXME: check unverifiable args for STACK_MP */
932                 ins->type = bin_num_table [src1->type] [src2->type];
933                 ins->opcode += binops_op_map [ins->type];
934                 break;
935         case CEE_DIV_UN:
936         case CEE_REM_UN:
937         case CEE_AND:
938         case CEE_OR:
939         case CEE_XOR:
940                 ins->type = bin_int_table [src1->type] [src2->type];
941                 ins->opcode += binops_op_map [ins->type];
942                 break;
943         case CEE_SHL:
944         case CEE_SHR:
945         case CEE_SHR_UN:
946                 ins->type = shift_table [src1->type] [src2->type];
947                 ins->opcode += binops_op_map [ins->type];
948                 break;
949         case OP_COMPARE:
950         case OP_LCOMPARE:
951         case OP_ICOMPARE:
952                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
953                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
954                         ins->opcode = OP_LCOMPARE;
955                 else if (src1->type == STACK_R4)
956                         ins->opcode = OP_RCOMPARE;
957                 else if (src1->type == STACK_R8)
958                         ins->opcode = OP_FCOMPARE;
959                 else
960                         ins->opcode = OP_ICOMPARE;
961                 break;
962         case OP_ICOMPARE_IMM:
963                 ins->type = bin_comp_table [src1->type] [src1->type] ? STACK_I4 : STACK_INV;
964                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
965                         ins->opcode = OP_LCOMPARE_IMM;          
966                 break;
967         case CEE_BEQ:
968         case CEE_BGE:
969         case CEE_BGT:
970         case CEE_BLE:
971         case CEE_BLT:
972         case CEE_BNE_UN:
973         case CEE_BGE_UN:
974         case CEE_BGT_UN:
975         case CEE_BLE_UN:
976         case CEE_BLT_UN:
977                 ins->opcode += beqops_op_map [src1->type];
978                 break;
979         case OP_CEQ:
980                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
981                 ins->opcode += ceqops_op_map [src1->type];
982                 break;
983         case OP_CGT:
984         case OP_CGT_UN:
985         case OP_CLT:
986         case OP_CLT_UN:
987                 ins->type = (bin_comp_table [src1->type] [src2->type] & 1) ? STACK_I4: STACK_INV;
988                 ins->opcode += ceqops_op_map [src1->type];
989                 break;
990         /* unops */
991         case CEE_NEG:
992                 ins->type = neg_table [src1->type];
993                 ins->opcode += unops_op_map [ins->type];
994                 break;
995         case CEE_NOT:
996                 if (src1->type >= STACK_I4 && src1->type <= STACK_PTR)
997                         ins->type = src1->type;
998                 else
999                         ins->type = STACK_INV;
1000                 ins->opcode += unops_op_map [ins->type];
1001                 break;
1002         case CEE_CONV_I1:
1003         case CEE_CONV_I2:
1004         case CEE_CONV_I4:
1005         case CEE_CONV_U4:
1006                 ins->type = STACK_I4;
1007                 ins->opcode += unops_op_map [src1->type];
1008                 break;
1009         case CEE_CONV_R_UN:
1010                 ins->type = STACK_R8;
1011                 switch (src1->type) {
1012                 case STACK_I4:
1013                 case STACK_PTR:
1014                         ins->opcode = OP_ICONV_TO_R_UN;
1015                         break;
1016                 case STACK_I8:
1017                         ins->opcode = OP_LCONV_TO_R_UN; 
1018                         break;
1019                 }
1020                 break;
1021         case CEE_CONV_OVF_I1:
1022         case CEE_CONV_OVF_U1:
1023         case CEE_CONV_OVF_I2:
1024         case CEE_CONV_OVF_U2:
1025         case CEE_CONV_OVF_I4:
1026         case CEE_CONV_OVF_U4:
1027                 ins->type = STACK_I4;
1028                 ins->opcode += ovf3ops_op_map [src1->type];
1029                 break;
1030         case CEE_CONV_OVF_I_UN:
1031         case CEE_CONV_OVF_U_UN:
1032                 ins->type = STACK_PTR;
1033                 ins->opcode += ovf2ops_op_map [src1->type];
1034                 break;
1035         case CEE_CONV_OVF_I1_UN:
1036         case CEE_CONV_OVF_I2_UN:
1037         case CEE_CONV_OVF_I4_UN:
1038         case CEE_CONV_OVF_U1_UN:
1039         case CEE_CONV_OVF_U2_UN:
1040         case CEE_CONV_OVF_U4_UN:
1041                 ins->type = STACK_I4;
1042                 ins->opcode += ovf2ops_op_map [src1->type];
1043                 break;
1044         case CEE_CONV_U:
1045                 ins->type = STACK_PTR;
1046                 switch (src1->type) {
1047                 case STACK_I4:
1048                         ins->opcode = OP_ICONV_TO_U;
1049                         break;
1050                 case STACK_PTR:
1051                 case STACK_MP:
1052 #if SIZEOF_VOID_P == 8
1053                         ins->opcode = OP_LCONV_TO_U;
1054 #else
1055                         ins->opcode = OP_MOVE;
1056 #endif
1057                         break;
1058                 case STACK_I8:
1059                         ins->opcode = OP_LCONV_TO_U;
1060                         break;
1061                 case STACK_R8:
1062                         ins->opcode = OP_FCONV_TO_U;
1063                         break;
1064                 }
1065                 break;
1066         case CEE_CONV_I8:
1067         case CEE_CONV_U8:
1068                 ins->type = STACK_I8;
1069                 ins->opcode += unops_op_map [src1->type];
1070                 break;
1071         case CEE_CONV_OVF_I8:
1072         case CEE_CONV_OVF_U8:
1073                 ins->type = STACK_I8;
1074                 ins->opcode += ovf3ops_op_map [src1->type];
1075                 break;
1076         case CEE_CONV_OVF_U8_UN:
1077         case CEE_CONV_OVF_I8_UN:
1078                 ins->type = STACK_I8;
1079                 ins->opcode += ovf2ops_op_map [src1->type];
1080                 break;
1081         case CEE_CONV_R4:
1082                 ins->type = cfg->r4_stack_type;
1083                 ins->opcode += unops_op_map [src1->type];
1084                 break;
1085         case CEE_CONV_R8:
1086                 ins->type = STACK_R8;
1087                 ins->opcode += unops_op_map [src1->type];
1088                 break;
1089         case OP_CKFINITE:
1090                 ins->type = STACK_R8;           
1091                 break;
1092         case CEE_CONV_U2:
1093         case CEE_CONV_U1:
1094                 ins->type = STACK_I4;
1095                 ins->opcode += ovfops_op_map [src1->type];
1096                 break;
1097         case CEE_CONV_I:
1098         case CEE_CONV_OVF_I:
1099         case CEE_CONV_OVF_U:
1100                 ins->type = STACK_PTR;
1101                 ins->opcode += ovfops_op_map [src1->type];
1102                 break;
1103         case CEE_ADD_OVF:
1104         case CEE_ADD_OVF_UN:
1105         case CEE_MUL_OVF:
1106         case CEE_MUL_OVF_UN:
1107         case CEE_SUB_OVF:
1108         case CEE_SUB_OVF_UN:
1109                 ins->type = bin_num_table [src1->type] [src2->type];
1110                 ins->opcode += ovfops_op_map [src1->type];
1111                 if (ins->type == STACK_R8)
1112                         ins->type = STACK_INV;
1113                 break;
1114         case OP_LOAD_MEMBASE:
1115                 ins->type = STACK_PTR;
1116                 break;
1117         case OP_LOADI1_MEMBASE:
1118         case OP_LOADU1_MEMBASE:
1119         case OP_LOADI2_MEMBASE:
1120         case OP_LOADU2_MEMBASE:
1121         case OP_LOADI4_MEMBASE:
1122         case OP_LOADU4_MEMBASE:
1123                 ins->type = STACK_PTR;
1124                 break;
1125         case OP_LOADI8_MEMBASE:
1126                 ins->type = STACK_I8;
1127                 break;
1128         case OP_LOADR4_MEMBASE:
1129                 ins->type = cfg->r4_stack_type;
1130                 break;
1131         case OP_LOADR8_MEMBASE:
1132                 ins->type = STACK_R8;
1133                 break;
1134         default:
1135                 g_error ("opcode 0x%04x not handled in type from op", ins->opcode);
1136                 break;
1137         }
1138
1139         if (ins->type == STACK_MP)
1140                 ins->klass = mono_defaults.object_class;
1141 }
1142
1143 static const char 
1144 ldind_type [] = {
1145         STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_R8, STACK_OBJ
1146 };
1147
1148 #if 0
1149
1150 static const char
1151 param_table [STACK_MAX] [STACK_MAX] = {
1152         {0},
1153 };
1154
1155 static int
1156 check_values_to_signature (MonoInst *args, MonoType *this_ins, MonoMethodSignature *sig)
1157 {
1158         int i;
1159
1160         if (sig->hasthis) {
1161                 switch (args->type) {
1162                 case STACK_I4:
1163                 case STACK_I8:
1164                 case STACK_R8:
1165                 case STACK_VTYPE:
1166                 case STACK_INV:
1167                         return 0;
1168                 }
1169                 args++;
1170         }
1171         for (i = 0; i < sig->param_count; ++i) {
1172                 switch (args [i].type) {
1173                 case STACK_INV:
1174                         return 0;
1175                 case STACK_MP:
1176                         if (!sig->params [i]->byref)
1177                                 return 0;
1178                         continue;
1179                 case STACK_OBJ:
1180                         if (sig->params [i]->byref)
1181                                 return 0;
1182                         switch (sig->params [i]->type) {
1183                         case MONO_TYPE_CLASS:
1184                         case MONO_TYPE_STRING:
1185                         case MONO_TYPE_OBJECT:
1186                         case MONO_TYPE_SZARRAY:
1187                         case MONO_TYPE_ARRAY:
1188                                 break;
1189                         default:
1190                                 return 0;
1191                         }
1192                         continue;
1193                 case STACK_R8:
1194                         if (sig->params [i]->byref)
1195                                 return 0;
1196                         if (sig->params [i]->type != MONO_TYPE_R4 && sig->params [i]->type != MONO_TYPE_R8)
1197                                 return 0;
1198                         continue;
1199                 case STACK_PTR:
1200                 case STACK_I4:
1201                 case STACK_I8:
1202                 case STACK_VTYPE:
1203                         break;
1204                 }
1205                 /*if (!param_table [args [i].type] [sig->params [i]->type])
1206                         return 0;*/
1207         }
1208         return 1;
1209 }
1210 #endif
1211
1212 /*
1213  * When we need a pointer to the current domain many times in a method, we
1214  * call mono_domain_get() once and we store the result in a local variable.
1215  * This function returns the variable that represents the MonoDomain*.
1216  */
1217 inline static MonoInst *
1218 mono_get_domainvar (MonoCompile *cfg)
1219 {
1220         if (!cfg->domainvar)
1221                 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1222         return cfg->domainvar;
1223 }
1224
1225 /*
1226  * The got_var contains the address of the Global Offset Table when AOT 
1227  * compiling.
1228  */
1229 MonoInst *
1230 mono_get_got_var (MonoCompile *cfg)
1231 {
1232         if (!cfg->compile_aot || !cfg->backend->need_got_var)
1233                 return NULL;
1234         if (!cfg->got_var) {
1235                 cfg->got_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1236         }
1237         return cfg->got_var;
1238 }
1239
1240 static MonoInst *
1241 mono_get_vtable_var (MonoCompile *cfg)
1242 {
1243         g_assert (cfg->gshared);
1244
1245         if (!cfg->rgctx_var) {
1246                 cfg->rgctx_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1247                 /* force the var to be stack allocated */
1248                 cfg->rgctx_var->flags |= MONO_INST_VOLATILE;
1249         }
1250
1251         return cfg->rgctx_var;
1252 }
1253
1254 static MonoType*
1255 type_from_stack_type (MonoInst *ins) {
1256         switch (ins->type) {
1257         case STACK_I4: return &mono_defaults.int32_class->byval_arg;
1258         case STACK_I8: return &mono_defaults.int64_class->byval_arg;
1259         case STACK_PTR: return &mono_defaults.int_class->byval_arg;
1260         case STACK_R4: return &mono_defaults.single_class->byval_arg;
1261         case STACK_R8: return &mono_defaults.double_class->byval_arg;
1262         case STACK_MP:
1263                 return &ins->klass->this_arg;
1264         case STACK_OBJ: return &mono_defaults.object_class->byval_arg;
1265         case STACK_VTYPE: return &ins->klass->byval_arg;
1266         default:
1267                 g_error ("stack type %d to monotype not handled\n", ins->type);
1268         }
1269         return NULL;
1270 }
1271
1272 static G_GNUC_UNUSED int
1273 type_to_stack_type (MonoCompile *cfg, MonoType *t)
1274 {
1275         t = mono_type_get_underlying_type (t);
1276         switch (t->type) {
1277         case MONO_TYPE_I1:
1278         case MONO_TYPE_U1:
1279         case MONO_TYPE_I2:
1280         case MONO_TYPE_U2:
1281         case MONO_TYPE_I4:
1282         case MONO_TYPE_U4:
1283                 return STACK_I4;
1284         case MONO_TYPE_I:
1285         case MONO_TYPE_U:
1286         case MONO_TYPE_PTR:
1287         case MONO_TYPE_FNPTR:
1288                 return STACK_PTR;
1289         case MONO_TYPE_CLASS:
1290         case MONO_TYPE_STRING:
1291         case MONO_TYPE_OBJECT:
1292         case MONO_TYPE_SZARRAY:
1293         case MONO_TYPE_ARRAY:    
1294                 return STACK_OBJ;
1295         case MONO_TYPE_I8:
1296         case MONO_TYPE_U8:
1297                 return STACK_I8;
1298         case MONO_TYPE_R4:
1299                 return cfg->r4_stack_type;
1300         case MONO_TYPE_R8:
1301                 return STACK_R8;
1302         case MONO_TYPE_VALUETYPE:
1303         case MONO_TYPE_TYPEDBYREF:
1304                 return STACK_VTYPE;
1305         case MONO_TYPE_GENERICINST:
1306                 if (mono_type_generic_inst_is_valuetype (t))
1307                         return STACK_VTYPE;
1308                 else
1309                         return STACK_OBJ;
1310                 break;
1311         default:
1312                 g_assert_not_reached ();
1313         }
1314
1315         return -1;
1316 }
1317
1318 static MonoClass*
1319 array_access_to_klass (int opcode)
1320 {
1321         switch (opcode) {
1322         case CEE_LDELEM_U1:
1323                 return mono_defaults.byte_class;
1324         case CEE_LDELEM_U2:
1325                 return mono_defaults.uint16_class;
1326         case CEE_LDELEM_I:
1327         case CEE_STELEM_I:
1328                 return mono_defaults.int_class;
1329         case CEE_LDELEM_I1:
1330         case CEE_STELEM_I1:
1331                 return mono_defaults.sbyte_class;
1332         case CEE_LDELEM_I2:
1333         case CEE_STELEM_I2:
1334                 return mono_defaults.int16_class;
1335         case CEE_LDELEM_I4:
1336         case CEE_STELEM_I4:
1337                 return mono_defaults.int32_class;
1338         case CEE_LDELEM_U4:
1339                 return mono_defaults.uint32_class;
1340         case CEE_LDELEM_I8:
1341         case CEE_STELEM_I8:
1342                 return mono_defaults.int64_class;
1343         case CEE_LDELEM_R4:
1344         case CEE_STELEM_R4:
1345                 return mono_defaults.single_class;
1346         case CEE_LDELEM_R8:
1347         case CEE_STELEM_R8:
1348                 return mono_defaults.double_class;
1349         case CEE_LDELEM_REF:
1350         case CEE_STELEM_REF:
1351                 return mono_defaults.object_class;
1352         default:
1353                 g_assert_not_reached ();
1354         }
1355         return NULL;
1356 }
1357
1358 /*
1359  * We try to share variables when possible
1360  */
1361 static MonoInst *
1362 mono_compile_get_interface_var (MonoCompile *cfg, int slot, MonoInst *ins)
1363 {
1364         MonoInst *res;
1365         int pos, vnum;
1366
1367         /* inlining can result in deeper stacks */ 
1368         if (slot >= cfg->header->max_stack)
1369                 return mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1370
1371         pos = ins->type - 1 + slot * STACK_MAX;
1372
1373         switch (ins->type) {
1374         case STACK_I4:
1375         case STACK_I8:
1376         case STACK_R8:
1377         case STACK_PTR:
1378         case STACK_MP:
1379         case STACK_OBJ:
1380                 if ((vnum = cfg->intvars [pos]))
1381                         return cfg->varinfo [vnum];
1382                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1383                 cfg->intvars [pos] = res->inst_c0;
1384                 break;
1385         default:
1386                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1387         }
1388         return res;
1389 }
1390
1391 static void
1392 mono_save_token_info (MonoCompile *cfg, MonoImage *image, guint32 token, gpointer key)
1393 {
1394         /* 
1395          * Don't use this if a generic_context is set, since that means AOT can't
1396          * look up the method using just the image+token.
1397          * table == 0 means this is a reference made from a wrapper.
1398          */
1399         if (cfg->compile_aot && !cfg->generic_context && (mono_metadata_token_table (token) > 0)) {
1400                 MonoJumpInfoToken *jump_info_token = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoToken));
1401                 jump_info_token->image = image;
1402                 jump_info_token->token = token;
1403                 g_hash_table_insert (cfg->token_info_hash, key, jump_info_token);
1404         }
1405 }
1406
1407 /*
1408  * This function is called to handle items that are left on the evaluation stack
1409  * at basic block boundaries. What happens is that we save the values to local variables
1410  * and we reload them later when first entering the target basic block (with the
1411  * handle_loaded_temps () function).
1412  * A single joint point will use the same variables (stored in the array bb->out_stack or
1413  * bb->in_stack, if the basic block is before or after the joint point).
1414  *
1415  * This function needs to be called _before_ emitting the last instruction of
1416  * the bb (i.e. before emitting a branch).
1417  * If the stack merge fails at a join point, cfg->unverifiable is set.
1418  */
1419 static void
1420 handle_stack_args (MonoCompile *cfg, MonoInst **sp, int count)
1421 {
1422         int i, bindex;
1423         MonoBasicBlock *bb = cfg->cbb;
1424         MonoBasicBlock *outb;
1425         MonoInst *inst, **locals;
1426         gboolean found;
1427
1428         if (!count)
1429                 return;
1430         if (cfg->verbose_level > 3)
1431                 printf ("%d item(s) on exit from B%d\n", count, bb->block_num);
1432         if (!bb->out_scount) {
1433                 bb->out_scount = count;
1434                 //printf ("bblock %d has out:", bb->block_num);
1435                 found = FALSE;
1436                 for (i = 0; i < bb->out_count; ++i) {
1437                         outb = bb->out_bb [i];
1438                         /* exception handlers are linked, but they should not be considered for stack args */
1439                         if (outb->flags & BB_EXCEPTION_HANDLER)
1440                                 continue;
1441                         //printf (" %d", outb->block_num);
1442                         if (outb->in_stack) {
1443                                 found = TRUE;
1444                                 bb->out_stack = outb->in_stack;
1445                                 break;
1446                         }
1447                 }
1448                 //printf ("\n");
1449                 if (!found) {
1450                         bb->out_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * count);
1451                         for (i = 0; i < count; ++i) {
1452                                 /* 
1453                                  * try to reuse temps already allocated for this purpouse, if they occupy the same
1454                                  * stack slot and if they are of the same type.
1455                                  * This won't cause conflicts since if 'local' is used to 
1456                                  * store one of the values in the in_stack of a bblock, then
1457                                  * the same variable will be used for the same outgoing stack 
1458                                  * slot as well. 
1459                                  * This doesn't work when inlining methods, since the bblocks
1460                                  * in the inlined methods do not inherit their in_stack from
1461                                  * the bblock they are inlined to. See bug #58863 for an
1462                                  * example.
1463                                  */
1464                                 if (cfg->inlined_method)
1465                                         bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
1466                                 else
1467                                         bb->out_stack [i] = mono_compile_get_interface_var (cfg, i, sp [i]);
1468                         }
1469                 }
1470         }
1471
1472         for (i = 0; i < bb->out_count; ++i) {
1473                 outb = bb->out_bb [i];
1474                 /* exception handlers are linked, but they should not be considered for stack args */
1475                 if (outb->flags & BB_EXCEPTION_HANDLER)
1476                         continue;
1477                 if (outb->in_scount) {
1478                         if (outb->in_scount != bb->out_scount) {
1479                                 cfg->unverifiable = TRUE;
1480                                 return;
1481                         }
1482                         continue; /* check they are the same locals */
1483                 }
1484                 outb->in_scount = count;
1485                 outb->in_stack = bb->out_stack;
1486         }
1487
1488         locals = bb->out_stack;
1489         cfg->cbb = bb;
1490         for (i = 0; i < count; ++i) {
1491                 EMIT_NEW_TEMPSTORE (cfg, inst, locals [i]->inst_c0, sp [i]);
1492                 inst->cil_code = sp [i]->cil_code;
1493                 sp [i] = locals [i];
1494                 if (cfg->verbose_level > 3)
1495                         printf ("storing %d to temp %d\n", i, (int)locals [i]->inst_c0);
1496         }
1497
1498         /*
1499          * It is possible that the out bblocks already have in_stack assigned, and
1500          * the in_stacks differ. In this case, we will store to all the different 
1501          * in_stacks.
1502          */
1503
1504         found = TRUE;
1505         bindex = 0;
1506         while (found) {
1507                 /* Find a bblock which has a different in_stack */
1508                 found = FALSE;
1509                 while (bindex < bb->out_count) {
1510                         outb = bb->out_bb [bindex];
1511                         /* exception handlers are linked, but they should not be considered for stack args */
1512                         if (outb->flags & BB_EXCEPTION_HANDLER) {
1513                                 bindex++;
1514                                 continue;
1515                         }
1516                         if (outb->in_stack != locals) {
1517                                 for (i = 0; i < count; ++i) {
1518                                         EMIT_NEW_TEMPSTORE (cfg, inst, outb->in_stack [i]->inst_c0, sp [i]);
1519                                         inst->cil_code = sp [i]->cil_code;
1520                                         sp [i] = locals [i];
1521                                         if (cfg->verbose_level > 3)
1522                                                 printf ("storing %d to temp %d\n", i, (int)outb->in_stack [i]->inst_c0);
1523                                 }
1524                                 locals = outb->in_stack;
1525                                 found = TRUE;
1526                                 break;
1527                         }
1528                         bindex ++;
1529                 }
1530         }
1531 }
1532
1533 static MonoInst*
1534 emit_runtime_constant (MonoCompile *cfg, MonoJumpInfoType patch_type, gpointer data)
1535 {
1536         MonoInst *ins;
1537
1538         if (cfg->compile_aot) {
1539                 EMIT_NEW_AOTCONST (cfg, ins, patch_type, data);
1540         } else {
1541                 MonoJumpInfo ji;
1542                 gpointer target;
1543
1544                 ji.type = patch_type;
1545                 ji.data.target = data;
1546                 target = mono_resolve_patch_target (NULL, cfg->domain, NULL, &ji, FALSE);
1547
1548                 EMIT_NEW_PCONST (cfg, ins, target);
1549         }
1550         return ins;
1551 }
1552
1553 static void
1554 mini_emit_interface_bitmap_check (MonoCompile *cfg, int intf_bit_reg, int base_reg, int offset, MonoClass *klass)
1555 {
1556         int ibitmap_reg = alloc_preg (cfg);
1557 #ifdef COMPRESSED_INTERFACE_BITMAP
1558         MonoInst *args [2];
1559         MonoInst *res, *ins;
1560         NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, ibitmap_reg, base_reg, offset);
1561         MONO_ADD_INS (cfg->cbb, ins);
1562         args [0] = ins;
1563         args [1] = emit_runtime_constant (cfg, MONO_PATCH_INFO_IID, klass);
1564         res = mono_emit_jit_icall (cfg, mono_class_interface_match, args);
1565         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, intf_bit_reg, res->dreg);
1566 #else
1567         int ibitmap_byte_reg = alloc_preg (cfg);
1568
1569         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, ibitmap_reg, base_reg, offset);
1570
1571         if (cfg->compile_aot) {
1572                 int iid_reg = alloc_preg (cfg);
1573                 int shifted_iid_reg = alloc_preg (cfg);
1574                 int ibitmap_byte_address_reg = alloc_preg (cfg);
1575                 int masked_iid_reg = alloc_preg (cfg);
1576                 int iid_one_bit_reg = alloc_preg (cfg);
1577                 int iid_bit_reg = alloc_preg (cfg);
1578                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1579                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, shifted_iid_reg, iid_reg, 3);
1580                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, ibitmap_byte_address_reg, ibitmap_reg, shifted_iid_reg);
1581                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, ibitmap_byte_reg, ibitmap_byte_address_reg, 0);
1582                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, masked_iid_reg, iid_reg, 7);
1583                 MONO_EMIT_NEW_ICONST (cfg, iid_one_bit_reg, 1);
1584                 MONO_EMIT_NEW_BIALU (cfg, OP_ISHL, iid_bit_reg, iid_one_bit_reg, masked_iid_reg);
1585                 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, intf_bit_reg, ibitmap_byte_reg, iid_bit_reg);
1586         } else {
1587                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, ibitmap_byte_reg, ibitmap_reg, klass->interface_id >> 3);
1588                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, intf_bit_reg, ibitmap_byte_reg, 1 << (klass->interface_id & 7));
1589         }
1590 #endif
1591 }
1592
1593 /* 
1594  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoClass
1595  * stored in "klass_reg" implements the interface "klass".
1596  */
1597 static void
1598 mini_emit_load_intf_bit_reg_class (MonoCompile *cfg, int intf_bit_reg, int klass_reg, MonoClass *klass)
1599 {
1600         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, interface_bitmap), klass);
1601 }
1602
1603 /* 
1604  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoVTable
1605  * stored in "vtable_reg" implements the interface "klass".
1606  */
1607 static void
1608 mini_emit_load_intf_bit_reg_vtable (MonoCompile *cfg, int intf_bit_reg, int vtable_reg, MonoClass *klass)
1609 {
1610         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, interface_bitmap), klass);
1611 }
1612
1613 /* 
1614  * Emit code which checks whenever the interface id of @klass is smaller than
1615  * than the value given by max_iid_reg.
1616 */
1617 static void
1618 mini_emit_max_iid_check (MonoCompile *cfg, int max_iid_reg, MonoClass *klass,
1619                                                  MonoBasicBlock *false_target)
1620 {
1621         if (cfg->compile_aot) {
1622                 int iid_reg = alloc_preg (cfg);
1623                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1624                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, max_iid_reg, iid_reg);
1625         }
1626         else
1627                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, max_iid_reg, klass->interface_id);
1628         if (false_target)
1629                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1630         else
1631                 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1632 }
1633
1634 /* Same as above, but obtains max_iid from a vtable */
1635 static void
1636 mini_emit_max_iid_check_vtable (MonoCompile *cfg, int vtable_reg, MonoClass *klass,
1637                                                                  MonoBasicBlock *false_target)
1638 {
1639         int max_iid_reg = alloc_preg (cfg);
1640                 
1641         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, max_interface_id));
1642         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1643 }
1644
1645 /* Same as above, but obtains max_iid from a klass */
1646 static void
1647 mini_emit_max_iid_check_class (MonoCompile *cfg, int klass_reg, MonoClass *klass,
1648                                                                  MonoBasicBlock *false_target)
1649 {
1650         int max_iid_reg = alloc_preg (cfg);
1651
1652         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, max_interface_id));
1653         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1654 }
1655
1656 static void
1657 mini_emit_isninst_cast_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_ins, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1658 {
1659         int idepth_reg = alloc_preg (cfg);
1660         int stypes_reg = alloc_preg (cfg);
1661         int stype = alloc_preg (cfg);
1662
1663         mono_class_setup_supertypes (klass);
1664
1665         if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1666                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth));
1667                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1668                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1669         }
1670         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes));
1671         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1672         if (klass_ins) {
1673                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, klass_ins->dreg);
1674         } else if (cfg->compile_aot) {
1675                 int const_reg = alloc_preg (cfg);
1676                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1677                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, const_reg);
1678         } else {
1679                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, stype, klass);
1680         }
1681         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, true_target);
1682 }
1683
1684 static void
1685 mini_emit_isninst_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1686 {
1687         mini_emit_isninst_cast_inst (cfg, klass_reg, klass, NULL, false_target, true_target);
1688 }
1689
1690 static void
1691 mini_emit_iface_cast (MonoCompile *cfg, int vtable_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1692 {
1693         int intf_reg = alloc_preg (cfg);
1694
1695         mini_emit_max_iid_check_vtable (cfg, vtable_reg, klass, false_target);
1696         mini_emit_load_intf_bit_reg_vtable (cfg, intf_reg, vtable_reg, klass);
1697         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_reg, 0);
1698         if (true_target)
1699                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1700         else
1701                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");               
1702 }
1703
1704 /*
1705  * Variant of the above that takes a register to the class, not the vtable.
1706  */
1707 static void
1708 mini_emit_iface_class_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1709 {
1710         int intf_bit_reg = alloc_preg (cfg);
1711
1712         mini_emit_max_iid_check_class (cfg, klass_reg, klass, false_target);
1713         mini_emit_load_intf_bit_reg_class (cfg, intf_bit_reg, klass_reg, klass);
1714         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_bit_reg, 0);
1715         if (true_target)
1716                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1717         else
1718                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
1719 }
1720
1721 static inline void
1722 mini_emit_class_check_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_inst)
1723 {
1724         if (klass_inst) {
1725                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_inst->dreg);
1726         } else {
1727                 MonoInst *ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, klass);
1728                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, ins->dreg);
1729         }
1730         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1731 }
1732
1733 static inline void
1734 mini_emit_class_check (MonoCompile *cfg, int klass_reg, MonoClass *klass)
1735 {
1736         mini_emit_class_check_inst (cfg, klass_reg, klass, NULL);
1737 }
1738
1739 static inline void
1740 mini_emit_class_check_branch (MonoCompile *cfg, int klass_reg, MonoClass *klass, int branch_op, MonoBasicBlock *target)
1741 {
1742         if (cfg->compile_aot) {
1743                 int const_reg = alloc_preg (cfg);
1744                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1745                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, const_reg);
1746         } else {
1747                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
1748         }
1749         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, branch_op, target);
1750 }
1751
1752 static void
1753 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null);
1754         
1755 static void
1756 mini_emit_castclass_inst (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoInst *klass_inst, MonoBasicBlock *object_is_null)
1757 {
1758         if (klass->rank) {
1759                 int rank_reg = alloc_preg (cfg);
1760                 int eclass_reg = alloc_preg (cfg);
1761
1762                 g_assert (!klass_inst);
1763                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, rank));
1764                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
1765                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1766                 //              MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
1767                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
1768                 if (klass->cast_class == mono_defaults.object_class) {
1769                         int parent_reg = alloc_preg (cfg);
1770                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
1771                         mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, object_is_null);
1772                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1773                 } else if (klass->cast_class == mono_defaults.enum_class->parent) {
1774                         mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, object_is_null);
1775                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1776                 } else if (klass->cast_class == mono_defaults.enum_class) {
1777                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1778                 } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1779                         mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, NULL, NULL);
1780                 } else {
1781                         // Pass -1 as obj_reg to skip the check below for arrays of arrays
1782                         mini_emit_castclass (cfg, -1, eclass_reg, klass->cast_class, object_is_null);
1783                 }
1784
1785                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY) && (obj_reg != -1)) {
1786                         /* Check that the object is a vector too */
1787                         int bounds_reg = alloc_preg (cfg);
1788                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
1789                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
1790                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1791                 }
1792         } else {
1793                 int idepth_reg = alloc_preg (cfg);
1794                 int stypes_reg = alloc_preg (cfg);
1795                 int stype = alloc_preg (cfg);
1796
1797                 mono_class_setup_supertypes (klass);
1798
1799                 if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1800                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth));
1801                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1802                         MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1803                 }
1804                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes));
1805                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1806                 mini_emit_class_check_inst (cfg, stype, klass, klass_inst);
1807         }
1808 }
1809
1810 static void
1811 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null)
1812 {
1813         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, NULL, object_is_null);
1814 }
1815
1816 static void 
1817 mini_emit_memset (MonoCompile *cfg, int destreg, int offset, int size, int val, int align)
1818 {
1819         int val_reg;
1820
1821         g_assert (val == 0);
1822
1823         if (align == 0)
1824                 align = 4;
1825
1826         if ((size <= SIZEOF_REGISTER) && (size <= align)) {
1827                 switch (size) {
1828                 case 1:
1829                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, destreg, offset, val);
1830                         return;
1831                 case 2:
1832                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI2_MEMBASE_IMM, destreg, offset, val);
1833                         return;
1834                 case 4:
1835                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI4_MEMBASE_IMM, destreg, offset, val);
1836                         return;
1837 #if SIZEOF_REGISTER == 8
1838                 case 8:
1839                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI8_MEMBASE_IMM, destreg, offset, val);
1840                         return;
1841 #endif
1842                 }
1843         }
1844
1845         val_reg = alloc_preg (cfg);
1846
1847         if (SIZEOF_REGISTER == 8)
1848                 MONO_EMIT_NEW_I8CONST (cfg, val_reg, val);
1849         else
1850                 MONO_EMIT_NEW_ICONST (cfg, val_reg, val);
1851
1852         if (align < 4) {
1853                 /* This could be optimized further if neccesary */
1854                 while (size >= 1) {
1855                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1856                         offset += 1;
1857                         size -= 1;
1858                 }
1859                 return;
1860         }       
1861
1862         if (!cfg->backend->no_unaligned_access && SIZEOF_REGISTER == 8) {
1863                 if (offset % 8) {
1864                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1865                         offset += 4;
1866                         size -= 4;
1867                 }
1868                 while (size >= 8) {
1869                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, offset, val_reg);
1870                         offset += 8;
1871                         size -= 8;
1872                 }
1873         }       
1874
1875         while (size >= 4) {
1876                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1877                 offset += 4;
1878                 size -= 4;
1879         }
1880         while (size >= 2) {
1881                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, val_reg);
1882                 offset += 2;
1883                 size -= 2;
1884         }
1885         while (size >= 1) {
1886                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1887                 offset += 1;
1888                 size -= 1;
1889         }
1890 }
1891
1892 void 
1893 mini_emit_memcpy (MonoCompile *cfg, int destreg, int doffset, int srcreg, int soffset, int size, int align)
1894 {
1895         int cur_reg;
1896
1897         if (align == 0)
1898                 align = 4;
1899
1900         /*FIXME arbitrary hack to avoid unbound code expansion.*/
1901         g_assert (size < 10000);
1902
1903         if (align < 4) {
1904                 /* This could be optimized further if neccesary */
1905                 while (size >= 1) {
1906                         cur_reg = alloc_preg (cfg);
1907                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1908                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1909                         doffset += 1;
1910                         soffset += 1;
1911                         size -= 1;
1912                 }
1913         }
1914
1915         if (!cfg->backend->no_unaligned_access && SIZEOF_REGISTER == 8) {
1916                 while (size >= 8) {
1917                         cur_reg = alloc_preg (cfg);
1918                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI8_MEMBASE, cur_reg, srcreg, soffset);
1919                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, doffset, cur_reg);
1920                         doffset += 8;
1921                         soffset += 8;
1922                         size -= 8;
1923                 }
1924         }       
1925
1926         while (size >= 4) {
1927                 cur_reg = alloc_preg (cfg);
1928                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, cur_reg, srcreg, soffset);
1929                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, doffset, cur_reg);
1930                 doffset += 4;
1931                 soffset += 4;
1932                 size -= 4;
1933         }
1934         while (size >= 2) {
1935                 cur_reg = alloc_preg (cfg);
1936                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, cur_reg, srcreg, soffset);
1937                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, doffset, cur_reg);
1938                 doffset += 2;
1939                 soffset += 2;
1940                 size -= 2;
1941         }
1942         while (size >= 1) {
1943                 cur_reg = alloc_preg (cfg);
1944                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1945                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1946                 doffset += 1;
1947                 soffset += 1;
1948                 size -= 1;
1949         }
1950 }
1951
1952 static void
1953 emit_tls_set (MonoCompile *cfg, int sreg1, int tls_key)
1954 {
1955         MonoInst *ins, *c;
1956
1957         if (cfg->compile_aot) {
1958                 EMIT_NEW_TLS_OFFSETCONST (cfg, c, tls_key);
1959                 MONO_INST_NEW (cfg, ins, OP_TLS_SET_REG);
1960                 ins->sreg1 = sreg1;
1961                 ins->sreg2 = c->dreg;
1962                 MONO_ADD_INS (cfg->cbb, ins);
1963         } else {
1964                 MONO_INST_NEW (cfg, ins, OP_TLS_SET);
1965                 ins->sreg1 = sreg1;
1966                 ins->inst_offset = mini_get_tls_offset (tls_key);
1967                 MONO_ADD_INS (cfg->cbb, ins);
1968         }
1969 }
1970
1971 /*
1972  * emit_push_lmf:
1973  *
1974  *   Emit IR to push the current LMF onto the LMF stack.
1975  */
1976 static void
1977 emit_push_lmf (MonoCompile *cfg)
1978 {
1979         /*
1980          * Emit IR to push the LMF:
1981          * lmf_addr = <lmf_addr from tls>
1982          * lmf->lmf_addr = lmf_addr
1983          * lmf->prev_lmf = *lmf_addr
1984          * *lmf_addr = lmf
1985          */
1986         int lmf_reg, prev_lmf_reg;
1987         MonoInst *ins, *lmf_ins;
1988
1989         if (!cfg->lmf_ir)
1990                 return;
1991
1992         if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
1993                 /* Load current lmf */
1994                 lmf_ins = mono_get_lmf_intrinsic (cfg);
1995                 g_assert (lmf_ins);
1996                 MONO_ADD_INS (cfg->cbb, lmf_ins);
1997                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
1998                 lmf_reg = ins->dreg;
1999                 /* Save previous_lmf */
2000                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), lmf_ins->dreg);
2001                 /* Set new LMF */
2002                 emit_tls_set (cfg, lmf_reg, TLS_KEY_LMF);
2003         } else {
2004                 /*
2005                  * Store lmf_addr in a variable, so it can be allocated to a global register.
2006                  */
2007                 if (!cfg->lmf_addr_var)
2008                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2009
2010 #ifdef HOST_WIN32
2011                 ins = mono_get_jit_tls_intrinsic (cfg);
2012                 if (ins) {
2013                         int jit_tls_dreg = ins->dreg;
2014
2015                         MONO_ADD_INS (cfg->cbb, ins);
2016                         lmf_reg = alloc_preg (cfg);
2017                         EMIT_NEW_BIALU_IMM (cfg, lmf_ins, OP_PADD_IMM, lmf_reg, jit_tls_dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, lmf));
2018                 } else {
2019                         lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
2020                 }
2021 #else
2022                 lmf_ins = mono_get_lmf_addr_intrinsic (cfg);
2023                 if (lmf_ins) {
2024                         MONO_ADD_INS (cfg->cbb, lmf_ins);
2025                 } else {
2026 #ifdef TARGET_IOS
2027                         MonoInst *args [16], *jit_tls_ins, *ins;
2028
2029                         /* Inline mono_get_lmf_addr () */
2030                         /* jit_tls = pthread_getspecific (mono_jit_tls_id); lmf_addr = &jit_tls->lmf; */
2031
2032                         /* Load mono_jit_tls_id */
2033                         if (cfg->compile_aot)
2034                                 EMIT_NEW_AOTCONST (cfg, args [0], MONO_PATCH_INFO_JIT_TLS_ID, NULL);
2035                         else
2036                                 EMIT_NEW_ICONST (cfg, args [0], mono_jit_tls_id);
2037                         /* call pthread_getspecific () */
2038                         jit_tls_ins = mono_emit_jit_icall (cfg, pthread_getspecific, args);
2039                         /* lmf_addr = &jit_tls->lmf */
2040                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, cfg->lmf_addr_var->dreg, jit_tls_ins->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, lmf));
2041                         lmf_ins = ins;
2042 #else
2043                         lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
2044 #endif
2045                 }
2046 #endif
2047                 lmf_ins->dreg = cfg->lmf_addr_var->dreg;
2048
2049                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2050                 lmf_reg = ins->dreg;
2051
2052                 prev_lmf_reg = alloc_preg (cfg);
2053                 /* Save previous_lmf */
2054                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, cfg->lmf_addr_var->dreg, 0);
2055                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), prev_lmf_reg);
2056                 /* Set new lmf */
2057                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, cfg->lmf_addr_var->dreg, 0, lmf_reg);
2058         }
2059 }
2060
2061 /*
2062  * emit_pop_lmf:
2063  *
2064  *   Emit IR to pop the current LMF from the LMF stack.
2065  */
2066 static void
2067 emit_pop_lmf (MonoCompile *cfg)
2068 {
2069         int lmf_reg, lmf_addr_reg, prev_lmf_reg;
2070         MonoInst *ins;
2071
2072         if (!cfg->lmf_ir)
2073                 return;
2074
2075         EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2076         lmf_reg = ins->dreg;
2077
2078         if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
2079                 /* Load previous_lmf */
2080                 prev_lmf_reg = alloc_preg (cfg);
2081                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
2082                 /* Set new LMF */
2083                 emit_tls_set (cfg, prev_lmf_reg, TLS_KEY_LMF);
2084         } else {
2085                 /*
2086                  * Emit IR to pop the LMF:
2087                  * *(lmf->lmf_addr) = lmf->prev_lmf
2088                  */
2089                 /* This could be called before emit_push_lmf () */
2090                 if (!cfg->lmf_addr_var)
2091                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2092                 lmf_addr_reg = cfg->lmf_addr_var->dreg;
2093
2094                 prev_lmf_reg = alloc_preg (cfg);
2095                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
2096                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_addr_reg, 0, prev_lmf_reg);
2097         }
2098 }
2099
2100 static void
2101 emit_instrumentation_call (MonoCompile *cfg, void *func)
2102 {
2103         MonoInst *iargs [1];
2104
2105         /*
2106          * Avoid instrumenting inlined methods since it can
2107          * distort profiling results.
2108          */
2109         if (cfg->method != cfg->current_method)
2110                 return;
2111
2112         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE) {
2113                 EMIT_NEW_METHODCONST (cfg, iargs [0], cfg->method);
2114                 mono_emit_jit_icall (cfg, func, iargs);
2115         }
2116 }
2117
2118 static int
2119 ret_type_to_call_opcode (MonoCompile *cfg, MonoType *type, int calli, int virt)
2120 {
2121 handle_enum:
2122         type = mini_get_underlying_type (type);
2123         switch (type->type) {
2124         case MONO_TYPE_VOID:
2125                 return calli? OP_VOIDCALL_REG: virt? OP_VOIDCALL_MEMBASE: OP_VOIDCALL;
2126         case MONO_TYPE_I1:
2127         case MONO_TYPE_U1:
2128         case MONO_TYPE_I2:
2129         case MONO_TYPE_U2:
2130         case MONO_TYPE_I4:
2131         case MONO_TYPE_U4:
2132                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2133         case MONO_TYPE_I:
2134         case MONO_TYPE_U:
2135         case MONO_TYPE_PTR:
2136         case MONO_TYPE_FNPTR:
2137                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2138         case MONO_TYPE_CLASS:
2139         case MONO_TYPE_STRING:
2140         case MONO_TYPE_OBJECT:
2141         case MONO_TYPE_SZARRAY:
2142         case MONO_TYPE_ARRAY:    
2143                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2144         case MONO_TYPE_I8:
2145         case MONO_TYPE_U8:
2146                 return calli? OP_LCALL_REG: virt? OP_LCALL_MEMBASE: OP_LCALL;
2147         case MONO_TYPE_R4:
2148                 if (cfg->r4fp)
2149                         return calli? OP_RCALL_REG: virt? OP_RCALL_MEMBASE: OP_RCALL;
2150                 else
2151                         return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
2152         case MONO_TYPE_R8:
2153                 return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
2154         case MONO_TYPE_VALUETYPE:
2155                 if (type->data.klass->enumtype) {
2156                         type = mono_class_enum_basetype (type->data.klass);
2157                         goto handle_enum;
2158                 } else
2159                         return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2160         case MONO_TYPE_TYPEDBYREF:
2161                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2162         case MONO_TYPE_GENERICINST:
2163                 type = &type->data.generic_class->container_class->byval_arg;
2164                 goto handle_enum;
2165         case MONO_TYPE_VAR:
2166         case MONO_TYPE_MVAR:
2167                 /* gsharedvt */
2168                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2169         default:
2170                 g_error ("unknown type 0x%02x in ret_type_to_call_opcode", type->type);
2171         }
2172         return -1;
2173 }
2174
2175 /*
2176  * target_type_is_incompatible:
2177  * @cfg: MonoCompile context
2178  *
2179  * Check that the item @arg on the evaluation stack can be stored
2180  * in the target type (can be a local, or field, etc).
2181  * The cfg arg can be used to check if we need verification or just
2182  * validity checks.
2183  *
2184  * Returns: non-0 value if arg can't be stored on a target.
2185  */
2186 static int
2187 target_type_is_incompatible (MonoCompile *cfg, MonoType *target, MonoInst *arg)
2188 {
2189         MonoType *simple_type;
2190         MonoClass *klass;
2191
2192         if (target->byref) {
2193                 /* FIXME: check that the pointed to types match */
2194                 if (arg->type == STACK_MP)
2195                         return target->type != MONO_TYPE_I && arg->klass != mono_class_from_mono_type (target);
2196                 if (arg->type == STACK_PTR)
2197                         return 0;
2198                 return 1;
2199         }
2200
2201         simple_type = mini_get_underlying_type (target);
2202         switch (simple_type->type) {
2203         case MONO_TYPE_VOID:
2204                 return 1;
2205         case MONO_TYPE_I1:
2206         case MONO_TYPE_U1:
2207         case MONO_TYPE_I2:
2208         case MONO_TYPE_U2:
2209         case MONO_TYPE_I4:
2210         case MONO_TYPE_U4:
2211                 if (arg->type != STACK_I4 && arg->type != STACK_PTR)
2212                         return 1;
2213                 return 0;
2214         case MONO_TYPE_PTR:
2215                 /* STACK_MP is needed when setting pinned locals */
2216                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2217                         return 1;
2218                 return 0;
2219         case MONO_TYPE_I:
2220         case MONO_TYPE_U:
2221         case MONO_TYPE_FNPTR:
2222                 /* 
2223                  * Some opcodes like ldloca returns 'transient pointers' which can be stored in
2224                  * in native int. (#688008).
2225                  */
2226                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2227                         return 1;
2228                 return 0;
2229         case MONO_TYPE_CLASS:
2230         case MONO_TYPE_STRING:
2231         case MONO_TYPE_OBJECT:
2232         case MONO_TYPE_SZARRAY:
2233         case MONO_TYPE_ARRAY:    
2234                 if (arg->type != STACK_OBJ)
2235                         return 1;
2236                 /* FIXME: check type compatibility */
2237                 return 0;
2238         case MONO_TYPE_I8:
2239         case MONO_TYPE_U8:
2240                 if (arg->type != STACK_I8)
2241                         return 1;
2242                 return 0;
2243         case MONO_TYPE_R4:
2244                 if (arg->type != cfg->r4_stack_type)
2245                         return 1;
2246                 return 0;
2247         case MONO_TYPE_R8:
2248                 if (arg->type != STACK_R8)
2249                         return 1;
2250                 return 0;
2251         case MONO_TYPE_VALUETYPE:
2252                 if (arg->type != STACK_VTYPE)
2253                         return 1;
2254                 klass = mono_class_from_mono_type (simple_type);
2255                 if (klass != arg->klass)
2256                         return 1;
2257                 return 0;
2258         case MONO_TYPE_TYPEDBYREF:
2259                 if (arg->type != STACK_VTYPE)
2260                         return 1;
2261                 klass = mono_class_from_mono_type (simple_type);
2262                 if (klass != arg->klass)
2263                         return 1;
2264                 return 0;
2265         case MONO_TYPE_GENERICINST:
2266                 if (mono_type_generic_inst_is_valuetype (simple_type)) {
2267                         if (arg->type != STACK_VTYPE)
2268                                 return 1;
2269                         klass = mono_class_from_mono_type (simple_type);
2270                         /* The second cases is needed when doing partial sharing */
2271                         if (klass != arg->klass && mono_class_from_mono_type (target) != arg->klass)
2272                                 return 1;
2273                         return 0;
2274                 } else {
2275                         if (arg->type != STACK_OBJ)
2276                                 return 1;
2277                         /* FIXME: check type compatibility */
2278                         return 0;
2279                 }
2280         case MONO_TYPE_VAR:
2281         case MONO_TYPE_MVAR:
2282                 g_assert (cfg->gshared);
2283                 if (mini_type_var_is_vt (simple_type)) {
2284                         if (arg->type != STACK_VTYPE)
2285                                 return 1;
2286                 } else {
2287                         if (arg->type != STACK_OBJ)
2288                                 return 1;
2289                 }
2290                 return 0;
2291         default:
2292                 g_error ("unknown type 0x%02x in target_type_is_incompatible", simple_type->type);
2293         }
2294         return 1;
2295 }
2296
2297 /*
2298  * Prepare arguments for passing to a function call.
2299  * Return a non-zero value if the arguments can't be passed to the given
2300  * signature.
2301  * The type checks are not yet complete and some conversions may need
2302  * casts on 32 or 64 bit architectures.
2303  *
2304  * FIXME: implement this using target_type_is_incompatible ()
2305  */
2306 static int
2307 check_call_signature (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args)
2308 {
2309         MonoType *simple_type;
2310         int i;
2311
2312         if (sig->hasthis) {
2313                 if (args [0]->type != STACK_OBJ && args [0]->type != STACK_MP && args [0]->type != STACK_PTR)
2314                         return 1;
2315                 args++;
2316         }
2317         for (i = 0; i < sig->param_count; ++i) {
2318                 if (sig->params [i]->byref) {
2319                         if (args [i]->type != STACK_MP && args [i]->type != STACK_PTR)
2320                                 return 1;
2321                         continue;
2322                 }
2323                 simple_type = mini_get_underlying_type (sig->params [i]);
2324 handle_enum:
2325                 switch (simple_type->type) {
2326                 case MONO_TYPE_VOID:
2327                         return 1;
2328                         continue;
2329                 case MONO_TYPE_I1:
2330                 case MONO_TYPE_U1:
2331                 case MONO_TYPE_I2:
2332                 case MONO_TYPE_U2:
2333                 case MONO_TYPE_I4:
2334                 case MONO_TYPE_U4:
2335                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR)
2336                                 return 1;
2337                         continue;
2338                 case MONO_TYPE_I:
2339                 case MONO_TYPE_U:
2340                 case MONO_TYPE_PTR:
2341                 case MONO_TYPE_FNPTR:
2342                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR && args [i]->type != STACK_MP && args [i]->type != STACK_OBJ)
2343                                 return 1;
2344                         continue;
2345                 case MONO_TYPE_CLASS:
2346                 case MONO_TYPE_STRING:
2347                 case MONO_TYPE_OBJECT:
2348                 case MONO_TYPE_SZARRAY:
2349                 case MONO_TYPE_ARRAY:    
2350                         if (args [i]->type != STACK_OBJ)
2351                                 return 1;
2352                         continue;
2353                 case MONO_TYPE_I8:
2354                 case MONO_TYPE_U8:
2355                         if (args [i]->type != STACK_I8)
2356                                 return 1;
2357                         continue;
2358                 case MONO_TYPE_R4:
2359                         if (args [i]->type != cfg->r4_stack_type)
2360                                 return 1;
2361                         continue;
2362                 case MONO_TYPE_R8:
2363                         if (args [i]->type != STACK_R8)
2364                                 return 1;
2365                         continue;
2366                 case MONO_TYPE_VALUETYPE:
2367                         if (simple_type->data.klass->enumtype) {
2368                                 simple_type = mono_class_enum_basetype (simple_type->data.klass);
2369                                 goto handle_enum;
2370                         }
2371                         if (args [i]->type != STACK_VTYPE)
2372                                 return 1;
2373                         continue;
2374                 case MONO_TYPE_TYPEDBYREF:
2375                         if (args [i]->type != STACK_VTYPE)
2376                                 return 1;
2377                         continue;
2378                 case MONO_TYPE_GENERICINST:
2379                         simple_type = &simple_type->data.generic_class->container_class->byval_arg;
2380                         goto handle_enum;
2381                 case MONO_TYPE_VAR:
2382                 case MONO_TYPE_MVAR:
2383                         /* gsharedvt */
2384                         if (args [i]->type != STACK_VTYPE)
2385                                 return 1;
2386                         continue;
2387                 default:
2388                         g_error ("unknown type 0x%02x in check_call_signature",
2389                                  simple_type->type);
2390                 }
2391         }
2392         return 0;
2393 }
2394
2395 static int
2396 callvirt_to_call (int opcode)
2397 {
2398         switch (opcode) {
2399         case OP_CALL_MEMBASE:
2400                 return OP_CALL;
2401         case OP_VOIDCALL_MEMBASE:
2402                 return OP_VOIDCALL;
2403         case OP_FCALL_MEMBASE:
2404                 return OP_FCALL;
2405         case OP_RCALL_MEMBASE:
2406                 return OP_RCALL;
2407         case OP_VCALL_MEMBASE:
2408                 return OP_VCALL;
2409         case OP_LCALL_MEMBASE:
2410                 return OP_LCALL;
2411         default:
2412                 g_assert_not_reached ();
2413         }
2414
2415         return -1;
2416 }
2417
2418 static int
2419 callvirt_to_call_reg (int opcode)
2420 {
2421         switch (opcode) {
2422         case OP_CALL_MEMBASE:
2423                 return OP_CALL_REG;
2424         case OP_VOIDCALL_MEMBASE:
2425                 return OP_VOIDCALL_REG;
2426         case OP_FCALL_MEMBASE:
2427                 return OP_FCALL_REG;
2428         case OP_RCALL_MEMBASE:
2429                 return OP_RCALL_REG;
2430         case OP_VCALL_MEMBASE:
2431                 return OP_VCALL_REG;
2432         case OP_LCALL_MEMBASE:
2433                 return OP_LCALL_REG;
2434         default:
2435                 g_assert_not_reached ();
2436         }
2437
2438         return -1;
2439 }
2440
2441 /* Either METHOD or IMT_ARG needs to be set */
2442 static void
2443 emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoMethod *method, MonoInst *imt_arg)
2444 {
2445         int method_reg;
2446
2447         if (COMPILE_LLVM (cfg)) {
2448                 if (imt_arg) {
2449                         method_reg = alloc_preg (cfg);
2450                         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2451                 } else {
2452                         MonoInst *ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_METHODCONST, method);
2453                         method_reg = ins->dreg;
2454                 }
2455
2456 #ifdef ENABLE_LLVM
2457                 call->imt_arg_reg = method_reg;
2458 #endif
2459                 mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2460                 return;
2461         }
2462
2463         if (imt_arg) {
2464                 method_reg = alloc_preg (cfg);
2465                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2466         } else {
2467                 MonoInst *ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_METHODCONST, method);
2468                 method_reg = ins->dreg;
2469         }
2470
2471         mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2472 }
2473
2474 static MonoJumpInfo *
2475 mono_patch_info_new (MonoMemPool *mp, int ip, MonoJumpInfoType type, gconstpointer target)
2476 {
2477         MonoJumpInfo *ji = mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
2478
2479         ji->ip.i = ip;
2480         ji->type = type;
2481         ji->data.target = target;
2482
2483         return ji;
2484 }
2485
2486 static int
2487 mini_class_check_context_used (MonoCompile *cfg, MonoClass *klass)
2488 {
2489         if (cfg->gshared)
2490                 return mono_class_check_context_used (klass);
2491         else
2492                 return 0;
2493 }
2494
2495 static int
2496 mini_method_check_context_used (MonoCompile *cfg, MonoMethod *method)
2497 {
2498         if (cfg->gshared)
2499                 return mono_method_check_context_used (method);
2500         else
2501                 return 0;
2502 }
2503
2504 /*
2505  * check_method_sharing:
2506  *
2507  *   Check whenever the vtable or an mrgctx needs to be passed when calling CMETHOD.
2508  */
2509 static void
2510 check_method_sharing (MonoCompile *cfg, MonoMethod *cmethod, gboolean *out_pass_vtable, gboolean *out_pass_mrgctx)
2511 {
2512         gboolean pass_vtable = FALSE;
2513         gboolean pass_mrgctx = FALSE;
2514
2515         if (((cmethod->flags & METHOD_ATTRIBUTE_STATIC) || cmethod->klass->valuetype) &&
2516                 (cmethod->klass->generic_class || cmethod->klass->generic_container)) {
2517                 gboolean sharable = FALSE;
2518
2519                 if (mono_method_is_generic_sharable_full (cmethod, TRUE, TRUE, TRUE))
2520                         sharable = TRUE;
2521
2522                 /*
2523                  * Pass vtable iff target method might
2524                  * be shared, which means that sharing
2525                  * is enabled for its class and its
2526                  * context is sharable (and it's not a
2527                  * generic method).
2528                  */
2529                 if (sharable && !(mini_method_get_context (cmethod) && mini_method_get_context (cmethod)->method_inst))
2530                         pass_vtable = TRUE;
2531         }
2532
2533         if (mini_method_get_context (cmethod) &&
2534                 mini_method_get_context (cmethod)->method_inst) {
2535                 g_assert (!pass_vtable);
2536
2537                 if (mono_method_is_generic_sharable_full (cmethod, TRUE, TRUE, TRUE)) {
2538                         pass_mrgctx = TRUE;
2539                 } else {
2540                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (mono_method_signature (cmethod)))
2541                                 pass_mrgctx = TRUE;
2542                 }
2543         }
2544
2545         if (out_pass_vtable)
2546                 *out_pass_vtable = pass_vtable;
2547         if (out_pass_mrgctx)
2548                 *out_pass_mrgctx = pass_mrgctx;
2549 }
2550
2551 inline static MonoCallInst *
2552 mono_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig, 
2553                                          MonoInst **args, int calli, int virtual, int tail, int rgctx, int unbox_trampoline)
2554 {
2555         MonoType *sig_ret;
2556         MonoCallInst *call;
2557 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2558         int i;
2559 #endif
2560
2561         if (cfg->llvm_only)
2562                 tail = FALSE;
2563
2564         if (tail) {
2565                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
2566
2567                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
2568         } else
2569                 MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (cfg, sig->ret, calli, virtual));
2570
2571         call->args = args;
2572         call->signature = sig;
2573         call->rgctx_reg = rgctx;
2574         sig_ret = mini_get_underlying_type (sig->ret);
2575
2576         type_to_eval_stack_type ((cfg), sig_ret, &call->inst);
2577
2578         if (tail) {
2579                 if (mini_type_is_vtype (sig_ret)) {
2580                         call->vret_var = cfg->vret_addr;
2581                         //g_assert_not_reached ();
2582                 }
2583         } else if (mini_type_is_vtype (sig_ret)) {
2584                 MonoInst *temp = mono_compile_create_var (cfg, sig_ret, OP_LOCAL);
2585                 MonoInst *loada;
2586
2587                 temp->backend.is_pinvoke = sig->pinvoke;
2588
2589                 /*
2590                  * We use a new opcode OP_OUTARG_VTRETADDR instead of LDADDR for emitting the
2591                  * address of return value to increase optimization opportunities.
2592                  * Before vtype decomposition, the dreg of the call ins itself represents the
2593                  * fact the call modifies the return value. After decomposition, the call will
2594                  * be transformed into one of the OP_VOIDCALL opcodes, and the VTRETADDR opcode
2595                  * will be transformed into an LDADDR.
2596                  */
2597                 MONO_INST_NEW (cfg, loada, OP_OUTARG_VTRETADDR);
2598                 loada->dreg = alloc_preg (cfg);
2599                 loada->inst_p0 = temp;
2600                 /* We reference the call too since call->dreg could change during optimization */
2601                 loada->inst_p1 = call;
2602                 MONO_ADD_INS (cfg->cbb, loada);
2603
2604                 call->inst.dreg = temp->dreg;
2605
2606                 call->vret_var = loada;
2607         } else if (!MONO_TYPE_IS_VOID (sig_ret))
2608                 call->inst.dreg = alloc_dreg (cfg, call->inst.type);
2609
2610 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2611         if (COMPILE_SOFT_FLOAT (cfg)) {
2612                 /* 
2613                  * If the call has a float argument, we would need to do an r8->r4 conversion using 
2614                  * an icall, but that cannot be done during the call sequence since it would clobber
2615                  * the call registers + the stack. So we do it before emitting the call.
2616                  */
2617                 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2618                         MonoType *t;
2619                         MonoInst *in = call->args [i];
2620
2621                         if (i >= sig->hasthis)
2622                                 t = sig->params [i - sig->hasthis];
2623                         else
2624                                 t = &mono_defaults.int_class->byval_arg;
2625                         t = mono_type_get_underlying_type (t);
2626
2627                         if (!t->byref && t->type == MONO_TYPE_R4) {
2628                                 MonoInst *iargs [1];
2629                                 MonoInst *conv;
2630
2631                                 iargs [0] = in;
2632                                 conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
2633
2634                                 /* The result will be in an int vreg */
2635                                 call->args [i] = conv;
2636                         }
2637                 }
2638         }
2639 #endif
2640
2641         call->need_unbox_trampoline = unbox_trampoline;
2642
2643 #ifdef ENABLE_LLVM
2644         if (COMPILE_LLVM (cfg))
2645                 mono_llvm_emit_call (cfg, call);
2646         else
2647                 mono_arch_emit_call (cfg, call);
2648 #else
2649         mono_arch_emit_call (cfg, call);
2650 #endif
2651
2652         cfg->param_area = MAX (cfg->param_area, call->stack_usage);
2653         cfg->flags |= MONO_CFG_HAS_CALLS;
2654         
2655         return call;
2656 }
2657
2658 static void
2659 set_rgctx_arg (MonoCompile *cfg, MonoCallInst *call, int rgctx_reg, MonoInst *rgctx_arg)
2660 {
2661         mono_call_inst_add_outarg_reg (cfg, call, rgctx_reg, MONO_ARCH_RGCTX_REG, FALSE);
2662         cfg->uses_rgctx_reg = TRUE;
2663         call->rgctx_reg = TRUE;
2664 #ifdef ENABLE_LLVM
2665         call->rgctx_arg_reg = rgctx_reg;
2666 #endif
2667 }       
2668
2669 inline static MonoInst*
2670 mono_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr, MonoInst *imt_arg, MonoInst *rgctx_arg)
2671 {
2672         MonoCallInst *call;
2673         MonoInst *ins;
2674         int rgctx_reg = -1;
2675         gboolean check_sp = FALSE;
2676
2677         if (cfg->check_pinvoke_callconv && cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
2678                 WrapperInfo *info = mono_marshal_get_wrapper_info (cfg->method);
2679
2680                 if (info && info->subtype == WRAPPER_SUBTYPE_PINVOKE)
2681                         check_sp = TRUE;
2682         }
2683
2684         if (rgctx_arg) {
2685                 rgctx_reg = mono_alloc_preg (cfg);
2686                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2687         }
2688
2689         if (check_sp) {
2690                 if (!cfg->stack_inbalance_var)
2691                         cfg->stack_inbalance_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2692
2693                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2694                 ins->dreg = cfg->stack_inbalance_var->dreg;
2695                 MONO_ADD_INS (cfg->cbb, ins);
2696         }
2697
2698         call = mono_emit_call_args (cfg, sig, args, TRUE, FALSE, FALSE, rgctx_arg ? TRUE : FALSE, FALSE);
2699
2700         call->inst.sreg1 = addr->dreg;
2701
2702         if (imt_arg)
2703                 emit_imt_argument (cfg, call, NULL, imt_arg);
2704
2705         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2706
2707         if (check_sp) {
2708                 int sp_reg;
2709
2710                 sp_reg = mono_alloc_preg (cfg);
2711
2712                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2713                 ins->dreg = sp_reg;
2714                 MONO_ADD_INS (cfg->cbb, ins);
2715
2716                 /* Restore the stack so we don't crash when throwing the exception */
2717                 MONO_INST_NEW (cfg, ins, OP_SET_SP);
2718                 ins->sreg1 = cfg->stack_inbalance_var->dreg;
2719                 MONO_ADD_INS (cfg->cbb, ins);
2720
2721                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, cfg->stack_inbalance_var->dreg, sp_reg);
2722                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ExecutionEngineException");
2723         }
2724
2725         if (rgctx_arg)
2726                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2727
2728         return (MonoInst*)call;
2729 }
2730
2731 static MonoInst*
2732 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2733
2734 static MonoInst*
2735 emit_get_rgctx_method (MonoCompile *cfg, int context_used, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type);
2736 static MonoInst*
2737 emit_get_rgctx_klass (MonoCompile *cfg, int context_used, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2738
2739 static MonoInst*
2740 mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSignature *sig, gboolean tail,
2741                                                         MonoInst **args, MonoInst *this_ins, MonoInst *imt_arg, MonoInst *rgctx_arg)
2742 {
2743 #ifndef DISABLE_REMOTING
2744         gboolean might_be_remote = FALSE;
2745 #endif
2746         gboolean virtual = this_ins != NULL;
2747         gboolean enable_for_aot = TRUE;
2748         int context_used;
2749         MonoCallInst *call;
2750         MonoInst *call_target = NULL;
2751         int rgctx_reg = 0;
2752         gboolean need_unbox_trampoline;
2753
2754         if (!sig)
2755                 sig = mono_method_signature (method);
2756
2757         if (cfg->llvm_only && (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2758                 MonoInst *icall_args [16];
2759                 MonoInst *ins;
2760
2761                 // FIXME: Optimize this
2762
2763                 guint32 imt_slot = mono_method_get_imt_slot (method);
2764
2765                 icall_args [0] = this_ins;
2766                 EMIT_NEW_ICONST (cfg, icall_args [1], imt_slot);
2767                 if (imt_arg) {
2768                         icall_args [2] = imt_arg;
2769                 } else {
2770                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_METHODCONST, method);
2771                         icall_args [2] = ins;
2772                 }
2773                 EMIT_NEW_PCONST (cfg, icall_args [3], NULL);
2774
2775                 call_target = mono_emit_jit_icall (cfg, mono_resolve_iface_call, icall_args);
2776         }
2777
2778         if (rgctx_arg) {
2779                 rgctx_reg = mono_alloc_preg (cfg);
2780                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2781         }
2782
2783         if (method->string_ctor) {
2784                 /* Create the real signature */
2785                 /* FIXME: Cache these */
2786                 MonoMethodSignature *ctor_sig = mono_metadata_signature_dup_mempool (cfg->mempool, sig);
2787                 ctor_sig->ret = &mono_defaults.string_class->byval_arg;
2788
2789                 sig = ctor_sig;
2790         }
2791
2792         context_used = mini_method_check_context_used (cfg, method);
2793
2794 #ifndef DISABLE_REMOTING
2795         might_be_remote = this_ins && sig->hasthis &&
2796                 (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) &&
2797                 !(method->flags & METHOD_ATTRIBUTE_VIRTUAL) && (!MONO_CHECK_THIS (this_ins) || context_used);
2798
2799         if (might_be_remote && context_used) {
2800                 MonoInst *addr;
2801
2802                 g_assert (cfg->gshared);
2803
2804                 addr = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK);
2805
2806                 return mono_emit_calli (cfg, sig, args, addr, NULL, NULL);
2807         }
2808 #endif
2809
2810         if (cfg->llvm_only && !call_target && virtual && (method->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
2811                 // FIXME: Vcall optimizations below
2812                 MonoInst *icall_args [16];
2813                 MonoInst *ins;
2814
2815                 if (sig->generic_param_count) {
2816                         /*
2817                          * Generic virtual call, pass the concrete method as the imt argument.
2818                          */
2819                         imt_arg = emit_get_rgctx_method (cfg, context_used,
2820                                                                                          method, MONO_RGCTX_INFO_METHOD);
2821                 }
2822
2823                 // FIXME: Optimize this
2824
2825                 int slot = mono_method_get_vtable_index (method);
2826
2827                 icall_args [0] = this_ins;
2828                 EMIT_NEW_ICONST (cfg, icall_args [1], slot);
2829                 if (imt_arg) {
2830                         icall_args [2] = imt_arg;
2831                 } else {
2832                         EMIT_NEW_PCONST (cfg, ins, NULL);
2833                         icall_args [2] = ins;
2834                 }
2835                 call_target = mono_emit_jit_icall (cfg, mono_resolve_vcall, icall_args);
2836         }
2837
2838         need_unbox_trampoline = method->klass == mono_defaults.object_class || (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE);
2839
2840         call = mono_emit_call_args (cfg, sig, args, FALSE, virtual, tail, rgctx_arg ? TRUE : FALSE, need_unbox_trampoline);
2841
2842 #ifndef DISABLE_REMOTING
2843         if (might_be_remote)
2844                 call->method = mono_marshal_get_remoting_invoke_with_check (method);
2845         else
2846 #endif
2847                 call->method = method;
2848         call->inst.flags |= MONO_INST_HAS_METHOD;
2849         call->inst.inst_left = this_ins;
2850         call->tail_call = tail;
2851
2852         if (virtual) {
2853                 int vtable_reg, slot_reg, this_reg;
2854                 int offset;
2855
2856                 this_reg = this_ins->dreg;
2857
2858                 if (!cfg->llvm_only && (method->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (method->name, "Invoke")) {
2859                         MonoInst *dummy_use;
2860
2861                         MONO_EMIT_NULL_CHECK (cfg, this_reg);
2862
2863                         /* Make a call to delegate->invoke_impl */
2864                         call->inst.inst_basereg = this_reg;
2865                         call->inst.inst_offset = MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl);
2866                         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2867
2868                         /* We must emit a dummy use here because the delegate trampoline will
2869                         replace the 'this' argument with the delegate target making this activation
2870                         no longer a root for the delegate.
2871                         This is an issue for delegates that target collectible code such as dynamic
2872                         methods of GC'able assemblies.
2873
2874                         For a test case look into #667921.
2875
2876                         FIXME: a dummy use is not the best way to do it as the local register allocator
2877                         will put it on a caller save register and spil it around the call. 
2878                         Ideally, we would either put it on a callee save register or only do the store part.  
2879                          */
2880                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, args [0]);
2881
2882                         return (MonoInst*)call;
2883                 }
2884
2885                 if ((!cfg->compile_aot || enable_for_aot) && 
2886                         (!(method->flags & METHOD_ATTRIBUTE_VIRTUAL) || 
2887                          (MONO_METHOD_IS_FINAL (method) &&
2888                           method->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)) &&
2889                         !(mono_class_is_marshalbyref (method->klass) && context_used)) {
2890                         /* 
2891                          * the method is not virtual, we just need to ensure this is not null
2892                          * and then we can call the method directly.
2893                          */
2894 #ifndef DISABLE_REMOTING
2895                         if (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) {
2896                                 /* 
2897                                  * The check above ensures method is not gshared, this is needed since
2898                                  * gshared methods can't have wrappers.
2899                                  */
2900                                 method = call->method = mono_marshal_get_remoting_invoke_with_check (method);
2901                         }
2902 #endif
2903
2904                         if (!method->string_ctor)
2905                                 MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2906
2907                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2908                 } else if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && MONO_METHOD_IS_FINAL (method)) {
2909                         /*
2910                          * the method is virtual, but we can statically dispatch since either
2911                          * it's class or the method itself are sealed.
2912                          * But first we need to ensure it's not a null reference.
2913                          */
2914                         MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2915
2916                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2917                 } else if (call_target) {
2918                         vtable_reg = alloc_preg (cfg);
2919                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
2920
2921                         call->inst.opcode = callvirt_to_call_reg (call->inst.opcode);
2922                         call->inst.sreg1 = call_target->dreg;
2923                         call->inst.flags &= !MONO_INST_HAS_METHOD;
2924                 } else {
2925                         vtable_reg = alloc_preg (cfg);
2926                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
2927                         if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2928                                 guint32 imt_slot = mono_method_get_imt_slot (method);
2929                                 emit_imt_argument (cfg, call, call->method, imt_arg);
2930                                 slot_reg = vtable_reg;
2931                                 offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
2932                         } else {
2933                                 slot_reg = vtable_reg;
2934                                 offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) +
2935                                         ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
2936                                 if (imt_arg) {
2937                                         g_assert (mono_method_signature (method)->generic_param_count);
2938                                         emit_imt_argument (cfg, call, call->method, imt_arg);
2939                                 }
2940                         }
2941
2942                         call->inst.sreg1 = slot_reg;
2943                         call->inst.inst_offset = offset;
2944                         call->is_virtual = TRUE;
2945                 }
2946         }
2947
2948         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2949
2950         if (rgctx_arg)
2951                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2952
2953         return (MonoInst*)call;
2954 }
2955
2956 MonoInst*
2957 mono_emit_method_call (MonoCompile *cfg, MonoMethod *method, MonoInst **args, MonoInst *this_ins)
2958 {
2959         return mono_emit_method_call_full (cfg, method, mono_method_signature (method), FALSE, args, this_ins, NULL, NULL);
2960 }
2961
2962 MonoInst*
2963 mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig,
2964                                            MonoInst **args)
2965 {
2966         MonoCallInst *call;
2967
2968         g_assert (sig);
2969
2970         call = mono_emit_call_args (cfg, sig, args, FALSE, FALSE, FALSE, FALSE, FALSE);
2971         call->fptr = func;
2972
2973         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2974
2975         return (MonoInst*)call;
2976 }
2977
2978 MonoInst*
2979 mono_emit_jit_icall (MonoCompile *cfg, gconstpointer func, MonoInst **args)
2980 {
2981         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (func);
2982
2983         g_assert (info);
2984
2985         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
2986 }
2987
2988 /*
2989  * mono_emit_abs_call:
2990  *
2991  *   Emit a call to the runtime function described by PATCH_TYPE and DATA.
2992  */
2993 inline static MonoInst*
2994 mono_emit_abs_call (MonoCompile *cfg, MonoJumpInfoType patch_type, gconstpointer data, 
2995                                         MonoMethodSignature *sig, MonoInst **args)
2996 {
2997         MonoJumpInfo *ji = mono_patch_info_new (cfg->mempool, 0, patch_type, data);
2998         MonoInst *ins;
2999
3000         /* 
3001          * We pass ji as the call address, the PATCH_INFO_ABS resolving code will
3002          * handle it.
3003          */
3004         if (cfg->abs_patches == NULL)
3005                 cfg->abs_patches = g_hash_table_new (NULL, NULL);
3006         g_hash_table_insert (cfg->abs_patches, ji, ji);
3007         ins = mono_emit_native_call (cfg, ji, sig, args);
3008         ((MonoCallInst*)ins)->fptr_is_patch = TRUE;
3009         return ins;
3010 }
3011
3012 static gboolean
3013 direct_icalls_enabled (MonoCompile *cfg)
3014 {
3015         /* LLVM on amd64 can't handle calls to non-32 bit addresses */
3016 #ifdef TARGET_AMD64
3017         if (cfg->compile_llvm)
3018                 return FALSE;
3019 #endif
3020         if (cfg->gen_sdb_seq_points || cfg->disable_direct_icalls)
3021                 return FALSE;
3022         return TRUE;
3023 }
3024
3025 MonoInst*
3026 mono_emit_jit_icall_by_info (MonoCompile *cfg, MonoJitICallInfo *info, MonoInst **args)
3027 {
3028         /*
3029          * Call the jit icall without a wrapper if possible.
3030          * The wrapper is needed for the following reasons:
3031          * - to handle exceptions thrown using mono_raise_exceptions () from the
3032          *   icall function. The EH code needs the lmf frame pushed by the
3033          *   wrapper to be able to unwind back to managed code.
3034          * - to be able to do stack walks for asynchronously suspended
3035          *   threads when debugging.
3036          */
3037         if (info->no_raise && direct_icalls_enabled (cfg)) {
3038                 char *name;
3039                 int costs;
3040
3041                 if (!info->wrapper_method) {
3042                         name = g_strdup_printf ("__icall_wrapper_%s", info->name);
3043                         info->wrapper_method = mono_marshal_get_icall_wrapper (info->sig, name, info->func, TRUE);
3044                         g_free (name);
3045                         mono_memory_barrier ();
3046                 }
3047
3048                 /*
3049                  * Inline the wrapper method, which is basically a call to the C icall, and
3050                  * an exception check.
3051                  */
3052                 costs = inline_method (cfg, info->wrapper_method, NULL,
3053                                                            args, NULL, cfg->real_offset, TRUE);
3054                 g_assert (costs > 0);
3055                 g_assert (!MONO_TYPE_IS_VOID (info->sig->ret));
3056
3057                 return args [0];
3058         } else {
3059                 return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
3060         }
3061 }
3062  
3063 static MonoInst*
3064 mono_emit_widen_call_res (MonoCompile *cfg, MonoInst *ins, MonoMethodSignature *fsig)
3065 {
3066         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
3067                 if ((fsig->pinvoke || LLVM_ENABLED) && !fsig->ret->byref) {
3068                         int widen_op = -1;
3069
3070                         /* 
3071                          * Native code might return non register sized integers 
3072                          * without initializing the upper bits.
3073                          */
3074                         switch (mono_type_to_load_membase (cfg, fsig->ret)) {
3075                         case OP_LOADI1_MEMBASE:
3076                                 widen_op = OP_ICONV_TO_I1;
3077                                 break;
3078                         case OP_LOADU1_MEMBASE:
3079                                 widen_op = OP_ICONV_TO_U1;
3080                                 break;
3081                         case OP_LOADI2_MEMBASE:
3082                                 widen_op = OP_ICONV_TO_I2;
3083                                 break;
3084                         case OP_LOADU2_MEMBASE:
3085                                 widen_op = OP_ICONV_TO_U2;
3086                                 break;
3087                         default:
3088                                 break;
3089                         }
3090
3091                         if (widen_op != -1) {
3092                                 int dreg = alloc_preg (cfg);
3093                                 MonoInst *widen;
3094
3095                                 EMIT_NEW_UNALU (cfg, widen, widen_op, dreg, ins->dreg);
3096                                 widen->type = ins->type;
3097                                 ins = widen;
3098                         }
3099                 }
3100         }
3101
3102         return ins;
3103 }
3104
3105 static MonoMethod*
3106 get_memcpy_method (void)
3107 {
3108         static MonoMethod *memcpy_method = NULL;
3109         if (!memcpy_method) {
3110                 memcpy_method = mono_class_get_method_from_name (mono_defaults.string_class, "memcpy", 3);
3111                 if (!memcpy_method)
3112                         g_error ("Old corlib found. Install a new one");
3113         }
3114         return memcpy_method;
3115 }
3116
3117 static void
3118 create_write_barrier_bitmap (MonoCompile *cfg, MonoClass *klass, unsigned *wb_bitmap, int offset)
3119 {
3120         MonoClassField *field;
3121         gpointer iter = NULL;
3122
3123         while ((field = mono_class_get_fields (klass, &iter))) {
3124                 int foffset;
3125
3126                 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
3127                         continue;
3128                 foffset = klass->valuetype ? field->offset - sizeof (MonoObject): field->offset;
3129                 if (mini_type_is_reference (mono_field_get_type (field))) {
3130                         g_assert ((foffset % SIZEOF_VOID_P) == 0);
3131                         *wb_bitmap |= 1 << ((offset + foffset) / SIZEOF_VOID_P);
3132                 } else {
3133                         MonoClass *field_class = mono_class_from_mono_type (field->type);
3134                         if (field_class->has_references)
3135                                 create_write_barrier_bitmap (cfg, field_class, wb_bitmap, offset + foffset);
3136                 }
3137         }
3138 }
3139
3140 static void
3141 emit_write_barrier (MonoCompile *cfg, MonoInst *ptr, MonoInst *value)
3142 {
3143         int card_table_shift_bits;
3144         gpointer card_table_mask;
3145         guint8 *card_table;
3146         MonoInst *dummy_use;
3147         int nursery_shift_bits;
3148         size_t nursery_size;
3149
3150         if (!cfg->gen_write_barriers)
3151                 return;
3152
3153         card_table = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
3154
3155         mono_gc_get_nursery (&nursery_shift_bits, &nursery_size);
3156
3157         if (cfg->backend->have_card_table_wb && !cfg->compile_aot && card_table && nursery_shift_bits > 0 && !COMPILE_LLVM (cfg)) {
3158                 MonoInst *wbarrier;
3159
3160                 MONO_INST_NEW (cfg, wbarrier, OP_CARD_TABLE_WBARRIER);
3161                 wbarrier->sreg1 = ptr->dreg;
3162                 wbarrier->sreg2 = value->dreg;
3163                 MONO_ADD_INS (cfg->cbb, wbarrier);
3164         } else if (card_table && !cfg->compile_aot && !mono_gc_card_table_nursery_check ()) {
3165                 int offset_reg = alloc_preg (cfg);
3166                 int card_reg;
3167                 MonoInst *ins;
3168
3169                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, offset_reg, ptr->dreg, card_table_shift_bits);
3170                 if (card_table_mask)
3171                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, offset_reg, offset_reg, card_table_mask);
3172
3173                 /*We can't use PADD_IMM since the cardtable might end up in high addresses and amd64 doesn't support
3174                  * IMM's larger than 32bits.
3175                  */
3176                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR, NULL);
3177                 card_reg = ins->dreg;
3178
3179                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, offset_reg, offset_reg, card_reg);
3180                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, offset_reg, 0, 1);
3181         } else {
3182                 MonoMethod *write_barrier = mono_gc_get_write_barrier ();
3183                 mono_emit_method_call (cfg, write_barrier, &ptr, NULL);
3184         }
3185
3186         EMIT_NEW_DUMMY_USE (cfg, dummy_use, value);
3187 }
3188
3189 static gboolean
3190 mono_emit_wb_aware_memcpy (MonoCompile *cfg, MonoClass *klass, MonoInst *iargs[4], int size, int align)
3191 {
3192         int dest_ptr_reg, tmp_reg, destreg, srcreg, offset;
3193         unsigned need_wb = 0;
3194
3195         if (align == 0)
3196                 align = 4;
3197
3198         /*types with references can't have alignment smaller than sizeof(void*) */
3199         if (align < SIZEOF_VOID_P)
3200                 return FALSE;
3201
3202         /*This value cannot be bigger than 32 due to the way we calculate the required wb bitmap.*/
3203         if (size > 32 * SIZEOF_VOID_P)
3204                 return FALSE;
3205
3206         create_write_barrier_bitmap (cfg, klass, &need_wb, 0);
3207
3208         /* We don't unroll more than 5 stores to avoid code bloat. */
3209         if (size > 5 * SIZEOF_VOID_P) {
3210                 /*This is harmless and simplify mono_gc_wbarrier_value_copy_bitmap */
3211                 size += (SIZEOF_VOID_P - 1);
3212                 size &= ~(SIZEOF_VOID_P - 1);
3213
3214                 EMIT_NEW_ICONST (cfg, iargs [2], size);
3215                 EMIT_NEW_ICONST (cfg, iargs [3], need_wb);
3216                 mono_emit_jit_icall (cfg, mono_gc_wbarrier_value_copy_bitmap, iargs);
3217                 return TRUE;
3218         }
3219
3220         destreg = iargs [0]->dreg;
3221         srcreg = iargs [1]->dreg;
3222         offset = 0;
3223
3224         dest_ptr_reg = alloc_preg (cfg);
3225         tmp_reg = alloc_preg (cfg);
3226
3227         /*tmp = dreg*/
3228         EMIT_NEW_UNALU (cfg, iargs [0], OP_MOVE, dest_ptr_reg, destreg);
3229
3230         while (size >= SIZEOF_VOID_P) {
3231                 MonoInst *load_inst;
3232                 MONO_INST_NEW (cfg, load_inst, OP_LOAD_MEMBASE);
3233                 load_inst->dreg = tmp_reg;
3234                 load_inst->inst_basereg = srcreg;
3235                 load_inst->inst_offset = offset;
3236                 MONO_ADD_INS (cfg->cbb, load_inst);
3237
3238                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, dest_ptr_reg, 0, tmp_reg);
3239
3240                 if (need_wb & 0x1)
3241                         emit_write_barrier (cfg, iargs [0], load_inst);
3242
3243                 offset += SIZEOF_VOID_P;
3244                 size -= SIZEOF_VOID_P;
3245                 need_wb >>= 1;
3246
3247                 /*tmp += sizeof (void*)*/
3248                 if (size >= SIZEOF_VOID_P) {
3249                         NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, dest_ptr_reg, dest_ptr_reg, SIZEOF_VOID_P);
3250                         MONO_ADD_INS (cfg->cbb, iargs [0]);
3251                 }
3252         }
3253
3254         /* Those cannot be references since size < sizeof (void*) */
3255         while (size >= 4) {
3256                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tmp_reg, srcreg, offset);
3257                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, tmp_reg);
3258                 offset += 4;
3259                 size -= 4;
3260         }
3261
3262         while (size >= 2) {
3263                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmp_reg, srcreg, offset);
3264                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, tmp_reg);
3265                 offset += 2;
3266                 size -= 2;
3267         }
3268
3269         while (size >= 1) {
3270                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmp_reg, srcreg, offset);
3271                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, tmp_reg);
3272                 offset += 1;
3273                 size -= 1;
3274         }
3275
3276         return TRUE;
3277 }
3278
3279 /*
3280  * Emit code to copy a valuetype of type @klass whose address is stored in
3281  * @src->dreg to memory whose address is stored at @dest->dreg.
3282  */
3283 void
3284 mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native)
3285 {
3286         MonoInst *iargs [4];
3287         int n;
3288         guint32 align = 0;
3289         MonoMethod *memcpy_method;
3290         MonoInst *size_ins = NULL;
3291         MonoInst *memcpy_ins = NULL;
3292
3293         g_assert (klass);
3294         if (cfg->gshared)
3295                 klass = mono_class_from_mono_type (mini_get_underlying_type (&klass->byval_arg));
3296
3297         /*
3298          * This check breaks with spilled vars... need to handle it during verification anyway.
3299          * g_assert (klass && klass == src->klass && klass == dest->klass);
3300          */
3301
3302         if (mini_is_gsharedvt_klass (klass)) {
3303                 g_assert (!native);
3304                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3305                 memcpy_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_MEMCPY);
3306         }
3307
3308         if (native)
3309                 n = mono_class_native_size (klass, &align);
3310         else
3311                 n = mono_class_value_size (klass, &align);
3312
3313         /* if native is true there should be no references in the struct */
3314         if (cfg->gen_write_barriers && (klass->has_references || size_ins) && !native) {
3315                 /* Avoid barriers when storing to the stack */
3316                 if (!((dest->opcode == OP_ADD_IMM && dest->sreg1 == cfg->frame_reg) ||
3317                           (dest->opcode == OP_LDADDR))) {
3318                         int context_used;
3319
3320                         iargs [0] = dest;
3321                         iargs [1] = src;
3322
3323                         context_used = mini_class_check_context_used (cfg, klass);
3324
3325                         /* It's ok to intrinsify under gsharing since shared code types are layout stable. */
3326                         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && mono_emit_wb_aware_memcpy (cfg, klass, iargs, n, align)) {
3327                                 return;
3328                         } else if (context_used) {
3329                                 iargs [2] = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3330                         }  else {
3331                                 iargs [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, klass);
3332                                 if (!cfg->compile_aot)
3333                                         mono_class_compute_gc_descriptor (klass);
3334                         }
3335
3336                         if (size_ins)
3337                                 mono_emit_jit_icall (cfg, mono_gsharedvt_value_copy, iargs);
3338                         else
3339                                 mono_emit_jit_icall (cfg, mono_value_copy, iargs);
3340                         return;
3341                 }
3342         }
3343
3344         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 8) {
3345                 /* FIXME: Optimize the case when src/dest is OP_LDADDR */
3346                 mini_emit_memcpy (cfg, dest->dreg, 0, src->dreg, 0, n, align);
3347         } else {
3348                 iargs [0] = dest;
3349                 iargs [1] = src;
3350                 if (size_ins)
3351                         iargs [2] = size_ins;
3352                 else
3353                         EMIT_NEW_ICONST (cfg, iargs [2], n);
3354                 
3355                 memcpy_method = get_memcpy_method ();
3356                 if (memcpy_ins)
3357                         mono_emit_calli (cfg, mono_method_signature (memcpy_method), iargs, memcpy_ins, NULL, NULL);
3358                 else
3359                         mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
3360         }
3361 }
3362
3363 static MonoMethod*
3364 get_memset_method (void)
3365 {
3366         static MonoMethod *memset_method = NULL;
3367         if (!memset_method) {
3368                 memset_method = mono_class_get_method_from_name (mono_defaults.string_class, "memset", 3);
3369                 if (!memset_method)
3370                         g_error ("Old corlib found. Install a new one");
3371         }
3372         return memset_method;
3373 }
3374
3375 void
3376 mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass)
3377 {
3378         MonoInst *iargs [3];
3379         int n;
3380         guint32 align;
3381         MonoMethod *memset_method;
3382         MonoInst *size_ins = NULL;
3383         MonoInst *bzero_ins = NULL;
3384         static MonoMethod *bzero_method;
3385
3386         /* FIXME: Optimize this for the case when dest is an LDADDR */
3387         mono_class_init (klass);
3388         if (mini_is_gsharedvt_klass (klass)) {
3389                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3390                 bzero_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_BZERO);
3391                 if (!bzero_method)
3392                         bzero_method = mono_class_get_method_from_name (mono_defaults.string_class, "bzero_aligned_1", 2);
3393                 g_assert (bzero_method);
3394                 iargs [0] = dest;
3395                 iargs [1] = size_ins;
3396                 mono_emit_calli (cfg, mono_method_signature (bzero_method), iargs, bzero_ins, NULL, NULL);
3397                 return;
3398         }
3399
3400         n = mono_class_value_size (klass, &align);
3401
3402         if (n <= sizeof (gpointer) * 8) {
3403                 mini_emit_memset (cfg, dest->dreg, 0, n, 0, align);
3404         }
3405         else {
3406                 memset_method = get_memset_method ();
3407                 iargs [0] = dest;
3408                 EMIT_NEW_ICONST (cfg, iargs [1], 0);
3409                 EMIT_NEW_ICONST (cfg, iargs [2], n);
3410                 mono_emit_method_call (cfg, memset_method, iargs, NULL);
3411         }
3412 }
3413
3414 /*
3415  * emit_get_rgctx:
3416  *
3417  *   Emit IR to return either the this pointer for instance method,
3418  * or the mrgctx for static methods.
3419  */
3420 static MonoInst*
3421 emit_get_rgctx (MonoCompile *cfg, MonoMethod *method, int context_used)
3422 {
3423         MonoInst *this_ins = NULL;
3424
3425         g_assert (cfg->gshared);
3426
3427         if (!(method->flags & METHOD_ATTRIBUTE_STATIC) &&
3428                         !(context_used & MONO_GENERIC_CONTEXT_USED_METHOD) &&
3429                         !method->klass->valuetype)
3430                 EMIT_NEW_ARGLOAD (cfg, this_ins, 0);
3431
3432         if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD) {
3433                 MonoInst *mrgctx_loc, *mrgctx_var;
3434
3435                 g_assert (!this_ins);
3436                 g_assert (method->is_inflated && mono_method_get_context (method)->method_inst);
3437
3438                 mrgctx_loc = mono_get_vtable_var (cfg);
3439                 EMIT_NEW_TEMPLOAD (cfg, mrgctx_var, mrgctx_loc->inst_c0);
3440
3441                 return mrgctx_var;
3442         } else if (method->flags & METHOD_ATTRIBUTE_STATIC || method->klass->valuetype) {
3443                 MonoInst *vtable_loc, *vtable_var;
3444
3445                 g_assert (!this_ins);
3446
3447                 vtable_loc = mono_get_vtable_var (cfg);
3448                 EMIT_NEW_TEMPLOAD (cfg, vtable_var, vtable_loc->inst_c0);
3449
3450                 if (method->is_inflated && mono_method_get_context (method)->method_inst) {
3451                         MonoInst *mrgctx_var = vtable_var;
3452                         int vtable_reg;
3453
3454                         vtable_reg = alloc_preg (cfg);
3455                         EMIT_NEW_LOAD_MEMBASE (cfg, vtable_var, OP_LOAD_MEMBASE, vtable_reg, mrgctx_var->dreg, MONO_STRUCT_OFFSET (MonoMethodRuntimeGenericContext, class_vtable));
3456                         vtable_var->type = STACK_PTR;
3457                 }
3458
3459                 return vtable_var;
3460         } else {
3461                 MonoInst *ins;
3462                 int vtable_reg;
3463         
3464                 vtable_reg = alloc_preg (cfg);
3465                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, vtable_reg, this_ins->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3466                 return ins;
3467         }
3468 }
3469
3470 static MonoJumpInfoRgctxEntry *
3471 mono_patch_info_rgctx_entry_new (MonoMemPool *mp, MonoMethod *method, gboolean in_mrgctx, MonoJumpInfoType patch_type, gconstpointer patch_data, MonoRgctxInfoType info_type)
3472 {
3473         MonoJumpInfoRgctxEntry *res = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoRgctxEntry));
3474         res->method = method;
3475         res->in_mrgctx = in_mrgctx;
3476         res->data = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo));
3477         res->data->type = patch_type;
3478         res->data->data.target = patch_data;
3479         res->info_type = info_type;
3480
3481         return res;
3482 }
3483
3484 static inline MonoInst*
3485 emit_rgctx_fetch_inline (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
3486 {
3487         MonoInst *args [16];
3488         MonoInst *call;
3489
3490         // FIXME: No fastpath since the slot is not a compile time constant
3491         args [0] = rgctx;
3492         EMIT_NEW_AOTCONST (cfg, args [1], MONO_PATCH_INFO_RGCTX_SLOT_INDEX, entry);
3493         if (entry->in_mrgctx)
3494                 call = mono_emit_jit_icall (cfg, mono_fill_method_rgctx, args);
3495         else
3496                 call = mono_emit_jit_icall (cfg, mono_fill_class_rgctx, args);
3497         return call;
3498 #if 0
3499         /*
3500          * FIXME: This can be called during decompose, which is a problem since it creates
3501          * new bblocks.
3502          * Also, the fastpath doesn't work since the slot number is dynamically allocated.
3503          */
3504         int i, slot, depth, index, rgctx_reg, val_reg, res_reg;
3505         gboolean mrgctx;
3506         MonoBasicBlock *is_null_bb, *end_bb;
3507         MonoInst *res, *ins, *call;
3508         MonoInst *args[16];
3509
3510         slot = mini_get_rgctx_entry_slot (entry);
3511
3512         mrgctx = MONO_RGCTX_SLOT_IS_MRGCTX (slot);
3513         index = MONO_RGCTX_SLOT_INDEX (slot);
3514         if (mrgctx)
3515                 index += MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
3516         for (depth = 0; ; ++depth) {
3517                 int size = mono_class_rgctx_get_array_size (depth, mrgctx);
3518
3519                 if (index < size - 1)
3520                         break;
3521                 index -= size - 1;
3522         }
3523
3524         NEW_BBLOCK (cfg, end_bb);
3525         NEW_BBLOCK (cfg, is_null_bb);
3526
3527         if (mrgctx) {
3528                 rgctx_reg = rgctx->dreg;
3529         } else {
3530                 rgctx_reg = alloc_preg (cfg);
3531
3532                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, rgctx_reg, rgctx->dreg, MONO_STRUCT_OFFSET (MonoVTable, runtime_generic_context));
3533                 // FIXME: Avoid this check by allocating the table when the vtable is created etc.
3534                 NEW_BBLOCK (cfg, is_null_bb);
3535
3536                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rgctx_reg, 0);
3537                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3538         }
3539
3540         for (i = 0; i < depth; ++i) {
3541                 int array_reg = alloc_preg (cfg);
3542
3543                 /* load ptr to next array */
3544                 if (mrgctx && i == 0)
3545                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, rgctx_reg, MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT);
3546                 else
3547                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, rgctx_reg, 0);
3548                 rgctx_reg = array_reg;
3549                 /* is the ptr null? */
3550                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rgctx_reg, 0);
3551                 /* if yes, jump to actual trampoline */
3552                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3553         }
3554
3555         /* fetch slot */
3556         val_reg = alloc_preg (cfg);
3557         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, val_reg, rgctx_reg, (index + 1) * sizeof (gpointer));
3558         /* is the slot null? */
3559         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, val_reg, 0);
3560         /* if yes, jump to actual trampoline */
3561         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3562
3563         /* Fastpath */
3564         res_reg = alloc_preg (cfg);
3565         MONO_INST_NEW (cfg, ins, OP_MOVE);
3566         ins->dreg = res_reg;
3567         ins->sreg1 = val_reg;
3568         MONO_ADD_INS (cfg->cbb, ins);
3569         res = ins;
3570         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3571
3572         /* Slowpath */
3573         MONO_START_BB (cfg, is_null_bb);
3574         args [0] = rgctx;
3575         EMIT_NEW_ICONST (cfg, args [1], index);
3576         if (mrgctx)
3577                 call = mono_emit_jit_icall (cfg, mono_fill_method_rgctx, args);
3578         else
3579                 call = mono_emit_jit_icall (cfg, mono_fill_class_rgctx, args);
3580         MONO_INST_NEW (cfg, ins, OP_MOVE);
3581         ins->dreg = res_reg;
3582         ins->sreg1 = call->dreg;
3583         MONO_ADD_INS (cfg->cbb, ins);
3584         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3585
3586         MONO_START_BB (cfg, end_bb);
3587
3588         return res;
3589 #endif
3590 }
3591
3592 /*
3593  * emit_rgctx_fetch:
3594  *
3595  *   Emit IR to load the value of the rgctx entry ENTRY from the rgctx
3596  * given by RGCTX.
3597  */
3598 static inline MonoInst*
3599 emit_rgctx_fetch (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
3600 {
3601         if (cfg->llvm_only)
3602                 return emit_rgctx_fetch_inline (cfg, rgctx, entry);
3603         else
3604                 return mono_emit_abs_call (cfg, MONO_PATCH_INFO_RGCTX_FETCH, entry, helper_sig_rgctx_lazy_fetch_trampoline, &rgctx);
3605 }
3606
3607 static MonoInst*
3608 emit_get_rgctx_klass (MonoCompile *cfg, int context_used,
3609                                           MonoClass *klass, MonoRgctxInfoType rgctx_type)
3610 {
3611         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);
3612         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3613
3614         return emit_rgctx_fetch (cfg, rgctx, entry);
3615 }
3616
3617 static MonoInst*
3618 emit_get_rgctx_sig (MonoCompile *cfg, int context_used,
3619                                         MonoMethodSignature *sig, MonoRgctxInfoType rgctx_type)
3620 {
3621         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);
3622         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3623
3624         return emit_rgctx_fetch (cfg, rgctx, entry);
3625 }
3626
3627 static MonoInst*
3628 emit_get_rgctx_gsharedvt_call (MonoCompile *cfg, int context_used,
3629                                                            MonoMethodSignature *sig, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3630 {
3631         MonoJumpInfoGSharedVtCall *call_info;
3632         MonoJumpInfoRgctxEntry *entry;
3633         MonoInst *rgctx;
3634
3635         call_info = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoGSharedVtCall));
3636         call_info->sig = sig;
3637         call_info->method = cmethod;
3638
3639         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);
3640         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3641
3642         return emit_rgctx_fetch (cfg, rgctx, entry);
3643 }
3644
3645 /*
3646  * emit_get_rgctx_virt_method:
3647  *
3648  *   Return data for method VIRT_METHOD for a receiver of type KLASS.
3649  */
3650 static MonoInst*
3651 emit_get_rgctx_virt_method (MonoCompile *cfg, int context_used,
3652                                                         MonoClass *klass, MonoMethod *virt_method, MonoRgctxInfoType rgctx_type)
3653 {
3654         MonoJumpInfoVirtMethod *info;
3655         MonoJumpInfoRgctxEntry *entry;
3656         MonoInst *rgctx;
3657
3658         info = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoVirtMethod));
3659         info->klass = klass;
3660         info->method = virt_method;
3661
3662         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);
3663         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3664
3665         return emit_rgctx_fetch (cfg, rgctx, entry);
3666 }
3667
3668 static MonoInst*
3669 emit_get_rgctx_gsharedvt_method (MonoCompile *cfg, int context_used,
3670                                                                  MonoMethod *cmethod, MonoGSharedVtMethodInfo *info)
3671 {
3672         MonoJumpInfoRgctxEntry *entry;
3673         MonoInst *rgctx;
3674
3675         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);
3676         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3677
3678         return emit_rgctx_fetch (cfg, rgctx, entry);
3679 }
3680
3681 /*
3682  * emit_get_rgctx_method:
3683  *
3684  *   Emit IR to load the property RGCTX_TYPE of CMETHOD. If context_used is 0, emit
3685  * normal constants, else emit a load from the rgctx.
3686  */
3687 static MonoInst*
3688 emit_get_rgctx_method (MonoCompile *cfg, int context_used,
3689                                            MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3690 {
3691         if (!context_used) {
3692                 MonoInst *ins;
3693
3694                 switch (rgctx_type) {
3695                 case MONO_RGCTX_INFO_METHOD:
3696                         EMIT_NEW_METHODCONST (cfg, ins, cmethod);
3697                         return ins;
3698                 case MONO_RGCTX_INFO_METHOD_RGCTX:
3699                         EMIT_NEW_METHOD_RGCTX_CONST (cfg, ins, cmethod);
3700                         return ins;
3701                 default:
3702                         g_assert_not_reached ();
3703                 }
3704         } else {
3705                 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);
3706                 MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3707
3708                 return emit_rgctx_fetch (cfg, rgctx, entry);
3709         }
3710 }
3711
3712 static MonoInst*
3713 emit_get_rgctx_field (MonoCompile *cfg, int context_used,
3714                                           MonoClassField *field, MonoRgctxInfoType rgctx_type)
3715 {
3716         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);
3717         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3718
3719         return emit_rgctx_fetch (cfg, rgctx, entry);
3720 }
3721
3722 static int
3723 get_gsharedvt_info_slot (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3724 {
3725         MonoGSharedVtMethodInfo *info = cfg->gsharedvt_info;
3726         MonoRuntimeGenericContextInfoTemplate *template;
3727         int i, idx;
3728
3729         g_assert (info);
3730
3731         for (i = 0; i < info->num_entries; ++i) {
3732                 MonoRuntimeGenericContextInfoTemplate *otemplate = &info->entries [i];
3733
3734                 if (otemplate->info_type == rgctx_type && otemplate->data == data && rgctx_type != MONO_RGCTX_INFO_LOCAL_OFFSET)
3735                         return i;
3736         }
3737
3738         if (info->num_entries == info->count_entries) {
3739                 MonoRuntimeGenericContextInfoTemplate *new_entries;
3740                 int new_count_entries = info->count_entries ? info->count_entries * 2 : 16;
3741
3742                 new_entries = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * new_count_entries);
3743
3744                 memcpy (new_entries, info->entries, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
3745                 info->entries = new_entries;
3746                 info->count_entries = new_count_entries;
3747         }
3748
3749         idx = info->num_entries;
3750         template = &info->entries [idx];
3751         template->info_type = rgctx_type;
3752         template->data = data;
3753
3754         info->num_entries ++;
3755
3756         return idx;
3757 }
3758
3759 /*
3760  * emit_get_gsharedvt_info:
3761  *
3762  *   This is similar to emit_get_rgctx_.., but loads the data from the gsharedvt info var instead of calling an rgctx fetch trampoline.
3763  */
3764 static MonoInst*
3765 emit_get_gsharedvt_info (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3766 {
3767         MonoInst *ins;
3768         int idx, dreg;
3769
3770         idx = get_gsharedvt_info_slot (cfg, data, rgctx_type);
3771         /* Load info->entries [idx] */
3772         dreg = alloc_preg (cfg);
3773         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, cfg->gsharedvt_info_var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
3774
3775         return ins;
3776 }
3777
3778 static MonoInst*
3779 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type)
3780 {
3781         return emit_get_gsharedvt_info (cfg, &klass->byval_arg, rgctx_type);
3782 }
3783
3784 /*
3785  * On return the caller must check @klass for load errors.
3786  */
3787 static void
3788 emit_class_init (MonoCompile *cfg, MonoClass *klass)
3789 {
3790         MonoInst *vtable_arg;
3791         int context_used;
3792
3793         context_used = mini_class_check_context_used (cfg, klass);
3794
3795         if (context_used) {
3796                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
3797                                                                                    klass, MONO_RGCTX_INFO_VTABLE);
3798         } else {
3799                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
3800
3801                 if (!vtable)
3802                         return;
3803                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
3804         }
3805
3806         if (!COMPILE_LLVM (cfg) && cfg->backend->have_op_generic_class_init) {
3807                 MonoInst *ins;
3808
3809                 /*
3810                  * Using an opcode instead of emitting IR here allows the hiding of the call inside the opcode,
3811                  * so this doesn't have to clobber any regs and it doesn't break basic blocks.
3812                  */
3813                 MONO_INST_NEW (cfg, ins, OP_GENERIC_CLASS_INIT);
3814                 ins->sreg1 = vtable_arg->dreg;
3815                 MONO_ADD_INS (cfg->cbb, ins);
3816         } else {
3817                 static int byte_offset = -1;
3818                 static guint8 bitmask;
3819                 int bits_reg, inited_reg;
3820                 MonoBasicBlock *inited_bb;
3821                 MonoInst *args [16];
3822
3823                 if (byte_offset < 0)
3824                         mono_marshal_find_bitfield_offset (MonoVTable, initialized, &byte_offset, &bitmask);
3825
3826                 bits_reg = alloc_ireg (cfg);
3827                 inited_reg = alloc_ireg (cfg);
3828
3829                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, bits_reg, vtable_arg->dreg, byte_offset);
3830                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, inited_reg, bits_reg, bitmask);
3831
3832                 NEW_BBLOCK (cfg, inited_bb);
3833
3834                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, inited_reg, 0);
3835                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, inited_bb);
3836
3837                 args [0] = vtable_arg;
3838                 mono_emit_jit_icall (cfg, mono_generic_class_init, args);
3839
3840                 MONO_START_BB (cfg, inited_bb);
3841         }
3842 }
3843
3844 static void
3845 emit_seq_point (MonoCompile *cfg, MonoMethod *method, guint8* ip, gboolean intr_loc, gboolean nonempty_stack)
3846 {
3847         MonoInst *ins;
3848
3849         if (cfg->gen_seq_points && cfg->method == method) {
3850                 NEW_SEQ_POINT (cfg, ins, ip - cfg->header->code, intr_loc);
3851                 if (nonempty_stack)
3852                         ins->flags |= MONO_INST_NONEMPTY_STACK;
3853                 MONO_ADD_INS (cfg->cbb, ins);
3854         }
3855 }
3856
3857 static void
3858 save_cast_details (MonoCompile *cfg, MonoClass *klass, int obj_reg, gboolean null_check)
3859 {
3860         if (mini_get_debug_options ()->better_cast_details) {
3861                 int vtable_reg = alloc_preg (cfg);
3862                 int klass_reg = alloc_preg (cfg);
3863                 MonoBasicBlock *is_null_bb = NULL;
3864                 MonoInst *tls_get;
3865                 int to_klass_reg, context_used;
3866
3867                 if (null_check) {
3868                         NEW_BBLOCK (cfg, is_null_bb);
3869
3870                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
3871                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3872                 }
3873
3874                 tls_get = mono_get_jit_tls_intrinsic (cfg);
3875                 if (!tls_get) {
3876                         fprintf (stderr, "error: --debug=casts not supported on this platform.\n.");
3877                         exit (1);
3878                 }
3879
3880                 MONO_ADD_INS (cfg->cbb, tls_get);
3881                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3882                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3883
3884                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), klass_reg);
3885
3886                 context_used = mini_class_check_context_used (cfg, klass);
3887                 if (context_used) {
3888                         MonoInst *class_ins;
3889
3890                         class_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3891                         to_klass_reg = class_ins->dreg;
3892                 } else {
3893                         to_klass_reg = alloc_preg (cfg);
3894                         MONO_EMIT_NEW_CLASSCONST (cfg, to_klass_reg, klass);
3895                 }
3896                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_to), to_klass_reg);
3897
3898                 if (null_check)
3899                         MONO_START_BB (cfg, is_null_bb);
3900         }
3901 }
3902
3903 static void
3904 reset_cast_details (MonoCompile *cfg)
3905 {
3906         /* Reset the variables holding the cast details */
3907         if (mini_get_debug_options ()->better_cast_details) {
3908                 MonoInst *tls_get = mono_get_jit_tls_intrinsic (cfg);
3909
3910                 MONO_ADD_INS (cfg->cbb, tls_get);
3911                 /* It is enough to reset the from field */
3912                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), 0);
3913         }
3914 }
3915
3916 /*
3917  * On return the caller must check @array_class for load errors
3918  */
3919 static void
3920 mini_emit_check_array_type (MonoCompile *cfg, MonoInst *obj, MonoClass *array_class)
3921 {
3922         int vtable_reg = alloc_preg (cfg);
3923         int context_used;
3924
3925         context_used = mini_class_check_context_used (cfg, array_class);
3926
3927         save_cast_details (cfg, array_class, obj->dreg, FALSE);
3928
3929         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3930
3931         if (cfg->opt & MONO_OPT_SHARED) {
3932                 int class_reg = alloc_preg (cfg);
3933                 MonoInst *ins;
3934
3935                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, class_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3936                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, array_class);
3937                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, class_reg, ins->dreg);
3938         } else if (context_used) {
3939                 MonoInst *vtable_ins;
3940
3941                 vtable_ins = emit_get_rgctx_klass (cfg, context_used, array_class, MONO_RGCTX_INFO_VTABLE);
3942                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vtable_ins->dreg);
3943         } else {
3944                 if (cfg->compile_aot) {
3945                         int vt_reg;
3946                         MonoVTable *vtable;
3947
3948                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3949                                 return;
3950                         vt_reg = alloc_preg (cfg);
3951                         MONO_EMIT_NEW_VTABLECONST (cfg, vt_reg, vtable);
3952                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vt_reg);
3953                 } else {
3954                         MonoVTable *vtable;
3955                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3956                                 return;
3957                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vtable);
3958                 }
3959         }
3960         
3961         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ArrayTypeMismatchException");
3962
3963         reset_cast_details (cfg);
3964 }
3965
3966 /**
3967  * Handles unbox of a Nullable<T>. If context_used is non zero, then shared 
3968  * generic code is generated.
3969  */
3970 static MonoInst*
3971 handle_unbox_nullable (MonoCompile* cfg, MonoInst* val, MonoClass* klass, int context_used)
3972 {
3973         MonoMethod* method = mono_class_get_method_from_name (klass, "Unbox", 1);
3974
3975         if (context_used) {
3976                 MonoInst *rgctx, *addr;
3977
3978                 /* FIXME: What if the class is shared?  We might not
3979                    have to get the address of the method from the
3980                    RGCTX. */
3981                 addr = emit_get_rgctx_method (cfg, context_used, method,
3982                                                                           MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
3983
3984                 rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3985
3986                 return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
3987         } else {
3988                 gboolean pass_vtable, pass_mrgctx;
3989                 MonoInst *rgctx_arg = NULL;
3990
3991                 check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
3992                 g_assert (!pass_mrgctx);
3993
3994                 if (pass_vtable) {
3995                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
3996
3997                         g_assert (vtable);
3998                         EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
3999                 }
4000
4001                 return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
4002         }
4003 }
4004
4005 static MonoInst*
4006 handle_unbox (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, int context_used)
4007 {
4008         MonoInst *add;
4009         int obj_reg;
4010         int vtable_reg = alloc_dreg (cfg ,STACK_PTR);
4011         int klass_reg = alloc_dreg (cfg ,STACK_PTR);
4012         int eclass_reg = alloc_dreg (cfg ,STACK_PTR);
4013         int rank_reg = alloc_dreg (cfg ,STACK_I4);
4014
4015         obj_reg = sp [0]->dreg;
4016         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4017         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
4018
4019         /* FIXME: generics */
4020         g_assert (klass->rank == 0);
4021                         
4022         // Check rank == 0
4023         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, 0);
4024         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4025
4026         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4027         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, element_class));
4028
4029         if (context_used) {
4030                 MonoInst *element_class;
4031
4032                 /* This assertion is from the unboxcast insn */
4033                 g_assert (klass->rank == 0);
4034
4035                 element_class = emit_get_rgctx_klass (cfg, context_used,
4036                                 klass, MONO_RGCTX_INFO_ELEMENT_KLASS);
4037
4038                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, eclass_reg, element_class->dreg);
4039                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4040         } else {
4041                 save_cast_details (cfg, klass->element_class, obj_reg, FALSE);
4042                 mini_emit_class_check (cfg, eclass_reg, klass->element_class);
4043                 reset_cast_details (cfg);
4044         }
4045
4046         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), obj_reg, sizeof (MonoObject));
4047         MONO_ADD_INS (cfg->cbb, add);
4048         add->type = STACK_MP;
4049         add->klass = klass;
4050
4051         return add;
4052 }
4053
4054 static MonoInst*
4055 handle_unbox_gsharedvt (MonoCompile *cfg, MonoClass *klass, MonoInst *obj)
4056 {
4057         MonoInst *addr, *klass_inst, *is_ref, *args[16];
4058         MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
4059         MonoInst *ins;
4060         int dreg, addr_reg;
4061
4062         klass_inst = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_KLASS);
4063
4064         /* obj */
4065         args [0] = obj;
4066
4067         /* klass */
4068         args [1] = klass_inst;
4069
4070         /* CASTCLASS */
4071         obj = mono_emit_jit_icall (cfg, mono_object_castclass_unbox, args);
4072
4073         NEW_BBLOCK (cfg, is_ref_bb);
4074         NEW_BBLOCK (cfg, is_nullable_bb);
4075         NEW_BBLOCK (cfg, end_bb);
4076         is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
4077         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
4078         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
4079
4080         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
4081         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
4082
4083         /* This will contain either the address of the unboxed vtype, or an address of the temporary where the ref is stored */
4084         addr_reg = alloc_dreg (cfg, STACK_MP);
4085
4086         /* Non-ref case */
4087         /* UNBOX */
4088         NEW_BIALU_IMM (cfg, addr, OP_ADD_IMM, addr_reg, obj->dreg, sizeof (MonoObject));
4089         MONO_ADD_INS (cfg->cbb, addr);
4090
4091         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4092
4093         /* Ref case */
4094         MONO_START_BB (cfg, is_ref_bb);
4095
4096         /* Save the ref to a temporary */
4097         dreg = alloc_ireg (cfg);
4098         EMIT_NEW_VARLOADA_VREG (cfg, addr, dreg, &klass->byval_arg);
4099         addr->dreg = addr_reg;
4100         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, obj->dreg);
4101         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4102
4103         /* Nullable case */
4104         MONO_START_BB (cfg, is_nullable_bb);
4105
4106         {
4107                 MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX);
4108                 MonoInst *unbox_call;
4109                 MonoMethodSignature *unbox_sig;
4110
4111                 unbox_sig = mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
4112                 unbox_sig->ret = &klass->byval_arg;
4113                 unbox_sig->param_count = 1;
4114                 unbox_sig->params [0] = &mono_defaults.object_class->byval_arg;
4115                 unbox_call = mono_emit_calli (cfg, unbox_sig, &obj, addr, NULL, NULL);
4116
4117                 EMIT_NEW_VARLOADA_VREG (cfg, addr, unbox_call->dreg, &klass->byval_arg);
4118                 addr->dreg = addr_reg;
4119         }
4120
4121         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4122
4123         /* End */
4124         MONO_START_BB (cfg, end_bb);
4125
4126         /* LDOBJ */
4127         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr_reg, 0);
4128
4129         return ins;
4130 }
4131
4132 /*
4133  * Returns NULL and set the cfg exception on error.
4134  */
4135 static MonoInst*
4136 handle_alloc (MonoCompile *cfg, MonoClass *klass, gboolean for_box, int context_used)
4137 {
4138         MonoInst *iargs [2];
4139         void *alloc_ftn;
4140
4141         if (context_used) {
4142                 MonoInst *data;
4143                 int rgctx_info;
4144                 MonoInst *iargs [2];
4145                 gboolean known_instance_size = !mini_is_gsharedvt_klass (klass);
4146
4147                 MonoMethod *managed_alloc = mono_gc_get_managed_allocator (klass, for_box, known_instance_size);
4148
4149                 if (cfg->opt & MONO_OPT_SHARED)
4150                         rgctx_info = MONO_RGCTX_INFO_KLASS;
4151                 else
4152                         rgctx_info = MONO_RGCTX_INFO_VTABLE;
4153                 data = emit_get_rgctx_klass (cfg, context_used, klass, rgctx_info);
4154
4155                 if (cfg->opt & MONO_OPT_SHARED) {
4156                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
4157                         iargs [1] = data;
4158                         alloc_ftn = mono_object_new;
4159                 } else {
4160                         iargs [0] = data;
4161                         alloc_ftn = mono_object_new_specific;
4162                 }
4163
4164                 if (managed_alloc && !(cfg->opt & MONO_OPT_SHARED)) {
4165                         if (known_instance_size) {
4166                                 int size = mono_class_instance_size (klass);
4167                                 if (size < sizeof (MonoObject))
4168                                         g_error ("Invalid size %d for class %s", size, mono_type_get_full_name (klass));
4169
4170                                 EMIT_NEW_ICONST (cfg, iargs [1], mono_gc_get_aligned_size_for_allocator (size));
4171                         }
4172                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
4173                 }
4174
4175                 return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
4176         }
4177
4178         if (cfg->opt & MONO_OPT_SHARED) {
4179                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
4180                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
4181
4182                 alloc_ftn = mono_object_new;
4183         } else if (cfg->compile_aot && cfg->cbb->out_of_line && klass->type_token && klass->image == mono_defaults.corlib && !klass->generic_class) {
4184                 /* This happens often in argument checking code, eg. throw new FooException... */
4185                 /* Avoid relocations and save some space by calling a helper function specialized to mscorlib */
4186                 EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (klass->type_token));
4187                 return mono_emit_jit_icall (cfg, mono_helper_newobj_mscorlib, iargs);
4188         } else {
4189                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
4190                 MonoMethod *managed_alloc = NULL;
4191                 gboolean pass_lw;
4192
4193                 if (!vtable) {
4194                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4195                         cfg->exception_ptr = klass;
4196                         return NULL;
4197                 }
4198
4199                 managed_alloc = mono_gc_get_managed_allocator (klass, for_box, TRUE);
4200
4201                 if (managed_alloc) {
4202                         int size = mono_class_instance_size (klass);
4203                         if (size < sizeof (MonoObject))
4204                                 g_error ("Invalid size %d for class %s", size, mono_type_get_full_name (klass));
4205
4206                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
4207                         EMIT_NEW_ICONST (cfg, iargs [1], mono_gc_get_aligned_size_for_allocator (size));
4208                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
4209                 }
4210                 alloc_ftn = mono_class_get_allocation_ftn (vtable, for_box, &pass_lw);
4211                 if (pass_lw) {
4212                         guint32 lw = vtable->klass->instance_size;
4213                         lw = ((lw + (sizeof (gpointer) - 1)) & ~(sizeof (gpointer) - 1)) / sizeof (gpointer);
4214                         EMIT_NEW_ICONST (cfg, iargs [0], lw);
4215                         EMIT_NEW_VTABLECONST (cfg, iargs [1], vtable);
4216                 }
4217                 else {
4218                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
4219                 }
4220         }
4221
4222         return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
4223 }
4224         
4225 /*
4226  * Returns NULL and set the cfg exception on error.
4227  */     
4228 static MonoInst*
4229 handle_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_used)
4230 {
4231         MonoInst *alloc, *ins;
4232
4233         if (mono_class_is_nullable (klass)) {
4234                 MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
4235
4236                 if (context_used) {
4237                         /* FIXME: What if the class is shared?  We might not
4238                            have to get the method address from the RGCTX. */
4239                         MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
4240                                                                                                         MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
4241                         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
4242
4243                         return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
4244                 } else {
4245                         gboolean pass_vtable, pass_mrgctx;
4246                         MonoInst *rgctx_arg = NULL;
4247
4248                         check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
4249                         g_assert (!pass_mrgctx);
4250
4251                         if (pass_vtable) {
4252                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
4253
4254                                 g_assert (vtable);
4255                                 EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
4256                         }
4257
4258                         return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
4259                 }
4260         }
4261
4262         if (mini_is_gsharedvt_klass (klass)) {
4263                 MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
4264                 MonoInst *res, *is_ref, *src_var, *addr;
4265                 int dreg;
4266
4267                 dreg = alloc_ireg (cfg);
4268
4269                 NEW_BBLOCK (cfg, is_ref_bb);
4270                 NEW_BBLOCK (cfg, is_nullable_bb);
4271                 NEW_BBLOCK (cfg, end_bb);
4272                 is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
4273                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
4274                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
4275
4276                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
4277                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
4278
4279                 /* Non-ref case */
4280                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4281                 if (!alloc)
4282                         return NULL;
4283                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4284                 ins->opcode = OP_STOREV_MEMBASE;
4285
4286                 EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, alloc->dreg);
4287                 res->type = STACK_OBJ;
4288                 res->klass = klass;
4289                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4290                 
4291                 /* Ref case */
4292                 MONO_START_BB (cfg, is_ref_bb);
4293
4294                 /* val is a vtype, so has to load the value manually */
4295                 src_var = get_vreg_to_inst (cfg, val->dreg);
4296                 if (!src_var)
4297                         src_var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, val->dreg);
4298                 EMIT_NEW_VARLOADA (cfg, addr, src_var, src_var->inst_vtype);
4299                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, addr->dreg, 0);
4300                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4301
4302                 /* Nullable case */
4303                 MONO_START_BB (cfg, is_nullable_bb);
4304
4305                 {
4306                         MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass,
4307                                                                                                         MONO_RGCTX_INFO_NULLABLE_CLASS_BOX);
4308                         MonoInst *box_call;
4309                         MonoMethodSignature *box_sig;
4310
4311                         /*
4312                          * klass is Nullable<T>, need to call Nullable<T>.Box () using a gsharedvt signature, but we cannot
4313                          * construct that method at JIT time, so have to do things by hand.
4314                          */
4315                         box_sig = mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
4316                         box_sig->ret = &mono_defaults.object_class->byval_arg;
4317                         box_sig->param_count = 1;
4318                         box_sig->params [0] = &klass->byval_arg;
4319                         box_call = mono_emit_calli (cfg, box_sig, &val, addr, NULL, NULL);
4320                         EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, box_call->dreg);
4321                         res->type = STACK_OBJ;
4322                         res->klass = klass;
4323                 }
4324
4325                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4326
4327                 MONO_START_BB (cfg, end_bb);
4328
4329                 return res;
4330         } else {
4331                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4332                 if (!alloc)
4333                         return NULL;
4334
4335                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4336                 return alloc;
4337         }
4338 }
4339
4340 static gboolean
4341 mini_class_has_reference_variant_generic_argument (MonoCompile *cfg, MonoClass *klass, int context_used)
4342 {
4343         int i;
4344         MonoGenericContainer *container;
4345         MonoGenericInst *ginst;
4346
4347         if (klass->generic_class) {
4348                 container = klass->generic_class->container_class->generic_container;
4349                 ginst = klass->generic_class->context.class_inst;
4350         } else if (klass->generic_container && context_used) {
4351                 container = klass->generic_container;
4352                 ginst = container->context.class_inst;
4353         } else {
4354                 return FALSE;
4355         }
4356
4357         for (i = 0; i < container->type_argc; ++i) {
4358                 MonoType *type;
4359                 if (!(mono_generic_container_get_param_info (container, i)->flags & (MONO_GEN_PARAM_VARIANT|MONO_GEN_PARAM_COVARIANT)))
4360                         continue;
4361                 type = ginst->type_argv [i];
4362                 if (mini_type_is_reference (type))
4363                         return TRUE;
4364         }
4365         return FALSE;
4366 }
4367
4368 static GHashTable* direct_icall_type_hash;
4369
4370 static gboolean
4371 icall_is_direct_callable (MonoCompile *cfg, MonoMethod *cmethod)
4372 {
4373         /* LLVM on amd64 can't handle calls to non-32 bit addresses */
4374         if (!direct_icalls_enabled (cfg))
4375                 return FALSE;
4376
4377         /*
4378          * An icall is directly callable if it doesn't directly or indirectly call mono_raise_exception ().
4379          * Whitelist a few icalls for now.
4380          */
4381         if (!direct_icall_type_hash) {
4382                 GHashTable *h = g_hash_table_new (g_str_hash, g_str_equal);
4383
4384                 g_hash_table_insert (h, (char*)"Decimal", GUINT_TO_POINTER (1));
4385                 g_hash_table_insert (h, (char*)"Number", GUINT_TO_POINTER (1));
4386                 g_hash_table_insert (h, (char*)"Buffer", GUINT_TO_POINTER (1));
4387                 g_hash_table_insert (h, (char*)"Monitor", GUINT_TO_POINTER (1));
4388                 mono_memory_barrier ();
4389                 direct_icall_type_hash = h;
4390         }
4391
4392         if (cmethod->klass == mono_defaults.math_class)
4393                 return TRUE;
4394         /* No locking needed */
4395         if (cmethod->klass->image == mono_defaults.corlib && g_hash_table_lookup (direct_icall_type_hash, cmethod->klass->name))
4396                 return TRUE;
4397         return FALSE;
4398 }
4399
4400 #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)
4401
4402 static MonoInst*
4403 emit_castclass_with_cache (MonoCompile *cfg, MonoClass *klass, MonoInst **args)
4404 {
4405         MonoMethod *mono_castclass;
4406         MonoInst *res;
4407
4408         mono_castclass = mono_marshal_get_castclass_with_cache ();
4409
4410         save_cast_details (cfg, klass, args [0]->dreg, TRUE);
4411         res = mono_emit_method_call (cfg, mono_castclass, args, NULL);
4412         reset_cast_details (cfg);
4413
4414         return res;
4415 }
4416
4417 static int
4418 get_castclass_cache_idx (MonoCompile *cfg)
4419 {
4420         /* Each CASTCLASS_CACHE patch needs a unique index which identifies the call site */
4421         cfg->castclass_cache_index ++;
4422         return (cfg->method_index << 16) | cfg->castclass_cache_index;
4423 }
4424
4425 static MonoInst*
4426 emit_castclass_with_cache_nonshared (MonoCompile *cfg, MonoInst *obj, MonoClass *klass)
4427 {
4428         MonoInst *args [3];
4429         int idx;
4430
4431         /* obj */
4432         args [0] = obj;
4433
4434         /* klass */
4435         EMIT_NEW_CLASSCONST (cfg, args [1], klass);
4436
4437         /* inline cache*/
4438         idx = get_castclass_cache_idx (cfg);
4439         args [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
4440
4441         /*The wrapper doesn't inline well so the bloat of inlining doesn't pay off.*/
4442         return emit_castclass_with_cache (cfg, klass, args);
4443 }
4444
4445 /*
4446  * Returns NULL and set the cfg exception on error.
4447  */
4448 static MonoInst*
4449 handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, guint8 *ip, int *inline_costs)
4450 {
4451         MonoBasicBlock *is_null_bb;
4452         int obj_reg = src->dreg;
4453         int vtable_reg = alloc_preg (cfg);
4454         int context_used;
4455         MonoInst *klass_inst = NULL, *res;
4456
4457         context_used = mini_class_check_context_used (cfg, klass);
4458
4459         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
4460                 res = emit_castclass_with_cache_nonshared (cfg, src, klass);
4461                 (*inline_costs) += 2;
4462                 return res;
4463         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
4464                 MonoMethod *mono_castclass;
4465                 MonoInst *iargs [1];
4466                 int costs;
4467
4468                 mono_castclass = mono_marshal_get_castclass (klass); 
4469                 iargs [0] = src;
4470                                 
4471                 save_cast_details (cfg, klass, src->dreg, TRUE);
4472                 costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), 
4473                                                            iargs, ip, cfg->real_offset, TRUE);
4474                 reset_cast_details (cfg);
4475                 CHECK_CFG_EXCEPTION;
4476                 g_assert (costs > 0);
4477                                 
4478                 cfg->real_offset += 5;
4479
4480                 (*inline_costs) += costs;
4481
4482                 return src;
4483         }
4484
4485         if (context_used) {
4486                 MonoInst *args [3];
4487
4488                 if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
4489                         MonoInst *cache_ins;
4490
4491                         cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
4492
4493                         /* obj */
4494                         args [0] = src;
4495
4496                         /* klass - it's the second element of the cache entry*/
4497                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
4498
4499                         /* cache */
4500                         args [2] = cache_ins;
4501
4502                         return emit_castclass_with_cache (cfg, klass, args);
4503                 }
4504
4505                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
4506         }
4507
4508         NEW_BBLOCK (cfg, is_null_bb);
4509
4510         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4511         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
4512
4513         save_cast_details (cfg, klass, obj_reg, FALSE);
4514
4515         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4516                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4517                 mini_emit_iface_cast (cfg, vtable_reg, klass, NULL, NULL);
4518         } else {
4519                 int klass_reg = alloc_preg (cfg);
4520
4521                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4522
4523                 if (!klass->rank && !cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
4524                         /* the remoting code is broken, access the class for now */
4525                         if (0) { /*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4526                                 MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4527                                 if (!vt) {
4528                                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4529                                         cfg->exception_ptr = klass;
4530                                         return NULL;
4531                                 }
4532                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4533                         } else {
4534                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4535                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4536                         }
4537                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4538                 } else {
4539                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4540                         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, klass_inst, is_null_bb);
4541                 }
4542         }
4543
4544         MONO_START_BB (cfg, is_null_bb);
4545
4546         reset_cast_details (cfg);
4547
4548         return src;
4549
4550 exception_exit:
4551         return NULL;
4552 }
4553
4554 /*
4555  * Returns NULL and set the cfg exception on error.
4556  */
4557 static MonoInst*
4558 handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
4559 {
4560         MonoInst *ins;
4561         MonoBasicBlock *is_null_bb, *false_bb, *end_bb;
4562         int obj_reg = src->dreg;
4563         int vtable_reg = alloc_preg (cfg);
4564         int res_reg = alloc_ireg_ref (cfg);
4565         MonoInst *klass_inst = NULL;
4566
4567         if (context_used) {
4568                 MonoInst *args [3];
4569
4570                 if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
4571                         MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
4572                         MonoInst *cache_ins;
4573
4574                         cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
4575
4576                         /* obj */
4577                         args [0] = src;
4578
4579                         /* klass - it's the second element of the cache entry*/
4580                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
4581
4582                         /* cache */
4583                         args [2] = cache_ins;
4584
4585                         return mono_emit_method_call (cfg, mono_isinst, args, NULL);
4586                 }
4587
4588                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
4589         }
4590
4591         NEW_BBLOCK (cfg, is_null_bb);
4592         NEW_BBLOCK (cfg, false_bb);
4593         NEW_BBLOCK (cfg, end_bb);
4594
4595         /* Do the assignment at the beginning, so the other assignment can be if converted */
4596         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, res_reg, obj_reg);
4597         ins->type = STACK_OBJ;
4598         ins->klass = klass;
4599
4600         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4601         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_null_bb);
4602
4603         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4604
4605         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4606                 g_assert (!context_used);
4607                 /* the is_null_bb target simply copies the input register to the output */
4608                 mini_emit_iface_cast (cfg, vtable_reg, klass, false_bb, is_null_bb);
4609         } else {
4610                 int klass_reg = alloc_preg (cfg);
4611
4612                 if (klass->rank) {
4613                         int rank_reg = alloc_preg (cfg);
4614                         int eclass_reg = alloc_preg (cfg);
4615
4616                         g_assert (!context_used);
4617                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
4618                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
4619                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4620                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4621                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
4622                         if (klass->cast_class == mono_defaults.object_class) {
4623                                 int parent_reg = alloc_preg (cfg);
4624                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
4625                                 mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, is_null_bb);
4626                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4627                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4628                         } else if (klass->cast_class == mono_defaults.enum_class->parent) {
4629                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, is_null_bb);
4630                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);                          
4631                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4632                         } else if (klass->cast_class == mono_defaults.enum_class) {
4633                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4634                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4635                         } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
4636                                 mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4637                         } else {
4638                                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY)) {
4639                                         /* Check that the object is a vector too */
4640                                         int bounds_reg = alloc_preg (cfg);
4641                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
4642                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
4643                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4644                                 }
4645
4646                                 /* the is_null_bb target simply copies the input register to the output */
4647                                 mini_emit_isninst_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4648                         }
4649                 } else if (mono_class_is_nullable (klass)) {
4650                         g_assert (!context_used);
4651                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4652                         /* the is_null_bb target simply copies the input register to the output */
4653                         mini_emit_isninst_cast (cfg, klass_reg, klass->cast_class, false_bb, is_null_bb);
4654                 } else {
4655                         if (!cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
4656                                 g_assert (!context_used);
4657                                 /* the remoting code is broken, access the class for now */
4658                                 if (0) {/*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4659                                         MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4660                                         if (!vt) {
4661                                                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4662                                                 cfg->exception_ptr = klass;
4663                                                 return NULL;
4664                                         }
4665                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4666                                 } else {
4667                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4668                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4669                                 }
4670                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4671                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, is_null_bb);
4672                         } else {
4673                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4674                                 /* the is_null_bb target simply copies the input register to the output */
4675                                 mini_emit_isninst_cast_inst (cfg, klass_reg, klass, klass_inst, false_bb, is_null_bb);
4676                         }
4677                 }
4678         }
4679
4680         MONO_START_BB (cfg, false_bb);
4681
4682         MONO_EMIT_NEW_PCONST (cfg, res_reg, 0);
4683         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4684
4685         MONO_START_BB (cfg, is_null_bb);
4686
4687         MONO_START_BB (cfg, end_bb);
4688
4689         return ins;
4690 }
4691
4692 static MonoInst*
4693 handle_cisinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4694 {
4695         /* This opcode takes as input an object reference and a class, and returns:
4696         0) if the object is an instance of the class,
4697         1) if the object is not instance of the class,
4698         2) if the object is a proxy whose type cannot be determined */
4699
4700         MonoInst *ins;
4701 #ifndef DISABLE_REMOTING
4702         MonoBasicBlock *true_bb, *false_bb, *false2_bb, *end_bb, *no_proxy_bb, *interface_fail_bb;
4703 #else
4704         MonoBasicBlock *true_bb, *false_bb, *end_bb;
4705 #endif
4706         int obj_reg = src->dreg;
4707         int dreg = alloc_ireg (cfg);
4708         int tmp_reg;
4709 #ifndef DISABLE_REMOTING
4710         int klass_reg = alloc_preg (cfg);
4711 #endif
4712
4713         NEW_BBLOCK (cfg, true_bb);
4714         NEW_BBLOCK (cfg, false_bb);
4715         NEW_BBLOCK (cfg, end_bb);
4716 #ifndef DISABLE_REMOTING
4717         NEW_BBLOCK (cfg, false2_bb);
4718         NEW_BBLOCK (cfg, no_proxy_bb);
4719 #endif
4720
4721         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4722         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, false_bb);
4723
4724         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4725 #ifndef DISABLE_REMOTING
4726                 NEW_BBLOCK (cfg, interface_fail_bb);
4727 #endif
4728
4729                 tmp_reg = alloc_preg (cfg);
4730                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4731 #ifndef DISABLE_REMOTING
4732                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, true_bb);
4733                 MONO_START_BB (cfg, interface_fail_bb);
4734                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4735                 
4736                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, false_bb);
4737
4738                 tmp_reg = alloc_preg (cfg);
4739                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4740                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4741                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false2_bb);                
4742 #else
4743                 mini_emit_iface_cast (cfg, tmp_reg, klass, false_bb, true_bb);
4744 #endif
4745         } else {
4746 #ifndef DISABLE_REMOTING
4747                 tmp_reg = alloc_preg (cfg);
4748                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4749                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4750
4751                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4752                 tmp_reg = alloc_preg (cfg);
4753                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4754                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4755
4756                 tmp_reg = alloc_preg (cfg);             
4757                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4758                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4759                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4760                 
4761                 mini_emit_isninst_cast (cfg, klass_reg, klass, false2_bb, true_bb);
4762                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false2_bb);
4763
4764                 MONO_START_BB (cfg, no_proxy_bb);
4765
4766                 mini_emit_isninst_cast (cfg, klass_reg, klass, false_bb, true_bb);
4767 #else
4768                 g_error ("transparent proxy support is disabled while trying to JIT code that uses it");
4769 #endif
4770         }
4771
4772         MONO_START_BB (cfg, false_bb);
4773
4774         MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4775         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4776
4777 #ifndef DISABLE_REMOTING
4778         MONO_START_BB (cfg, false2_bb);
4779
4780         MONO_EMIT_NEW_ICONST (cfg, dreg, 2);
4781         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4782 #endif
4783
4784         MONO_START_BB (cfg, true_bb);
4785
4786         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4787
4788         MONO_START_BB (cfg, end_bb);
4789
4790         /* FIXME: */
4791         MONO_INST_NEW (cfg, ins, OP_ICONST);
4792         ins->dreg = dreg;
4793         ins->type = STACK_I4;
4794
4795         return ins;
4796 }
4797
4798 static MonoInst*
4799 handle_ccastclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4800 {
4801         /* This opcode takes as input an object reference and a class, and returns:
4802         0) if the object is an instance of the class,
4803         1) if the object is a proxy whose type cannot be determined
4804         an InvalidCastException exception is thrown otherwhise*/
4805         
4806         MonoInst *ins;
4807 #ifndef DISABLE_REMOTING
4808         MonoBasicBlock *end_bb, *ok_result_bb, *no_proxy_bb, *interface_fail_bb, *fail_1_bb;
4809 #else
4810         MonoBasicBlock *ok_result_bb;
4811 #endif
4812         int obj_reg = src->dreg;
4813         int dreg = alloc_ireg (cfg);
4814         int tmp_reg = alloc_preg (cfg);
4815
4816 #ifndef DISABLE_REMOTING
4817         int klass_reg = alloc_preg (cfg);
4818         NEW_BBLOCK (cfg, end_bb);
4819 #endif
4820
4821         NEW_BBLOCK (cfg, ok_result_bb);
4822
4823         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4824         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, ok_result_bb);
4825
4826         save_cast_details (cfg, klass, obj_reg, FALSE);
4827
4828         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4829 #ifndef DISABLE_REMOTING
4830                 NEW_BBLOCK (cfg, interface_fail_bb);
4831         
4832                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4833                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, ok_result_bb);
4834                 MONO_START_BB (cfg, interface_fail_bb);
4835                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4836
4837                 mini_emit_class_check (cfg, klass_reg, mono_defaults.transparent_proxy_class);
4838
4839                 tmp_reg = alloc_preg (cfg);             
4840                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4841                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4842                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
4843                 
4844                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4845                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4846 #else
4847                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4848                 mini_emit_iface_cast (cfg, tmp_reg, klass, NULL, NULL);
4849                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, ok_result_bb);
4850 #endif
4851         } else {
4852 #ifndef DISABLE_REMOTING
4853                 NEW_BBLOCK (cfg, no_proxy_bb);
4854
4855                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4856                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4857                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4858
4859                 tmp_reg = alloc_preg (cfg);
4860                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4861                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4862
4863                 tmp_reg = alloc_preg (cfg);
4864                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4865                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4866                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4867
4868                 NEW_BBLOCK (cfg, fail_1_bb);
4869                 
4870                 mini_emit_isninst_cast (cfg, klass_reg, klass, fail_1_bb, ok_result_bb);
4871
4872                 MONO_START_BB (cfg, fail_1_bb);
4873
4874                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4875                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4876
4877                 MONO_START_BB (cfg, no_proxy_bb);
4878
4879                 mini_emit_castclass (cfg, obj_reg, klass_reg, klass, ok_result_bb);
4880 #else
4881                 g_error ("Transparent proxy support is disabled while trying to JIT code that uses it");
4882 #endif
4883         }
4884
4885         MONO_START_BB (cfg, ok_result_bb);
4886
4887         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4888
4889 #ifndef DISABLE_REMOTING
4890         MONO_START_BB (cfg, end_bb);
4891 #endif
4892
4893         /* FIXME: */
4894         MONO_INST_NEW (cfg, ins, OP_ICONST);
4895         ins->dreg = dreg;
4896         ins->type = STACK_I4;
4897
4898         return ins;
4899 }
4900
4901 static G_GNUC_UNUSED MonoInst*
4902 handle_enum_has_flag (MonoCompile *cfg, MonoClass *klass, MonoInst *enum_this, MonoInst *enum_flag)
4903 {
4904         MonoType *enum_type = mono_type_get_underlying_type (&klass->byval_arg);
4905         guint32 load_opc = mono_type_to_load_membase (cfg, enum_type);
4906         gboolean is_i4;
4907
4908         switch (enum_type->type) {
4909         case MONO_TYPE_I8:
4910         case MONO_TYPE_U8:
4911 #if SIZEOF_REGISTER == 8
4912         case MONO_TYPE_I:
4913         case MONO_TYPE_U:
4914 #endif
4915                 is_i4 = FALSE;
4916                 break;
4917         default:
4918                 is_i4 = TRUE;
4919                 break;
4920         }
4921
4922         {
4923                 MonoInst *load, *and, *cmp, *ceq;
4924                 int enum_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
4925                 int and_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
4926                 int dest_reg = alloc_ireg (cfg);
4927
4928                 EMIT_NEW_LOAD_MEMBASE (cfg, load, load_opc, enum_reg, enum_this->dreg, 0);
4929                 EMIT_NEW_BIALU (cfg, and, is_i4 ? OP_IAND : OP_LAND, and_reg, enum_reg, enum_flag->dreg);
4930                 EMIT_NEW_BIALU (cfg, cmp, is_i4 ? OP_ICOMPARE : OP_LCOMPARE, -1, and_reg, enum_flag->dreg);
4931                 EMIT_NEW_UNALU (cfg, ceq, is_i4 ? OP_ICEQ : OP_LCEQ, dest_reg, -1);
4932
4933                 ceq->type = STACK_I4;
4934
4935                 if (!is_i4) {
4936                         load = mono_decompose_opcode (cfg, load);
4937                         and = mono_decompose_opcode (cfg, and);
4938                         cmp = mono_decompose_opcode (cfg, cmp);
4939                         ceq = mono_decompose_opcode (cfg, ceq);
4940                 }
4941
4942                 return ceq;
4943         }
4944 }
4945
4946 /*
4947  * Returns NULL and set the cfg exception on error.
4948  */
4949 static G_GNUC_UNUSED MonoInst*
4950 handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, MonoMethod *method, int context_used, gboolean virtual)
4951 {
4952         MonoInst *ptr;
4953         int dreg;
4954         gpointer trampoline;
4955         MonoInst *obj, *method_ins, *tramp_ins;
4956         MonoDomain *domain;
4957         guint8 **code_slot;
4958
4959         if (virtual && !cfg->llvm_only) {
4960                 MonoMethod *invoke = mono_get_delegate_invoke (klass);
4961                 g_assert (invoke);
4962
4963                 if (!mono_get_delegate_virtual_invoke_impl (mono_method_signature (invoke), context_used ? NULL : method))
4964                         return NULL;
4965         }
4966
4967         obj = handle_alloc (cfg, klass, FALSE, mono_class_check_context_used (klass));
4968         if (!obj)
4969                 return NULL;
4970
4971         if (cfg->llvm_only) {
4972                 MonoInst *args [16];
4973
4974                 /*
4975                  * If the method to be called needs an rgctx, we can't fall back to mono_delegate_ctor (), since it might receive
4976                  * the address of a gshared method. So use a JIT icall.
4977                  * FIXME: Optimize this.
4978                  */
4979                 args [0] = obj;
4980                 args [1] = target;
4981                 args [2] = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
4982                 mono_emit_jit_icall (cfg, virtual ? mono_init_delegate_virtual : mono_init_delegate, args);
4983
4984                 return obj;
4985         }
4986
4987         /* Inline the contents of mono_delegate_ctor */
4988
4989         /* Set target field */
4990         /* Optimize away setting of NULL target */
4991         if (!(target->opcode == OP_PCONST && target->inst_p0 == 0)) {
4992                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target), target->dreg);
4993                 if (cfg->gen_write_barriers) {
4994                         dreg = alloc_preg (cfg);
4995                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target));
4996                         emit_write_barrier (cfg, ptr, target);
4997                 }
4998         }
4999
5000         /* Set method field */
5001         method_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
5002         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method), method_ins->dreg);
5003
5004         /* 
5005          * To avoid looking up the compiled code belonging to the target method
5006          * in mono_delegate_trampoline (), we allocate a per-domain memory slot to
5007          * store it, and we fill it after the method has been compiled.
5008          */
5009         if (!method->dynamic && !(cfg->opt & MONO_OPT_SHARED)) {
5010                 MonoInst *code_slot_ins;
5011
5012                 if (context_used) {
5013                         code_slot_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD_DELEGATE_CODE);
5014                 } else {
5015                         domain = mono_domain_get ();
5016                         mono_domain_lock (domain);
5017                         if (!domain_jit_info (domain)->method_code_hash)
5018                                 domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
5019                         code_slot = g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, method);
5020                         if (!code_slot) {
5021                                 code_slot = mono_domain_alloc0 (domain, sizeof (gpointer));
5022                                 g_hash_table_insert (domain_jit_info (domain)->method_code_hash, method, code_slot);
5023                         }
5024                         mono_domain_unlock (domain);
5025
5026                         code_slot_ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_METHOD_CODE_SLOT, method);
5027                 }
5028                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_code), code_slot_ins->dreg);                
5029         }
5030
5031         if (cfg->compile_aot) {
5032                 MonoDelegateClassMethodPair *del_tramp;
5033
5034                 del_tramp = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoDelegateClassMethodPair));
5035                 del_tramp->klass = klass;
5036                 del_tramp->method = context_used ? NULL : method;
5037                 del_tramp->is_virtual = virtual;
5038                 EMIT_NEW_AOTCONST (cfg, tramp_ins, MONO_PATCH_INFO_DELEGATE_TRAMPOLINE, del_tramp);
5039         } else {
5040                 if (virtual)
5041                         trampoline = mono_create_delegate_virtual_trampoline (cfg->domain, klass, context_used ? NULL : method);
5042                 else
5043                         trampoline = mono_create_delegate_trampoline_info (cfg->domain, klass, context_used ? NULL : method);
5044                 EMIT_NEW_PCONST (cfg, tramp_ins, trampoline);
5045         }
5046
5047         /* Set invoke_impl field */
5048         if (virtual) {
5049                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), tramp_ins->dreg);
5050         } else {
5051                 dreg = alloc_preg (cfg);
5052                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, invoke_impl));
5053                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), dreg);
5054
5055                 dreg = alloc_preg (cfg);
5056                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, method_ptr));
5057                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr), dreg);
5058         }
5059
5060         dreg = alloc_preg (cfg);
5061         MONO_EMIT_NEW_ICONST (cfg, dreg, virtual ? 1 : 0);
5062         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_is_virtual), dreg);
5063
5064         /* All the checks which are in mono_delegate_ctor () are done by the delegate trampoline */
5065
5066         return obj;
5067 }
5068
5069 static MonoInst*
5070 handle_array_new (MonoCompile *cfg, int rank, MonoInst **sp, unsigned char *ip)
5071 {
5072         MonoJitICallInfo *info;
5073
5074         /* Need to register the icall so it gets an icall wrapper */
5075         info = mono_get_array_new_va_icall (rank);
5076
5077         cfg->flags |= MONO_CFG_HAS_VARARGS;
5078
5079         /* mono_array_new_va () needs a vararg calling convention */
5080         cfg->disable_llvm = TRUE;
5081
5082         /* FIXME: This uses info->sig, but it should use the signature of the wrapper */
5083         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, sp);
5084 }
5085
5086 /*
5087  * handle_constrained_gsharedvt_call:
5088  *
5089  *   Handle constrained calls where the receiver is a gsharedvt type.
5090  * Return the instruction representing the call. Set the cfg exception on failure.
5091  */
5092 static MonoInst*
5093 handle_constrained_gsharedvt_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp, MonoClass *constrained_class,
5094                                                                    gboolean *ref_emit_widen)
5095 {
5096         MonoInst *ins = NULL;
5097         gboolean emit_widen = *ref_emit_widen;
5098
5099         /*
5100          * Constrained calls need to behave differently at runtime dependending on whenever the receiver is instantiated as ref type or as a vtype.
5101          * 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
5102          * pack the arguments into an array, and do the rest of the work in in an icall.
5103          */
5104         if (((cmethod->klass == mono_defaults.object_class) || (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) || (!cmethod->klass->valuetype && cmethod->klass->image != mono_defaults.corlib)) &&
5105                 (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)) &&
5106                 (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]))))) {
5107                 MonoInst *args [16];
5108
5109                 /*
5110                  * This case handles calls to
5111                  * - object:ToString()/Equals()/GetHashCode(),
5112                  * - System.IComparable<T>:CompareTo()
5113                  * - System.IEquatable<T>:Equals ()
5114                  * plus some simple interface calls enough to support AsyncTaskMethodBuilder.
5115                  */
5116
5117                 args [0] = sp [0];
5118                 if (mono_method_check_context_used (cmethod))
5119                         args [1] = emit_get_rgctx_method (cfg, mono_method_check_context_used (cmethod), cmethod, MONO_RGCTX_INFO_METHOD);
5120                 else
5121                         EMIT_NEW_METHODCONST (cfg, args [1], cmethod);
5122                 args [2] = emit_get_rgctx_klass (cfg, mono_class_check_context_used (constrained_class), constrained_class, MONO_RGCTX_INFO_KLASS);
5123
5124                 /* !fsig->hasthis is for the wrapper for the Object.GetType () icall */
5125                 if (fsig->hasthis && fsig->param_count) {
5126                         /* Pass the arguments using a localloc-ed array using the format expected by runtime_invoke () */
5127                         MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
5128                         ins->dreg = alloc_preg (cfg);
5129                         ins->inst_imm = fsig->param_count * sizeof (mgreg_t);
5130                         MONO_ADD_INS (cfg->cbb, ins);
5131                         args [4] = ins;
5132
5133                         if (mini_is_gsharedvt_type (fsig->params [0])) {
5134                                 int addr_reg, deref_arg_reg;
5135
5136                                 ins = emit_get_gsharedvt_info_klass (cfg, mono_class_from_mono_type (fsig->params [0]), MONO_RGCTX_INFO_CLASS_BOX_TYPE);
5137                                 deref_arg_reg = alloc_preg (cfg);
5138                                 /* deref_arg = BOX_TYPE != MONO_GSHAREDVT_BOX_TYPE_VTYPE */
5139                                 EMIT_NEW_BIALU_IMM (cfg, args [3], OP_ISUB_IMM, deref_arg_reg, ins->dreg, 1);
5140
5141                                 EMIT_NEW_VARLOADA_VREG (cfg, ins, sp [1]->dreg, fsig->params [0]);
5142                                 addr_reg = ins->dreg;
5143                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, addr_reg);
5144                         } else {
5145                                 EMIT_NEW_ICONST (cfg, args [3], 0);
5146                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, sp [1]->dreg);
5147                         }
5148                 } else {
5149                         EMIT_NEW_ICONST (cfg, args [3], 0);
5150                         EMIT_NEW_ICONST (cfg, args [4], 0);
5151                 }
5152                 ins = mono_emit_jit_icall (cfg, mono_gsharedvt_constrained_call, args);
5153                 emit_widen = FALSE;
5154
5155                 if (mini_is_gsharedvt_type (fsig->ret)) {
5156                         ins = handle_unbox_gsharedvt (cfg, mono_class_from_mono_type (fsig->ret), ins);
5157                 } else if (MONO_TYPE_IS_PRIMITIVE (fsig->ret) || MONO_TYPE_ISSTRUCT (fsig->ret)) {
5158                         MonoInst *add;
5159
5160                         /* Unbox */
5161                         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), ins->dreg, sizeof (MonoObject));
5162                         MONO_ADD_INS (cfg->cbb, add);
5163                         /* Load value */
5164                         NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, add->dreg, 0);
5165                         MONO_ADD_INS (cfg->cbb, ins);
5166                         /* ins represents the call result */
5167                 }
5168         } else {
5169                 GSHAREDVT_FAILURE (CEE_CALLVIRT);
5170         }
5171
5172         *ref_emit_widen = emit_widen;
5173
5174         return ins;
5175
5176  exception_exit:
5177         return NULL;
5178 }
5179
5180 static void
5181 mono_emit_load_got_addr (MonoCompile *cfg)
5182 {
5183         MonoInst *getaddr, *dummy_use;
5184
5185         if (!cfg->got_var || cfg->got_var_allocated)
5186                 return;
5187
5188         MONO_INST_NEW (cfg, getaddr, OP_LOAD_GOTADDR);
5189         getaddr->cil_code = cfg->header->code;
5190         getaddr->dreg = cfg->got_var->dreg;
5191
5192         /* Add it to the start of the first bblock */
5193         if (cfg->bb_entry->code) {
5194                 getaddr->next = cfg->bb_entry->code;
5195                 cfg->bb_entry->code = getaddr;
5196         }
5197         else
5198                 MONO_ADD_INS (cfg->bb_entry, getaddr);
5199
5200         cfg->got_var_allocated = TRUE;
5201
5202         /* 
5203          * Add a dummy use to keep the got_var alive, since real uses might
5204          * only be generated by the back ends.
5205          * Add it to end_bblock, so the variable's lifetime covers the whole
5206          * method.
5207          * It would be better to make the usage of the got var explicit in all
5208          * cases when the backend needs it (i.e. calls, throw etc.), so this
5209          * wouldn't be needed.
5210          */
5211         NEW_DUMMY_USE (cfg, dummy_use, cfg->got_var);
5212         MONO_ADD_INS (cfg->bb_exit, dummy_use);
5213 }
5214
5215 static int inline_limit;
5216 static gboolean inline_limit_inited;
5217
5218 static gboolean
5219 mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
5220 {
5221         MonoMethodHeaderSummary header;
5222         MonoVTable *vtable;
5223 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
5224         MonoMethodSignature *sig = mono_method_signature (method);
5225         int i;
5226 #endif
5227
5228         if (cfg->disable_inline)
5229                 return FALSE;
5230         if (cfg->gshared)
5231                 return FALSE;
5232
5233         if (cfg->inline_depth > 10)
5234                 return FALSE;
5235
5236         if (!mono_method_get_header_summary (method, &header))
5237                 return FALSE;
5238
5239         /*runtime, icall and pinvoke are checked by summary call*/
5240         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
5241             (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
5242             (mono_class_is_marshalbyref (method->klass)) ||
5243             header.has_clauses)
5244                 return FALSE;
5245
5246         /* also consider num_locals? */
5247         /* Do the size check early to avoid creating vtables */
5248         if (!inline_limit_inited) {
5249                 if (g_getenv ("MONO_INLINELIMIT"))
5250                         inline_limit = atoi (g_getenv ("MONO_INLINELIMIT"));
5251                 else
5252                         inline_limit = INLINE_LENGTH_LIMIT;
5253                 inline_limit_inited = TRUE;
5254         }
5255         if (header.code_size >= inline_limit && !(method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))
5256                 return FALSE;
5257
5258         /*
5259          * if we can initialize the class of the method right away, we do,
5260          * otherwise we don't allow inlining if the class needs initialization,
5261          * since it would mean inserting a call to mono_runtime_class_init()
5262          * inside the inlined code
5263          */
5264         if (!(cfg->opt & MONO_OPT_SHARED)) {
5265                 /* The AggressiveInlining hint is a good excuse to force that cctor to run. */
5266                 if (method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING) {
5267                         vtable = mono_class_vtable (cfg->domain, method->klass);
5268                         if (!vtable)
5269                                 return FALSE;
5270                         if (!cfg->compile_aot)
5271                                 mono_runtime_class_init (vtable);
5272                 } else if (method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
5273                         if (cfg->run_cctors && method->klass->has_cctor) {
5274                                 /*FIXME it would easier and lazier to just use mono_class_try_get_vtable */
5275                                 if (!method->klass->runtime_info)
5276                                         /* No vtable created yet */
5277                                         return FALSE;
5278                                 vtable = mono_class_vtable (cfg->domain, method->klass);
5279                                 if (!vtable)
5280                                         return FALSE;
5281                                 /* This makes so that inline cannot trigger */
5282                                 /* .cctors: too many apps depend on them */
5283                                 /* running with a specific order... */
5284                                 if (! vtable->initialized)
5285                                         return FALSE;
5286                                 mono_runtime_class_init (vtable);
5287                         }
5288                 } else if (mono_class_needs_cctor_run (method->klass, NULL)) {
5289                         if (!method->klass->runtime_info)
5290                                 /* No vtable created yet */
5291                                 return FALSE;
5292                         vtable = mono_class_vtable (cfg->domain, method->klass);
5293                         if (!vtable)
5294                                 return FALSE;
5295                         if (!vtable->initialized)
5296                                 return FALSE;
5297                 }
5298         } else {
5299                 /* 
5300                  * If we're compiling for shared code
5301                  * the cctor will need to be run at aot method load time, for example,
5302                  * or at the end of the compilation of the inlining method.
5303                  */
5304                 if (mono_class_needs_cctor_run (method->klass, NULL) && !((method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)))
5305                         return FALSE;
5306         }
5307
5308 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
5309         if (mono_arch_is_soft_float ()) {
5310                 /* FIXME: */
5311                 if (sig->ret && sig->ret->type == MONO_TYPE_R4)
5312                         return FALSE;
5313                 for (i = 0; i < sig->param_count; ++i)
5314                         if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_R4)
5315                                 return FALSE;
5316         }
5317 #endif
5318
5319         if (g_list_find (cfg->dont_inline, method))
5320                 return FALSE;
5321
5322         return TRUE;
5323 }
5324
5325 static gboolean
5326 mini_field_access_needs_cctor_run (MonoCompile *cfg, MonoMethod *method, MonoClass *klass, MonoVTable *vtable)
5327 {
5328         if (!cfg->compile_aot) {
5329                 g_assert (vtable);
5330                 if (vtable->initialized)
5331                         return FALSE;
5332         }
5333
5334         if (klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
5335                 if (cfg->method == method)
5336                         return FALSE;
5337         }
5338
5339         if (!mono_class_needs_cctor_run (klass, method))
5340                 return FALSE;
5341
5342         if (! (method->flags & METHOD_ATTRIBUTE_STATIC) && (klass == method->klass))
5343                 /* The initialization is already done before the method is called */
5344                 return FALSE;
5345
5346         return TRUE;
5347 }
5348
5349 static MonoInst*
5350 mini_emit_ldelema_1_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index, gboolean bcheck)
5351 {
5352         MonoInst *ins;
5353         guint32 size;
5354         int mult_reg, add_reg, array_reg, index_reg, index2_reg;
5355         int context_used;
5356
5357         if (mini_is_gsharedvt_variable_klass (klass)) {
5358                 size = -1;
5359         } else {
5360                 mono_class_init (klass);
5361                 size = mono_class_array_element_size (klass);
5362         }
5363
5364         mult_reg = alloc_preg (cfg);
5365         array_reg = arr->dreg;
5366         index_reg = index->dreg;
5367
5368 #if SIZEOF_REGISTER == 8
5369         /* The array reg is 64 bits but the index reg is only 32 */
5370         if (COMPILE_LLVM (cfg)) {
5371                 /* Not needed */
5372                 index2_reg = index_reg;
5373         } else {
5374                 index2_reg = alloc_preg (cfg);
5375                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index2_reg, index_reg);
5376         }
5377 #else
5378         if (index->type == STACK_I8) {
5379                 index2_reg = alloc_preg (cfg);
5380                 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I4, index2_reg, index_reg);
5381         } else {
5382                 index2_reg = index_reg;
5383         }
5384 #endif
5385
5386         if (bcheck)
5387                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index2_reg);
5388
5389 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5390         if (size == 1 || size == 2 || size == 4 || size == 8) {
5391                 static const int fast_log2 [] = { 1, 0, 1, -1, 2, -1, -1, -1, 3 };
5392
5393                 EMIT_NEW_X86_LEA (cfg, ins, array_reg, index2_reg, fast_log2 [size], MONO_STRUCT_OFFSET (MonoArray, vector));
5394                 ins->klass = mono_class_get_element_class (klass);
5395                 ins->type = STACK_MP;
5396
5397                 return ins;
5398         }
5399 #endif          
5400
5401         add_reg = alloc_ireg_mp (cfg);
5402
5403         if (size == -1) {
5404                 MonoInst *rgctx_ins;
5405
5406                 /* gsharedvt */
5407                 g_assert (cfg->gshared);
5408                 context_used = mini_class_check_context_used (cfg, klass);
5409                 g_assert (context_used);
5410                 rgctx_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE);
5411                 MONO_EMIT_NEW_BIALU (cfg, OP_IMUL, mult_reg, index2_reg, rgctx_ins->dreg);
5412         } else {
5413                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MUL_IMM, mult_reg, index2_reg, size);
5414         }
5415         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, array_reg, mult_reg);
5416         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
5417         ins->klass = mono_class_get_element_class (klass);
5418         ins->type = STACK_MP;
5419         MONO_ADD_INS (cfg->cbb, ins);
5420
5421         return ins;
5422 }
5423
5424 static MonoInst*
5425 mini_emit_ldelema_2_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index_ins1, MonoInst *index_ins2)
5426 {
5427         int bounds_reg = alloc_preg (cfg);
5428         int add_reg = alloc_ireg_mp (cfg);
5429         int mult_reg = alloc_preg (cfg);
5430         int mult2_reg = alloc_preg (cfg);
5431         int low1_reg = alloc_preg (cfg);
5432         int low2_reg = alloc_preg (cfg);
5433         int high1_reg = alloc_preg (cfg);
5434         int high2_reg = alloc_preg (cfg);
5435         int realidx1_reg = alloc_preg (cfg);
5436         int realidx2_reg = alloc_preg (cfg);
5437         int sum_reg = alloc_preg (cfg);
5438         int index1, index2, tmpreg;
5439         MonoInst *ins;
5440         guint32 size;
5441
5442         mono_class_init (klass);
5443         size = mono_class_array_element_size (klass);
5444
5445         index1 = index_ins1->dreg;
5446         index2 = index_ins2->dreg;
5447
5448 #if SIZEOF_REGISTER == 8
5449         /* The array reg is 64 bits but the index reg is only 32 */
5450         if (COMPILE_LLVM (cfg)) {
5451                 /* Not needed */
5452         } else {
5453                 tmpreg = alloc_preg (cfg);
5454                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index1);
5455                 index1 = tmpreg;
5456                 tmpreg = alloc_preg (cfg);
5457                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index2);
5458                 index2 = tmpreg;
5459         }
5460 #else
5461         // FIXME: Do we need to do something here for i8 indexes, like in ldelema_1_ins ?
5462         tmpreg = -1;
5463 #endif
5464
5465         /* range checking */
5466         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, 
5467                                        arr->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
5468
5469         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low1_reg, 
5470                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5471         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx1_reg, index1, low1_reg);
5472         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high1_reg, 
5473                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5474         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high1_reg, realidx1_reg);
5475         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
5476
5477         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low2_reg, 
5478                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5479         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx2_reg, index2, low2_reg);
5480         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high2_reg, 
5481                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5482         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high2_reg, realidx2_reg);
5483         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
5484
5485         MONO_EMIT_NEW_BIALU (cfg, OP_PMUL, mult_reg, high2_reg, realidx1_reg);
5486         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, mult_reg, realidx2_reg);
5487         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PMUL_IMM, mult2_reg, sum_reg, size);
5488         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult2_reg, arr->dreg);
5489         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
5490
5491         ins->type = STACK_MP;
5492         ins->klass = klass;
5493         MONO_ADD_INS (cfg->cbb, ins);
5494
5495         return ins;
5496 }
5497
5498 static MonoInst*
5499 mini_emit_ldelema_ins (MonoCompile *cfg, MonoMethod *cmethod, MonoInst **sp, unsigned char *ip, gboolean is_set)
5500 {
5501         int rank;
5502         MonoInst *addr;
5503         MonoMethod *addr_method;
5504         int element_size;
5505         MonoClass *eclass = cmethod->klass->element_class;
5506
5507         rank = mono_method_signature (cmethod)->param_count - (is_set? 1: 0);
5508
5509         if (rank == 1)
5510                 return mini_emit_ldelema_1_ins (cfg, eclass, sp [0], sp [1], TRUE);
5511
5512         /* emit_ldelema_2 depends on OP_LMUL */
5513         if (!cfg->backend->emulate_mul_div && rank == 2 && (cfg->opt & MONO_OPT_INTRINS) && !mini_is_gsharedvt_variable_klass (eclass)) {
5514                 return mini_emit_ldelema_2_ins (cfg, eclass, sp [0], sp [1], sp [2]);
5515         }
5516
5517         if (mini_is_gsharedvt_variable_klass (eclass))
5518                 element_size = 0;
5519         else
5520                 element_size = mono_class_array_element_size (eclass);
5521         addr_method = mono_marshal_get_array_address (rank, element_size);
5522         addr = mono_emit_method_call (cfg, addr_method, sp, NULL);
5523
5524         return addr;
5525 }
5526
5527 static MonoBreakPolicy
5528 always_insert_breakpoint (MonoMethod *method)
5529 {
5530         return MONO_BREAK_POLICY_ALWAYS;
5531 }
5532
5533 static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
5534
5535 /**
5536  * mono_set_break_policy:
5537  * policy_callback: the new callback function
5538  *
5539  * Allow embedders to decide wherther to actually obey breakpoint instructions
5540  * (both break IL instructions and Debugger.Break () method calls), for example
5541  * to not allow an app to be aborted by a perfectly valid IL opcode when executing
5542  * untrusted or semi-trusted code.
5543  *
5544  * @policy_callback will be called every time a break point instruction needs to
5545  * be inserted with the method argument being the method that calls Debugger.Break()
5546  * or has the IL break instruction. The callback should return #MONO_BREAK_POLICY_NEVER
5547  * if it wants the breakpoint to not be effective in the given method.
5548  * #MONO_BREAK_POLICY_ALWAYS is the default.
5549  */
5550 void
5551 mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
5552 {
5553         if (policy_callback)
5554                 break_policy_func = policy_callback;
5555         else
5556                 break_policy_func = always_insert_breakpoint;
5557 }
5558
5559 static gboolean
5560 should_insert_brekpoint (MonoMethod *method) {
5561         switch (break_policy_func (method)) {
5562         case MONO_BREAK_POLICY_ALWAYS:
5563                 return TRUE;
5564         case MONO_BREAK_POLICY_NEVER:
5565                 return FALSE;
5566         case MONO_BREAK_POLICY_ON_DBG:
5567                 g_warning ("mdb no longer supported");
5568                 return FALSE;
5569         default:
5570                 g_warning ("Incorrect value returned from break policy callback");
5571                 return FALSE;
5572         }
5573 }
5574
5575 /* optimize the simple GetGenericValueImpl/SetGenericValueImpl generic icalls */
5576 static MonoInst*
5577 emit_array_generic_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
5578 {
5579         MonoInst *addr, *store, *load;
5580         MonoClass *eklass = mono_class_from_mono_type (fsig->params [2]);
5581
5582         /* the bounds check is already done by the callers */
5583         addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
5584         if (is_set) {
5585                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, args [2]->dreg, 0);
5586                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, addr->dreg, 0, load->dreg);
5587                 if (mini_type_is_reference (fsig->params [2]))
5588                         emit_write_barrier (cfg, addr, load);
5589         } else {
5590                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, addr->dreg, 0);
5591                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, args [2]->dreg, 0, load->dreg);
5592         }
5593         return store;
5594 }
5595
5596
5597 static gboolean
5598 generic_class_is_reference_type (MonoCompile *cfg, MonoClass *klass)
5599 {
5600         return mini_type_is_reference (&klass->byval_arg);
5601 }
5602
5603 static MonoInst*
5604 emit_array_store (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, gboolean safety_checks)
5605 {
5606         if (safety_checks && generic_class_is_reference_type (cfg, klass) &&
5607                 !(sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL)) {
5608                 MonoClass *obj_array = mono_array_class_get_cached (mono_defaults.object_class, 1);
5609                 MonoMethod *helper = mono_marshal_get_virtual_stelemref (obj_array);
5610                 MonoInst *iargs [3];
5611
5612                 if (!helper->slot)
5613                         mono_class_setup_vtable (obj_array);
5614                 g_assert (helper->slot);
5615
5616                 if (sp [0]->type != STACK_OBJ)
5617                         return NULL;
5618                 if (sp [2]->type != STACK_OBJ)
5619                         return NULL;
5620
5621                 iargs [2] = sp [2];
5622                 iargs [1] = sp [1];
5623                 iargs [0] = sp [0];
5624
5625                 return mono_emit_method_call (cfg, helper, iargs, sp [0]);
5626         } else {
5627                 MonoInst *ins;
5628
5629                 if (mini_is_gsharedvt_variable_klass (klass)) {
5630                         MonoInst *addr;
5631
5632                         // FIXME-VT: OP_ICONST optimization
5633                         addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
5634                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5635                         ins->opcode = OP_STOREV_MEMBASE;
5636                 } else if (sp [1]->opcode == OP_ICONST) {
5637                         int array_reg = sp [0]->dreg;
5638                         int index_reg = sp [1]->dreg;
5639                         int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
5640
5641                         if (safety_checks)
5642                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
5643                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset, sp [2]->dreg);
5644                 } else {
5645                         MonoInst *addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], safety_checks);
5646                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5647                         if (generic_class_is_reference_type (cfg, klass))
5648                                 emit_write_barrier (cfg, addr, sp [2]);
5649                 }
5650                 return ins;
5651         }
5652 }
5653
5654 static MonoInst*
5655 emit_array_unsafe_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
5656 {
5657         MonoClass *eklass;
5658         
5659         if (is_set)
5660                 eklass = mono_class_from_mono_type (fsig->params [2]);
5661         else
5662                 eklass = mono_class_from_mono_type (fsig->ret);
5663
5664         if (is_set) {
5665                 return emit_array_store (cfg, eklass, args, FALSE);
5666         } else {
5667                 MonoInst *ins, *addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
5668                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &eklass->byval_arg, addr->dreg, 0);
5669                 return ins;
5670         }
5671 }
5672
5673 static gboolean
5674 is_unsafe_mov_compatible (MonoCompile *cfg, MonoClass *param_klass, MonoClass *return_klass)
5675 {
5676         uint32_t align;
5677         int param_size, return_size;
5678
5679         param_klass = mono_class_from_mono_type (mini_get_underlying_type (&param_klass->byval_arg));
5680         return_klass = mono_class_from_mono_type (mini_get_underlying_type (&return_klass->byval_arg));
5681
5682         if (cfg->verbose_level > 3)
5683                 printf ("[UNSAFE-MOV-INTRISIC] %s <- %s\n", return_klass->name, param_klass->name);
5684
5685         //Don't allow mixing reference types with value types
5686         if (param_klass->valuetype != return_klass->valuetype) {
5687                 if (cfg->verbose_level > 3)
5688                         printf ("[UNSAFE-MOV-INTRISIC]\tone of the args is a valuetype and the other is not\n");
5689                 return FALSE;
5690         }
5691
5692         if (!param_klass->valuetype) {
5693                 if (cfg->verbose_level > 3)
5694                         printf ("[UNSAFE-MOV-INTRISIC]\targs are reference types\n");
5695                 return TRUE;
5696         }
5697
5698         //That are blitable
5699         if (param_klass->has_references || return_klass->has_references)
5700                 return FALSE;
5701
5702         /* Avoid mixing structs and primitive types/enums, they need to be handled differently in the JIT */
5703         if ((MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && !MONO_TYPE_ISSTRUCT (&return_klass->byval_arg)) ||
5704                 (!MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && MONO_TYPE_ISSTRUCT (&return_klass->byval_arg))) {
5705                         if (cfg->verbose_level > 3)
5706                                 printf ("[UNSAFE-MOV-INTRISIC]\tmixing structs and scalars\n");
5707                 return FALSE;
5708         }
5709
5710         if (param_klass->byval_arg.type == MONO_TYPE_R4 || param_klass->byval_arg.type == MONO_TYPE_R8 ||
5711                 return_klass->byval_arg.type == MONO_TYPE_R4 || return_klass->byval_arg.type == MONO_TYPE_R8) {
5712                 if (cfg->verbose_level > 3)
5713                         printf ("[UNSAFE-MOV-INTRISIC]\tfloat or double are not supported\n");
5714                 return FALSE;
5715         }
5716
5717         param_size = mono_class_value_size (param_klass, &align);
5718         return_size = mono_class_value_size (return_klass, &align);
5719
5720         //We can do it if sizes match
5721         if (param_size == return_size) {
5722                 if (cfg->verbose_level > 3)
5723                         printf ("[UNSAFE-MOV-INTRISIC]\tsame size\n");
5724                 return TRUE;
5725         }
5726
5727         //No simple way to handle struct if sizes don't match
5728         if (MONO_TYPE_ISSTRUCT (&param_klass->byval_arg)) {
5729                 if (cfg->verbose_level > 3)
5730                         printf ("[UNSAFE-MOV-INTRISIC]\tsize mismatch and type is a struct\n");
5731                 return FALSE;
5732         }
5733
5734         /*
5735          * Same reg size category.
5736          * A quick note on why we don't require widening here.
5737          * The intrinsic is "R Array.UnsafeMov<S,R> (S s)".
5738          *
5739          * Since the source value comes from a function argument, the JIT will already have
5740          * the value in a VREG and performed any widening needed before (say, when loading from a field).
5741          */
5742         if (param_size <= 4 && return_size <= 4) {
5743                 if (cfg->verbose_level > 3)
5744                         printf ("[UNSAFE-MOV-INTRISIC]\tsize mismatch but both are of the same reg class\n");
5745                 return TRUE;
5746         }
5747
5748         return FALSE;
5749 }
5750
5751 static MonoInst*
5752 emit_array_unsafe_mov (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args)
5753 {
5754         MonoClass *param_klass = mono_class_from_mono_type (fsig->params [0]);
5755         MonoClass *return_klass = mono_class_from_mono_type (fsig->ret);
5756
5757         //Valuetypes that are semantically equivalent or numbers than can be widened to
5758         if (is_unsafe_mov_compatible (cfg, param_klass, return_klass))
5759                 return args [0];
5760
5761         //Arrays of valuetypes that are semantically equivalent
5762         if (param_klass->rank == 1 && return_klass->rank == 1 && is_unsafe_mov_compatible (cfg, param_klass->element_class, return_klass->element_class))
5763                 return args [0];
5764
5765         return NULL;
5766 }
5767
5768 static MonoInst*
5769 mini_emit_inst_for_ctor (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5770 {
5771 #ifdef MONO_ARCH_SIMD_INTRINSICS
5772         MonoInst *ins = NULL;
5773
5774         if (cfg->opt & MONO_OPT_SIMD) {
5775                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
5776                 if (ins)
5777                         return ins;
5778         }
5779 #endif
5780
5781         return mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
5782 }
5783
5784 static MonoInst*
5785 emit_memory_barrier (MonoCompile *cfg, int kind)
5786 {
5787         MonoInst *ins = NULL;
5788         MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
5789         MONO_ADD_INS (cfg->cbb, ins);
5790         ins->backend.memory_barrier_kind = kind;
5791
5792         return ins;
5793 }
5794
5795 static MonoInst*
5796 llvm_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5797 {
5798         MonoInst *ins = NULL;
5799         int opcode = 0;
5800
5801         /* The LLVM backend supports these intrinsics */
5802         if (cmethod->klass == mono_defaults.math_class) {
5803                 if (strcmp (cmethod->name, "Sin") == 0) {
5804                         opcode = OP_SIN;
5805                 } else if (strcmp (cmethod->name, "Cos") == 0) {
5806                         opcode = OP_COS;
5807                 } else if (strcmp (cmethod->name, "Sqrt") == 0) {
5808                         opcode = OP_SQRT;
5809                 } else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8) {
5810                         opcode = OP_ABS;
5811                 }
5812
5813                 if (opcode && fsig->param_count == 1) {
5814                         MONO_INST_NEW (cfg, ins, opcode);
5815                         ins->type = STACK_R8;
5816                         ins->dreg = mono_alloc_freg (cfg);
5817                         ins->sreg1 = args [0]->dreg;
5818                         MONO_ADD_INS (cfg->cbb, ins);
5819                 }
5820
5821                 opcode = 0;
5822                 if (cfg->opt & MONO_OPT_CMOV) {
5823                         if (strcmp (cmethod->name, "Min") == 0) {
5824                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5825                                         opcode = OP_IMIN;
5826                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5827                                         opcode = OP_IMIN_UN;
5828                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5829                                         opcode = OP_LMIN;
5830                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5831                                         opcode = OP_LMIN_UN;
5832                         } else if (strcmp (cmethod->name, "Max") == 0) {
5833                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5834                                         opcode = OP_IMAX;
5835                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5836                                         opcode = OP_IMAX_UN;
5837                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5838                                         opcode = OP_LMAX;
5839                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5840                                         opcode = OP_LMAX_UN;
5841                         }
5842                 }
5843
5844                 if (opcode && fsig->param_count == 2) {
5845                         MONO_INST_NEW (cfg, ins, opcode);
5846                         ins->type = fsig->params [0]->type == MONO_TYPE_I4 ? STACK_I4 : STACK_I8;
5847                         ins->dreg = mono_alloc_ireg (cfg);
5848                         ins->sreg1 = args [0]->dreg;
5849                         ins->sreg2 = args [1]->dreg;
5850                         MONO_ADD_INS (cfg->cbb, ins);
5851                 }
5852         }
5853
5854         return ins;
5855 }
5856
5857 static MonoInst*
5858 mini_emit_inst_for_sharable_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5859 {
5860         if (cmethod->klass == mono_defaults.array_class) {
5861                 if (strcmp (cmethod->name, "UnsafeStore") == 0)
5862                         return emit_array_unsafe_access (cfg, fsig, args, TRUE);
5863                 else if (strcmp (cmethod->name, "UnsafeLoad") == 0)
5864                         return emit_array_unsafe_access (cfg, fsig, args, FALSE);
5865                 else if (strcmp (cmethod->name, "UnsafeMov") == 0)
5866                         return emit_array_unsafe_mov (cfg, fsig, args);
5867         }
5868
5869         return NULL;
5870 }
5871
5872 static MonoInst*
5873 mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5874 {
5875         MonoInst *ins = NULL;
5876
5877         static MonoClass *runtime_helpers_class = NULL;
5878         if (! runtime_helpers_class)
5879                 runtime_helpers_class = mono_class_from_name (mono_defaults.corlib,
5880                         "System.Runtime.CompilerServices", "RuntimeHelpers");
5881
5882         if (cmethod->klass == mono_defaults.string_class) {
5883                 if (strcmp (cmethod->name, "get_Chars") == 0 && fsig->param_count + fsig->hasthis == 2) {
5884                         int dreg = alloc_ireg (cfg);
5885                         int index_reg = alloc_preg (cfg);
5886                         int add_reg = alloc_preg (cfg);
5887
5888 #if SIZEOF_REGISTER == 8
5889                         /* The array reg is 64 bits but the index reg is only 32 */
5890                         MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index_reg, args [1]->dreg);
5891 #else
5892                         index_reg = args [1]->dreg;
5893 #endif  
5894                         MONO_EMIT_BOUNDS_CHECK (cfg, args [0]->dreg, MonoString, length, index_reg);
5895
5896 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5897                         EMIT_NEW_X86_LEA (cfg, ins, args [0]->dreg, index_reg, 1, MONO_STRUCT_OFFSET (MonoString, chars));
5898                         add_reg = ins->dreg;
5899                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5900                                                                    add_reg, 0);
5901 #else
5902                         int mult_reg = alloc_preg (cfg);
5903                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, index_reg, 1);
5904                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
5905                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5906                                                                    add_reg, MONO_STRUCT_OFFSET (MonoString, chars));
5907 #endif
5908                         type_from_op (cfg, ins, NULL, NULL);
5909                         return ins;
5910                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count + fsig->hasthis == 1) {
5911                         int dreg = alloc_ireg (cfg);
5912                         /* Decompose later to allow more optimizations */
5913                         EMIT_NEW_UNALU (cfg, ins, OP_STRLEN, dreg, args [0]->dreg);
5914                         ins->type = STACK_I4;
5915                         ins->flags |= MONO_INST_FAULT;
5916                         cfg->cbb->has_array_access = TRUE;
5917                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
5918
5919                         return ins;
5920                 } else 
5921                         return NULL;
5922         } else if (cmethod->klass == mono_defaults.object_class) {
5923
5924                 if (strcmp (cmethod->name, "GetType") == 0 && fsig->param_count + fsig->hasthis == 1) {
5925                         int dreg = alloc_ireg_ref (cfg);
5926                         int vt_reg = alloc_preg (cfg);
5927                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vt_reg, args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
5928                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, vt_reg, MONO_STRUCT_OFFSET (MonoVTable, type));
5929                         type_from_op (cfg, ins, NULL, NULL);
5930
5931                         return ins;
5932                 } else if (!cfg->backend->emulate_mul_div && strcmp (cmethod->name, "InternalGetHashCode") == 0 && fsig->param_count == 1 && !mono_gc_is_moving ()) {
5933                         int dreg = alloc_ireg (cfg);
5934                         int t1 = alloc_ireg (cfg);
5935         
5936                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, t1, args [0]->dreg, 3);
5937                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_MUL_IMM, dreg, t1, 2654435761u);
5938                         ins->type = STACK_I4;
5939
5940                         return ins;
5941                 } else if (strcmp (cmethod->name, ".ctor") == 0 && fsig->param_count == 0) {
5942                         MONO_INST_NEW (cfg, ins, OP_NOP);
5943                         MONO_ADD_INS (cfg->cbb, ins);
5944                         return ins;
5945                 } else
5946                         return NULL;
5947         } else if (cmethod->klass == mono_defaults.array_class) {
5948                 if (strcmp (cmethod->name, "GetGenericValueImpl") == 0 && fsig->param_count + fsig->hasthis == 3 && !cfg->gsharedvt)
5949                         return emit_array_generic_access (cfg, fsig, args, FALSE);
5950                 else if (strcmp (cmethod->name, "SetGenericValueImpl") == 0 && fsig->param_count + fsig->hasthis == 3 && !cfg->gsharedvt)
5951                         return emit_array_generic_access (cfg, fsig, args, TRUE);
5952
5953 #ifndef MONO_BIG_ARRAYS
5954                 /*
5955                  * This is an inline version of GetLength/GetLowerBound(0) used frequently in
5956                  * Array methods.
5957                  */
5958                 else if (((strcmp (cmethod->name, "GetLength") == 0 && fsig->param_count + fsig->hasthis == 2) ||
5959                          (strcmp (cmethod->name, "GetLowerBound") == 0 && fsig->param_count + fsig->hasthis == 2)) &&
5960                          args [1]->opcode == OP_ICONST && args [1]->inst_c0 == 0) {
5961                         int dreg = alloc_ireg (cfg);
5962                         int bounds_reg = alloc_ireg_mp (cfg);
5963                         MonoBasicBlock *end_bb, *szarray_bb;
5964                         gboolean get_length = strcmp (cmethod->name, "GetLength") == 0;
5965
5966                         NEW_BBLOCK (cfg, end_bb);
5967                         NEW_BBLOCK (cfg, szarray_bb);
5968
5969                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOAD_MEMBASE, bounds_reg,
5970                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
5971                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
5972                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, szarray_bb);
5973                         /* Non-szarray case */
5974                         if (get_length)
5975                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5976                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5977                         else
5978                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5979                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5980                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
5981                         MONO_START_BB (cfg, szarray_bb);
5982                         /* Szarray case */
5983                         if (get_length)
5984                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5985                                                                            args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
5986                         else
5987                                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
5988                         MONO_START_BB (cfg, end_bb);
5989
5990                         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, dreg, dreg);
5991                         ins->type = STACK_I4;
5992                         
5993                         return ins;
5994                 }
5995 #endif
5996
5997                 if (cmethod->name [0] != 'g')
5998                         return NULL;
5999
6000                 if (strcmp (cmethod->name, "get_Rank") == 0 && fsig->param_count + fsig->hasthis == 1) {
6001                         int dreg = alloc_ireg (cfg);
6002                         int vtable_reg = alloc_preg (cfg);
6003                         MONO_EMIT_NEW_LOAD_MEMBASE_OP_FAULT (cfg, OP_LOAD_MEMBASE, vtable_reg, 
6004                                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
6005                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU1_MEMBASE, dreg,
6006                                                                    vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
6007                         type_from_op (cfg, ins, NULL, NULL);
6008
6009                         return ins;
6010                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count + fsig->hasthis == 1) {
6011                         int dreg = alloc_ireg (cfg);
6012
6013                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOADI4_MEMBASE, dreg, 
6014                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
6015                         type_from_op (cfg, ins, NULL, NULL);
6016
6017                         return ins;
6018                 } else
6019                         return NULL;
6020         } else if (cmethod->klass == runtime_helpers_class) {
6021
6022                 if (strcmp (cmethod->name, "get_OffsetToStringData") == 0 && fsig->param_count == 0) {
6023                         EMIT_NEW_ICONST (cfg, ins, MONO_STRUCT_OFFSET (MonoString, chars));
6024                         return ins;
6025                 } else
6026                         return NULL;
6027         } else if (cmethod->klass == mono_defaults.thread_class) {
6028                 if (strcmp (cmethod->name, "SpinWait_nop") == 0 && fsig->param_count == 0) {
6029                         MONO_INST_NEW (cfg, ins, OP_RELAXED_NOP);
6030                         MONO_ADD_INS (cfg->cbb, ins);
6031                         return ins;
6032                 } else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0) {
6033                         return emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6034                 } else if (!strcmp (cmethod->name, "VolatileRead") && fsig->param_count == 1) {
6035                         guint32 opcode = 0;
6036                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6037
6038                         if (fsig->params [0]->type == MONO_TYPE_I1)
6039                                 opcode = OP_LOADI1_MEMBASE;
6040                         else if (fsig->params [0]->type == MONO_TYPE_U1)
6041                                 opcode = OP_LOADU1_MEMBASE;
6042                         else if (fsig->params [0]->type == MONO_TYPE_I2)
6043                                 opcode = OP_LOADI2_MEMBASE;
6044                         else if (fsig->params [0]->type == MONO_TYPE_U2)
6045                                 opcode = OP_LOADU2_MEMBASE;
6046                         else if (fsig->params [0]->type == MONO_TYPE_I4)
6047                                 opcode = OP_LOADI4_MEMBASE;
6048                         else if (fsig->params [0]->type == MONO_TYPE_U4)
6049                                 opcode = OP_LOADU4_MEMBASE;
6050                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
6051                                 opcode = OP_LOADI8_MEMBASE;
6052                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6053                                 opcode = OP_LOADR4_MEMBASE;
6054                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6055                                 opcode = OP_LOADR8_MEMBASE;
6056                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
6057                                 opcode = OP_LOAD_MEMBASE;
6058
6059                         if (opcode) {
6060                                 MONO_INST_NEW (cfg, ins, opcode);
6061                                 ins->inst_basereg = args [0]->dreg;
6062                                 ins->inst_offset = 0;
6063                                 MONO_ADD_INS (cfg->cbb, ins);
6064
6065                                 switch (fsig->params [0]->type) {
6066                                 case MONO_TYPE_I1:
6067                                 case MONO_TYPE_U1:
6068                                 case MONO_TYPE_I2:
6069                                 case MONO_TYPE_U2:
6070                                 case MONO_TYPE_I4:
6071                                 case MONO_TYPE_U4:
6072                                         ins->dreg = mono_alloc_ireg (cfg);
6073                                         ins->type = STACK_I4;
6074                                         break;
6075                                 case MONO_TYPE_I8:
6076                                 case MONO_TYPE_U8:
6077                                         ins->dreg = mono_alloc_lreg (cfg);
6078                                         ins->type = STACK_I8;
6079                                         break;
6080                                 case MONO_TYPE_I:
6081                                 case MONO_TYPE_U:
6082                                         ins->dreg = mono_alloc_ireg (cfg);
6083 #if SIZEOF_REGISTER == 8
6084                                         ins->type = STACK_I8;
6085 #else
6086                                         ins->type = STACK_I4;
6087 #endif
6088                                         break;
6089                                 case MONO_TYPE_R4:
6090                                 case MONO_TYPE_R8:
6091                                         ins->dreg = mono_alloc_freg (cfg);
6092                                         ins->type = STACK_R8;
6093                                         break;
6094                                 default:
6095                                         g_assert (mini_type_is_reference (fsig->params [0]));
6096                                         ins->dreg = mono_alloc_ireg_ref (cfg);
6097                                         ins->type = STACK_OBJ;
6098                                         break;
6099                                 }
6100
6101                                 if (opcode == OP_LOADI8_MEMBASE)
6102                                         ins = mono_decompose_opcode (cfg, ins);
6103
6104                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
6105
6106                                 return ins;
6107                         }
6108                 } else if (!strcmp (cmethod->name, "VolatileWrite") && fsig->param_count == 2) {
6109                         guint32 opcode = 0;
6110                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6111
6112                         if (fsig->params [0]->type == MONO_TYPE_I1 || fsig->params [0]->type == MONO_TYPE_U1)
6113                                 opcode = OP_STOREI1_MEMBASE_REG;
6114                         else if (fsig->params [0]->type == MONO_TYPE_I2 || fsig->params [0]->type == MONO_TYPE_U2)
6115                                 opcode = OP_STOREI2_MEMBASE_REG;
6116                         else if (fsig->params [0]->type == MONO_TYPE_I4 || fsig->params [0]->type == MONO_TYPE_U4)
6117                                 opcode = OP_STOREI4_MEMBASE_REG;
6118                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
6119                                 opcode = OP_STOREI8_MEMBASE_REG;
6120                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6121                                 opcode = OP_STORER4_MEMBASE_REG;
6122                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6123                                 opcode = OP_STORER8_MEMBASE_REG;
6124                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
6125                                 opcode = OP_STORE_MEMBASE_REG;
6126
6127                         if (opcode) {
6128                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
6129
6130                                 MONO_INST_NEW (cfg, ins, opcode);
6131                                 ins->sreg1 = args [1]->dreg;
6132                                 ins->inst_destbasereg = args [0]->dreg;
6133                                 ins->inst_offset = 0;
6134                                 MONO_ADD_INS (cfg->cbb, ins);
6135
6136                                 if (opcode == OP_STOREI8_MEMBASE_REG)
6137                                         ins = mono_decompose_opcode (cfg, ins);
6138
6139                                 return ins;
6140                         }
6141                 }
6142         } else if (cmethod->klass->image == mono_defaults.corlib &&
6143                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
6144                            (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
6145                 ins = NULL;
6146
6147 #if SIZEOF_REGISTER == 8
6148                 if (!cfg->llvm_only && strcmp (cmethod->name, "Read") == 0 && fsig->param_count == 1 && (fsig->params [0]->type == MONO_TYPE_I8)) {
6149                         if (!cfg->llvm_only && mono_arch_opcode_supported (OP_ATOMIC_LOAD_I8)) {
6150                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_LOAD_I8);
6151                                 ins->dreg = mono_alloc_preg (cfg);
6152                                 ins->sreg1 = args [0]->dreg;
6153                                 ins->type = STACK_I8;
6154                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_SEQ;
6155                                 MONO_ADD_INS (cfg->cbb, ins);
6156                         } else {
6157                                 MonoInst *load_ins;
6158
6159                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6160
6161                                 /* 64 bit reads are already atomic */
6162                                 MONO_INST_NEW (cfg, load_ins, OP_LOADI8_MEMBASE);
6163                                 load_ins->dreg = mono_alloc_preg (cfg);
6164                                 load_ins->inst_basereg = args [0]->dreg;
6165                                 load_ins->inst_offset = 0;
6166                                 load_ins->type = STACK_I8;
6167                                 MONO_ADD_INS (cfg->cbb, load_ins);
6168
6169                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6170
6171                                 ins = load_ins;
6172                         }
6173                 }
6174 #endif
6175
6176                 if (strcmp (cmethod->name, "Increment") == 0 && fsig->param_count == 1) {
6177                         MonoInst *ins_iconst;
6178                         guint32 opcode = 0;
6179
6180                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6181                                 opcode = OP_ATOMIC_ADD_I4;
6182                                 cfg->has_atomic_add_i4 = TRUE;
6183                         }
6184 #if SIZEOF_REGISTER == 8
6185                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6186                                 opcode = OP_ATOMIC_ADD_I8;
6187 #endif
6188                         if (opcode) {
6189                                 if (!mono_arch_opcode_supported (opcode))
6190                                         return NULL;
6191                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
6192                                 ins_iconst->inst_c0 = 1;
6193                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
6194                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
6195
6196                                 MONO_INST_NEW (cfg, ins, opcode);
6197                                 ins->dreg = mono_alloc_ireg (cfg);
6198                                 ins->inst_basereg = args [0]->dreg;
6199                                 ins->inst_offset = 0;
6200                                 ins->sreg2 = ins_iconst->dreg;
6201                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6202                                 MONO_ADD_INS (cfg->cbb, ins);
6203                         }
6204                 } else if (strcmp (cmethod->name, "Decrement") == 0 && fsig->param_count == 1) {
6205                         MonoInst *ins_iconst;
6206                         guint32 opcode = 0;
6207
6208                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6209                                 opcode = OP_ATOMIC_ADD_I4;
6210                                 cfg->has_atomic_add_i4 = TRUE;
6211                         }
6212 #if SIZEOF_REGISTER == 8
6213                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6214                                 opcode = OP_ATOMIC_ADD_I8;
6215 #endif
6216                         if (opcode) {
6217                                 if (!mono_arch_opcode_supported (opcode))
6218                                         return NULL;
6219                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
6220                                 ins_iconst->inst_c0 = -1;
6221                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
6222                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
6223
6224                                 MONO_INST_NEW (cfg, ins, opcode);
6225                                 ins->dreg = mono_alloc_ireg (cfg);
6226                                 ins->inst_basereg = args [0]->dreg;
6227                                 ins->inst_offset = 0;
6228                                 ins->sreg2 = ins_iconst->dreg;
6229                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6230                                 MONO_ADD_INS (cfg->cbb, ins);
6231                         }
6232                 } else if (strcmp (cmethod->name, "Add") == 0 && fsig->param_count == 2) {
6233                         guint32 opcode = 0;
6234
6235                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6236                                 opcode = OP_ATOMIC_ADD_I4;
6237                                 cfg->has_atomic_add_i4 = TRUE;
6238                         }
6239 #if SIZEOF_REGISTER == 8
6240                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6241                                 opcode = OP_ATOMIC_ADD_I8;
6242 #endif
6243                         if (opcode) {
6244                                 if (!mono_arch_opcode_supported (opcode))
6245                                         return NULL;
6246                                 MONO_INST_NEW (cfg, ins, opcode);
6247                                 ins->dreg = mono_alloc_ireg (cfg);
6248                                 ins->inst_basereg = args [0]->dreg;
6249                                 ins->inst_offset = 0;
6250                                 ins->sreg2 = args [1]->dreg;
6251                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6252                                 MONO_ADD_INS (cfg->cbb, ins);
6253                         }
6254                 }
6255                 else if (strcmp (cmethod->name, "Exchange") == 0 && fsig->param_count == 2) {
6256                         MonoInst *f2i = NULL, *i2f;
6257                         guint32 opcode, f2i_opcode, i2f_opcode;
6258                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6259                         gboolean is_float = fsig->params [0]->type == MONO_TYPE_R4 || fsig->params [0]->type == MONO_TYPE_R8;
6260
6261                         if (fsig->params [0]->type == MONO_TYPE_I4 ||
6262                             fsig->params [0]->type == MONO_TYPE_R4) {
6263                                 opcode = OP_ATOMIC_EXCHANGE_I4;
6264                                 f2i_opcode = OP_MOVE_F_TO_I4;
6265                                 i2f_opcode = OP_MOVE_I4_TO_F;
6266                                 cfg->has_atomic_exchange_i4 = TRUE;
6267                         }
6268 #if SIZEOF_REGISTER == 8
6269                         else if (is_ref ||
6270                                  fsig->params [0]->type == MONO_TYPE_I8 ||
6271                                  fsig->params [0]->type == MONO_TYPE_R8 ||
6272                                  fsig->params [0]->type == MONO_TYPE_I) {
6273                                 opcode = OP_ATOMIC_EXCHANGE_I8;
6274                                 f2i_opcode = OP_MOVE_F_TO_I8;
6275                                 i2f_opcode = OP_MOVE_I8_TO_F;
6276                         }
6277 #else
6278                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I) {
6279                                 opcode = OP_ATOMIC_EXCHANGE_I4;
6280                                 cfg->has_atomic_exchange_i4 = TRUE;
6281                         }
6282 #endif
6283                         else
6284                                 return NULL;
6285
6286                         if (!mono_arch_opcode_supported (opcode))
6287                                 return NULL;
6288
6289                         if (is_float) {
6290                                 /* TODO: Decompose these opcodes instead of bailing here. */
6291                                 if (COMPILE_SOFT_FLOAT (cfg))
6292                                         return NULL;
6293
6294                                 MONO_INST_NEW (cfg, f2i, f2i_opcode);
6295                                 f2i->dreg = mono_alloc_ireg (cfg);
6296                                 f2i->sreg1 = args [1]->dreg;
6297                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6298                                         f2i->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6299                                 MONO_ADD_INS (cfg->cbb, f2i);
6300                         }
6301
6302                         MONO_INST_NEW (cfg, ins, opcode);
6303                         ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : mono_alloc_ireg (cfg);
6304                         ins->inst_basereg = args [0]->dreg;
6305                         ins->inst_offset = 0;
6306                         ins->sreg2 = is_float ? f2i->dreg : args [1]->dreg;
6307                         MONO_ADD_INS (cfg->cbb, ins);
6308
6309                         switch (fsig->params [0]->type) {
6310                         case MONO_TYPE_I4:
6311                                 ins->type = STACK_I4;
6312                                 break;
6313                         case MONO_TYPE_I8:
6314                                 ins->type = STACK_I8;
6315                                 break;
6316                         case MONO_TYPE_I:
6317 #if SIZEOF_REGISTER == 8
6318                                 ins->type = STACK_I8;
6319 #else
6320                                 ins->type = STACK_I4;
6321 #endif
6322                                 break;
6323                         case MONO_TYPE_R4:
6324                         case MONO_TYPE_R8:
6325                                 ins->type = STACK_R8;
6326                                 break;
6327                         default:
6328                                 g_assert (mini_type_is_reference (fsig->params [0]));
6329                                 ins->type = STACK_OBJ;
6330                                 break;
6331                         }
6332
6333                         if (is_float) {
6334                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
6335                                 i2f->dreg = mono_alloc_freg (cfg);
6336                                 i2f->sreg1 = ins->dreg;
6337                                 i2f->type = STACK_R8;
6338                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
6339                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6340                                 MONO_ADD_INS (cfg->cbb, i2f);
6341
6342                                 ins = i2f;
6343                         }
6344
6345                         if (cfg->gen_write_barriers && is_ref)
6346                                 emit_write_barrier (cfg, args [0], args [1]);
6347                 }
6348                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 3) {
6349                         MonoInst *f2i_new = NULL, *f2i_cmp = NULL, *i2f;
6350                         guint32 opcode, f2i_opcode, i2f_opcode;
6351                         gboolean is_ref = mini_type_is_reference (fsig->params [1]);
6352                         gboolean is_float = fsig->params [1]->type == MONO_TYPE_R4 || fsig->params [1]->type == MONO_TYPE_R8;
6353
6354                         if (fsig->params [1]->type == MONO_TYPE_I4 ||
6355                             fsig->params [1]->type == MONO_TYPE_R4) {
6356                                 opcode = OP_ATOMIC_CAS_I4;
6357                                 f2i_opcode = OP_MOVE_F_TO_I4;
6358                                 i2f_opcode = OP_MOVE_I4_TO_F;
6359                                 cfg->has_atomic_cas_i4 = TRUE;
6360                         }
6361 #if SIZEOF_REGISTER == 8
6362                         else if (is_ref ||
6363                                  fsig->params [1]->type == MONO_TYPE_I8 ||
6364                                  fsig->params [1]->type == MONO_TYPE_R8 ||
6365                                  fsig->params [1]->type == MONO_TYPE_I) {
6366                                 opcode = OP_ATOMIC_CAS_I8;
6367                                 f2i_opcode = OP_MOVE_F_TO_I8;
6368                                 i2f_opcode = OP_MOVE_I8_TO_F;
6369                         }
6370 #else
6371                         else if (is_ref || fsig->params [1]->type == MONO_TYPE_I) {
6372                                 opcode = OP_ATOMIC_CAS_I4;
6373                                 cfg->has_atomic_cas_i4 = TRUE;
6374                         }
6375 #endif
6376                         else
6377                                 return NULL;
6378
6379                         if (!mono_arch_opcode_supported (opcode))
6380                                 return NULL;
6381
6382                         if (is_float) {
6383                                 /* TODO: Decompose these opcodes instead of bailing here. */
6384                                 if (COMPILE_SOFT_FLOAT (cfg))
6385                                         return NULL;
6386
6387                                 MONO_INST_NEW (cfg, f2i_new, f2i_opcode);
6388                                 f2i_new->dreg = mono_alloc_ireg (cfg);
6389                                 f2i_new->sreg1 = args [1]->dreg;
6390                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6391                                         f2i_new->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6392                                 MONO_ADD_INS (cfg->cbb, f2i_new);
6393
6394                                 MONO_INST_NEW (cfg, f2i_cmp, f2i_opcode);
6395                                 f2i_cmp->dreg = mono_alloc_ireg (cfg);
6396                                 f2i_cmp->sreg1 = args [2]->dreg;
6397                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6398                                         f2i_cmp->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6399                                 MONO_ADD_INS (cfg->cbb, f2i_cmp);
6400                         }
6401
6402                         MONO_INST_NEW (cfg, ins, opcode);
6403                         ins->dreg = is_ref ? alloc_ireg_ref (cfg) : alloc_ireg (cfg);
6404                         ins->sreg1 = args [0]->dreg;
6405                         ins->sreg2 = is_float ? f2i_new->dreg : args [1]->dreg;
6406                         ins->sreg3 = is_float ? f2i_cmp->dreg : args [2]->dreg;
6407                         MONO_ADD_INS (cfg->cbb, ins);
6408
6409                         switch (fsig->params [1]->type) {
6410                         case MONO_TYPE_I4:
6411                                 ins->type = STACK_I4;
6412                                 break;
6413                         case MONO_TYPE_I8:
6414                                 ins->type = STACK_I8;
6415                                 break;
6416                         case MONO_TYPE_I:
6417 #if SIZEOF_REGISTER == 8
6418                                 ins->type = STACK_I8;
6419 #else
6420                                 ins->type = STACK_I4;
6421 #endif
6422                                 break;
6423                         case MONO_TYPE_R4:
6424                                 ins->type = cfg->r4_stack_type;
6425                                 break;
6426                         case MONO_TYPE_R8:
6427                                 ins->type = STACK_R8;
6428                                 break;
6429                         default:
6430                                 g_assert (mini_type_is_reference (fsig->params [1]));
6431                                 ins->type = STACK_OBJ;
6432                                 break;
6433                         }
6434
6435                         if (is_float) {
6436                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
6437                                 i2f->dreg = mono_alloc_freg (cfg);
6438                                 i2f->sreg1 = ins->dreg;
6439                                 i2f->type = STACK_R8;
6440                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
6441                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6442                                 MONO_ADD_INS (cfg->cbb, i2f);
6443
6444                                 ins = i2f;
6445                         }
6446
6447                         if (cfg->gen_write_barriers && is_ref)
6448                                 emit_write_barrier (cfg, args [0], args [1]);
6449                 }
6450                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 4 &&
6451                          fsig->params [1]->type == MONO_TYPE_I4) {
6452                         MonoInst *cmp, *ceq;
6453
6454                         if (!mono_arch_opcode_supported (OP_ATOMIC_CAS_I4))
6455                                 return NULL;
6456
6457                         /* int32 r = CAS (location, value, comparand); */
6458                         MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I4);
6459                         ins->dreg = alloc_ireg (cfg);
6460                         ins->sreg1 = args [0]->dreg;
6461                         ins->sreg2 = args [1]->dreg;
6462                         ins->sreg3 = args [2]->dreg;
6463                         ins->type = STACK_I4;
6464                         MONO_ADD_INS (cfg->cbb, ins);
6465
6466                         /* bool result = r == comparand; */
6467                         MONO_INST_NEW (cfg, cmp, OP_ICOMPARE);
6468                         cmp->sreg1 = ins->dreg;
6469                         cmp->sreg2 = args [2]->dreg;
6470                         cmp->type = STACK_I4;
6471                         MONO_ADD_INS (cfg->cbb, cmp);
6472
6473                         MONO_INST_NEW (cfg, ceq, OP_ICEQ);
6474                         ceq->dreg = alloc_ireg (cfg);
6475                         ceq->type = STACK_I4;
6476                         MONO_ADD_INS (cfg->cbb, ceq);
6477
6478                         /* *success = result; */
6479                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, args [3]->dreg, 0, ceq->dreg);
6480
6481                         cfg->has_atomic_cas_i4 = TRUE;
6482                 }
6483                 else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0)
6484                         ins = emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6485
6486                 if (ins)
6487                         return ins;
6488         } else if (cmethod->klass->image == mono_defaults.corlib &&
6489                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
6490                            (strcmp (cmethod->klass->name, "Volatile") == 0)) {
6491                 ins = NULL;
6492
6493                 if (!cfg->llvm_only && !strcmp (cmethod->name, "Read") && fsig->param_count == 1) {
6494                         guint32 opcode = 0;
6495                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6496                         gboolean is_float = fsig->params [0]->type == MONO_TYPE_R4 || fsig->params [0]->type == MONO_TYPE_R8;
6497
6498                         if (fsig->params [0]->type == MONO_TYPE_I1)
6499                                 opcode = OP_ATOMIC_LOAD_I1;
6500                         else if (fsig->params [0]->type == MONO_TYPE_U1 || fsig->params [0]->type == MONO_TYPE_BOOLEAN)
6501                                 opcode = OP_ATOMIC_LOAD_U1;
6502                         else if (fsig->params [0]->type == MONO_TYPE_I2)
6503                                 opcode = OP_ATOMIC_LOAD_I2;
6504                         else if (fsig->params [0]->type == MONO_TYPE_U2)
6505                                 opcode = OP_ATOMIC_LOAD_U2;
6506                         else if (fsig->params [0]->type == MONO_TYPE_I4)
6507                                 opcode = OP_ATOMIC_LOAD_I4;
6508                         else if (fsig->params [0]->type == MONO_TYPE_U4)
6509                                 opcode = OP_ATOMIC_LOAD_U4;
6510                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6511                                 opcode = OP_ATOMIC_LOAD_R4;
6512                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6513                                 opcode = OP_ATOMIC_LOAD_R8;
6514 #if SIZEOF_REGISTER == 8
6515                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_I)
6516                                 opcode = OP_ATOMIC_LOAD_I8;
6517                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_U8 || fsig->params [0]->type == MONO_TYPE_U)
6518                                 opcode = OP_ATOMIC_LOAD_U8;
6519 #else
6520                         else if (fsig->params [0]->type == MONO_TYPE_I)
6521                                 opcode = OP_ATOMIC_LOAD_I4;
6522                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_U)
6523                                 opcode = OP_ATOMIC_LOAD_U4;
6524 #endif
6525
6526                         if (opcode) {
6527                                 if (!mono_arch_opcode_supported (opcode))
6528                                         return NULL;
6529
6530                                 MONO_INST_NEW (cfg, ins, opcode);
6531                                 ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : (is_float ? mono_alloc_freg (cfg) : mono_alloc_ireg (cfg));
6532                                 ins->sreg1 = args [0]->dreg;
6533                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_ACQ;
6534                                 MONO_ADD_INS (cfg->cbb, ins);
6535
6536                                 switch (fsig->params [0]->type) {
6537                                 case MONO_TYPE_BOOLEAN:
6538                                 case MONO_TYPE_I1:
6539                                 case MONO_TYPE_U1:
6540                                 case MONO_TYPE_I2:
6541                                 case MONO_TYPE_U2:
6542                                 case MONO_TYPE_I4:
6543                                 case MONO_TYPE_U4:
6544                                         ins->type = STACK_I4;
6545                                         break;
6546                                 case MONO_TYPE_I8:
6547                                 case MONO_TYPE_U8:
6548                                         ins->type = STACK_I8;
6549                                         break;
6550                                 case MONO_TYPE_I:
6551                                 case MONO_TYPE_U:
6552 #if SIZEOF_REGISTER == 8
6553                                         ins->type = STACK_I8;
6554 #else
6555                                         ins->type = STACK_I4;
6556 #endif
6557                                         break;
6558                                 case MONO_TYPE_R4:
6559                                         ins->type = cfg->r4_stack_type;
6560                                         break;
6561                                 case MONO_TYPE_R8:
6562                                         ins->type = STACK_R8;
6563                                         break;
6564                                 default:
6565                                         g_assert (mini_type_is_reference (fsig->params [0]));
6566                                         ins->type = STACK_OBJ;
6567                                         break;
6568                                 }
6569                         }
6570                 }
6571
6572                 if (!cfg->llvm_only && !strcmp (cmethod->name, "Write") && fsig->param_count == 2) {
6573                         guint32 opcode = 0;
6574                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6575
6576                         if (fsig->params [0]->type == MONO_TYPE_I1)
6577                                 opcode = OP_ATOMIC_STORE_I1;
6578                         else if (fsig->params [0]->type == MONO_TYPE_U1 || fsig->params [0]->type == MONO_TYPE_BOOLEAN)
6579                                 opcode = OP_ATOMIC_STORE_U1;
6580                         else if (fsig->params [0]->type == MONO_TYPE_I2)
6581                                 opcode = OP_ATOMIC_STORE_I2;
6582                         else if (fsig->params [0]->type == MONO_TYPE_U2)
6583                                 opcode = OP_ATOMIC_STORE_U2;
6584                         else if (fsig->params [0]->type == MONO_TYPE_I4)
6585                                 opcode = OP_ATOMIC_STORE_I4;
6586                         else if (fsig->params [0]->type == MONO_TYPE_U4)
6587                                 opcode = OP_ATOMIC_STORE_U4;
6588                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6589                                 opcode = OP_ATOMIC_STORE_R4;
6590                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6591                                 opcode = OP_ATOMIC_STORE_R8;
6592 #if SIZEOF_REGISTER == 8
6593                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_I)
6594                                 opcode = OP_ATOMIC_STORE_I8;
6595                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_U8 || fsig->params [0]->type == MONO_TYPE_U)
6596                                 opcode = OP_ATOMIC_STORE_U8;
6597 #else
6598                         else if (fsig->params [0]->type == MONO_TYPE_I)
6599                                 opcode = OP_ATOMIC_STORE_I4;
6600                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_U)
6601                                 opcode = OP_ATOMIC_STORE_U4;
6602 #endif
6603
6604                         if (opcode) {
6605                                 if (!mono_arch_opcode_supported (opcode))
6606                                         return NULL;
6607
6608                                 MONO_INST_NEW (cfg, ins, opcode);
6609                                 ins->dreg = args [0]->dreg;
6610                                 ins->sreg1 = args [1]->dreg;
6611                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_REL;
6612                                 MONO_ADD_INS (cfg->cbb, ins);
6613
6614                                 if (cfg->gen_write_barriers && is_ref)
6615                                         emit_write_barrier (cfg, args [0], args [1]);
6616                         }
6617                 }
6618
6619                 if (ins)
6620                         return ins;
6621         } else if (cmethod->klass->image == mono_defaults.corlib &&
6622                            (strcmp (cmethod->klass->name_space, "System.Diagnostics") == 0) &&
6623                            (strcmp (cmethod->klass->name, "Debugger") == 0)) {
6624                 if (!strcmp (cmethod->name, "Break") && fsig->param_count == 0) {
6625                         if (should_insert_brekpoint (cfg->method)) {
6626                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
6627                         } else {
6628                                 MONO_INST_NEW (cfg, ins, OP_NOP);
6629                                 MONO_ADD_INS (cfg->cbb, ins);
6630                         }
6631                         return ins;
6632                 }
6633         } else if (cmethod->klass->image == mono_defaults.corlib &&
6634                    (strcmp (cmethod->klass->name_space, "System") == 0) &&
6635                    (strcmp (cmethod->klass->name, "Environment") == 0)) {
6636                 if (!strcmp (cmethod->name, "get_IsRunningOnWindows") && fsig->param_count == 0) {
6637 #ifdef TARGET_WIN32
6638                         EMIT_NEW_ICONST (cfg, ins, 1);
6639 #else
6640                         EMIT_NEW_ICONST (cfg, ins, 0);
6641 #endif
6642                 }
6643         } else if (cmethod->klass->image == mono_defaults.corlib &&
6644                            (strcmp (cmethod->klass->name_space, "System.Reflection") == 0) &&
6645                            (strcmp (cmethod->klass->name, "Assembly") == 0)) {
6646                 if (cfg->llvm_only && !strcmp (cmethod->name, "GetExecutingAssembly")) {
6647                         /* No stack walks are current available, so implement this as an intrinsic */
6648                         MonoInst *assembly_ins;
6649
6650                         EMIT_NEW_AOTCONST (cfg, assembly_ins, MONO_PATCH_INFO_IMAGE, cfg->method->klass->image);
6651                         ins = mono_emit_jit_icall (cfg, mono_get_assembly_object, &assembly_ins);
6652                         return ins;
6653                 }
6654         } else if (cmethod->klass == mono_defaults.math_class) {
6655                 /* 
6656                  * There is general branchless code for Min/Max, but it does not work for 
6657                  * all inputs:
6658                  * http://everything2.com/?node_id=1051618
6659                  */
6660         } else if (((!strcmp (cmethod->klass->image->assembly->aname.name, "MonoMac") ||
6661                     !strcmp (cmethod->klass->image->assembly->aname.name, "monotouch")) &&
6662                                 !strcmp (cmethod->klass->name_space, "XamCore.ObjCRuntime") &&
6663                                 !strcmp (cmethod->klass->name, "Selector")) ||
6664                            (!strcmp (cmethod->klass->image->assembly->aname.name, "Xamarin.iOS") &&
6665                                 !strcmp (cmethod->klass->name_space, "ObjCRuntime") &&
6666                                 !strcmp (cmethod->klass->name, "Selector"))
6667                            ) {
6668                 if (cfg->backend->have_objc_get_selector &&
6669                         !strcmp (cmethod->name, "GetHandle") && fsig->param_count == 1 &&
6670                     (args [0]->opcode == OP_GOT_ENTRY || args [0]->opcode == OP_AOTCONST) &&
6671                     cfg->compile_aot) {
6672                         MonoInst *pi;
6673                         MonoJumpInfoToken *ji;
6674                         MonoString *s;
6675
6676                         cfg->disable_llvm = TRUE;
6677
6678                         if (args [0]->opcode == OP_GOT_ENTRY) {
6679                                 pi = args [0]->inst_p1;
6680                                 g_assert (pi->opcode == OP_PATCH_INFO);
6681                                 g_assert (GPOINTER_TO_INT (pi->inst_p1) == MONO_PATCH_INFO_LDSTR);
6682                                 ji = pi->inst_p0;
6683                         } else {
6684                                 g_assert (GPOINTER_TO_INT (args [0]->inst_p1) == MONO_PATCH_INFO_LDSTR);
6685                                 ji = args [0]->inst_p0;
6686                         }
6687
6688                         NULLIFY_INS (args [0]);
6689
6690                         // FIXME: Ugly
6691                         s = mono_ldstr (cfg->domain, ji->image, mono_metadata_token_index (ji->token));
6692                         MONO_INST_NEW (cfg, ins, OP_OBJC_GET_SELECTOR);
6693                         ins->dreg = mono_alloc_ireg (cfg);
6694                         // FIXME: Leaks
6695                         ins->inst_p0 = mono_string_to_utf8 (s);
6696                         MONO_ADD_INS (cfg->cbb, ins);
6697                         return ins;
6698                 }
6699         }
6700
6701 #ifdef MONO_ARCH_SIMD_INTRINSICS
6702         if (cfg->opt & MONO_OPT_SIMD) {
6703                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
6704                 if (ins)
6705                         return ins;
6706         }
6707 #endif
6708
6709         ins = mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
6710         if (ins)
6711                 return ins;
6712
6713         if (COMPILE_LLVM (cfg)) {
6714                 ins = llvm_emit_inst_for_method (cfg, cmethod, fsig, args);
6715                 if (ins)
6716                         return ins;
6717         }
6718
6719         return mono_arch_emit_inst_for_method (cfg, cmethod, fsig, args);
6720 }
6721
6722 /*
6723  * This entry point could be used later for arbitrary method
6724  * redirection.
6725  */
6726 inline static MonoInst*
6727 mini_redirect_call (MonoCompile *cfg, MonoMethod *method,  
6728                                         MonoMethodSignature *signature, MonoInst **args, MonoInst *this_ins)
6729 {
6730         if (method->klass == mono_defaults.string_class) {
6731                 /* managed string allocation support */
6732                 if (strcmp (method->name, "InternalAllocateStr") == 0 && !(mono_profiler_events & MONO_PROFILE_ALLOCATIONS) && !(cfg->opt & MONO_OPT_SHARED)) {
6733                         MonoInst *iargs [2];
6734                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
6735                         MonoMethod *managed_alloc = NULL;
6736
6737                         g_assert (vtable); /*Should not fail since it System.String*/
6738 #ifndef MONO_CROSS_COMPILE
6739                         managed_alloc = mono_gc_get_managed_allocator (method->klass, FALSE, FALSE);
6740 #endif
6741                         if (!managed_alloc)
6742                                 return NULL;
6743                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
6744                         iargs [1] = args [0];
6745                         return mono_emit_method_call (cfg, managed_alloc, iargs, this_ins);
6746                 }
6747         }
6748         return NULL;
6749 }
6750
6751 static void
6752 mono_save_args (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **sp)
6753 {
6754         MonoInst *store, *temp;
6755         int i;
6756
6757         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
6758                 MonoType *argtype = (sig->hasthis && (i == 0)) ? type_from_stack_type (*sp) : sig->params [i - sig->hasthis];
6759
6760                 /*
6761                  * FIXME: We should use *args++ = sp [0], but that would mean the arg
6762                  * would be different than the MonoInst's used to represent arguments, and
6763                  * the ldelema implementation can't deal with that.
6764                  * Solution: When ldelema is used on an inline argument, create a var for 
6765                  * it, emit ldelema on that var, and emit the saving code below in
6766                  * inline_method () if needed.
6767                  */
6768                 temp = mono_compile_create_var (cfg, argtype, OP_LOCAL);
6769                 cfg->args [i] = temp;
6770                 /* This uses cfg->args [i] which is set by the preceeding line */
6771                 EMIT_NEW_ARGSTORE (cfg, store, i, *sp);
6772                 store->cil_code = sp [0]->cil_code;
6773                 sp++;
6774         }
6775 }
6776
6777 #define MONO_INLINE_CALLED_LIMITED_METHODS 1
6778 #define MONO_INLINE_CALLER_LIMITED_METHODS 1
6779
6780 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
6781 static gboolean
6782 check_inline_called_method_name_limit (MonoMethod *called_method)
6783 {
6784         int strncmp_result;
6785         static const char *limit = NULL;
6786         
6787         if (limit == NULL) {
6788                 const char *limit_string = g_getenv ("MONO_INLINE_CALLED_METHOD_NAME_LIMIT");
6789
6790                 if (limit_string != NULL)
6791                         limit = limit_string;
6792                 else
6793                         limit = "";
6794         }
6795
6796         if (limit [0] != '\0') {
6797                 char *called_method_name = mono_method_full_name (called_method, TRUE);
6798
6799                 strncmp_result = strncmp (called_method_name, limit, strlen (limit));
6800                 g_free (called_method_name);
6801         
6802                 //return (strncmp_result <= 0);
6803                 return (strncmp_result == 0);
6804         } else {
6805                 return TRUE;
6806         }
6807 }
6808 #endif
6809
6810 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
6811 static gboolean
6812 check_inline_caller_method_name_limit (MonoMethod *caller_method)
6813 {
6814         int strncmp_result;
6815         static const char *limit = NULL;
6816         
6817         if (limit == NULL) {
6818                 const char *limit_string = g_getenv ("MONO_INLINE_CALLER_METHOD_NAME_LIMIT");
6819                 if (limit_string != NULL) {
6820                         limit = limit_string;
6821                 } else {
6822                         limit = "";
6823                 }
6824         }
6825
6826         if (limit [0] != '\0') {
6827                 char *caller_method_name = mono_method_full_name (caller_method, TRUE);
6828
6829                 strncmp_result = strncmp (caller_method_name, limit, strlen (limit));
6830                 g_free (caller_method_name);
6831         
6832                 //return (strncmp_result <= 0);
6833                 return (strncmp_result == 0);
6834         } else {
6835                 return TRUE;
6836         }
6837 }
6838 #endif
6839
6840 static void
6841 emit_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
6842 {
6843         static double r8_0 = 0.0;
6844         static float r4_0 = 0.0;
6845         MonoInst *ins;
6846         int t;
6847
6848         rtype = mini_get_underlying_type (rtype);
6849         t = rtype->type;
6850
6851         if (rtype->byref) {
6852                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
6853         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
6854                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
6855         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
6856                 MONO_EMIT_NEW_I8CONST (cfg, dreg, 0);
6857         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
6858                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
6859                 ins->type = STACK_R4;
6860                 ins->inst_p0 = (void*)&r4_0;
6861                 ins->dreg = dreg;
6862                 MONO_ADD_INS (cfg->cbb, ins);
6863         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
6864                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
6865                 ins->type = STACK_R8;
6866                 ins->inst_p0 = (void*)&r8_0;
6867                 ins->dreg = dreg;
6868                 MONO_ADD_INS (cfg->cbb, ins);
6869         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
6870                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
6871                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
6872         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (rtype)) {
6873                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
6874         } else {
6875                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
6876         }
6877 }
6878
6879 static void
6880 emit_dummy_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
6881 {
6882         int t;
6883
6884         rtype = mini_get_underlying_type (rtype);
6885         t = rtype->type;
6886
6887         if (rtype->byref) {
6888                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_PCONST);
6889         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
6890                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_ICONST);
6891         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
6892                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_I8CONST);
6893         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
6894                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R4CONST);
6895         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
6896                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R8CONST);
6897         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
6898                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
6899                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
6900         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (rtype)) {
6901                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
6902         } else {
6903                 emit_init_rvar (cfg, dreg, rtype);
6904         }
6905 }
6906
6907 /* If INIT is FALSE, emit dummy initialization statements to keep the IR valid */
6908 static void
6909 emit_init_local (MonoCompile *cfg, int local, MonoType *type, gboolean init)
6910 {
6911         MonoInst *var = cfg->locals [local];
6912         if (COMPILE_SOFT_FLOAT (cfg)) {
6913                 MonoInst *store;
6914                 int reg = alloc_dreg (cfg, var->type);
6915                 emit_init_rvar (cfg, reg, type);
6916                 EMIT_NEW_LOCSTORE (cfg, store, local, cfg->cbb->last_ins);
6917         } else {
6918                 if (init)
6919                         emit_init_rvar (cfg, var->dreg, type);
6920                 else
6921                         emit_dummy_init_rvar (cfg, var->dreg, type);
6922         }
6923 }
6924
6925 /*
6926  * inline_method:
6927  *
6928  *   Return the cost of inlining CMETHOD.
6929  */
6930 static int
6931 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
6932                            guchar *ip, guint real_offset, gboolean inline_always)
6933 {
6934         MonoInst *ins, *rvar = NULL;
6935         MonoMethodHeader *cheader;
6936         MonoBasicBlock *ebblock, *sbblock;
6937         int i, costs;
6938         MonoMethod *prev_inlined_method;
6939         MonoInst **prev_locals, **prev_args;
6940         MonoType **prev_arg_types;
6941         guint prev_real_offset;
6942         GHashTable *prev_cbb_hash;
6943         MonoBasicBlock **prev_cil_offset_to_bb;
6944         MonoBasicBlock *prev_cbb;
6945         unsigned char* prev_cil_start;
6946         guint32 prev_cil_offset_to_bb_len;
6947         MonoMethod *prev_current_method;
6948         MonoGenericContext *prev_generic_context;
6949         gboolean ret_var_set, prev_ret_var_set, prev_disable_inline, virtual = FALSE;
6950
6951         g_assert (cfg->exception_type == MONO_EXCEPTION_NONE);
6952
6953 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
6954         if ((! inline_always) && ! check_inline_called_method_name_limit (cmethod))
6955                 return 0;
6956 #endif
6957 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
6958         if ((! inline_always) && ! check_inline_caller_method_name_limit (cfg->method))
6959                 return 0;
6960 #endif
6961
6962         if (!fsig)
6963                 fsig = mono_method_signature (cmethod);
6964
6965         if (cfg->verbose_level > 2)
6966                 printf ("INLINE START %p %s -> %s\n", cmethod,  mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
6967
6968         if (!cmethod->inline_info) {
6969                 cfg->stat_inlineable_methods++;
6970                 cmethod->inline_info = 1;
6971         }
6972
6973         /* allocate local variables */
6974         cheader = mono_method_get_header (cmethod);
6975
6976         if (cheader == NULL || mono_loader_get_last_error ()) {
6977                 MonoLoaderError *error = mono_loader_get_last_error ();
6978
6979                 if (cheader)
6980                         mono_metadata_free_mh (cheader);
6981                 if (inline_always && error)
6982                         mono_cfg_set_exception (cfg, error->exception_type);
6983
6984                 mono_loader_clear_error ();
6985                 return 0;
6986         }
6987
6988         /*Must verify before creating locals as it can cause the JIT to assert.*/
6989         if (mono_compile_is_broken (cfg, cmethod, FALSE)) {
6990                 mono_metadata_free_mh (cheader);
6991                 return 0;
6992         }
6993
6994         /* allocate space to store the return value */
6995         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
6996                 rvar = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
6997         }
6998
6999         prev_locals = cfg->locals;
7000         cfg->locals = mono_mempool_alloc0 (cfg->mempool, cheader->num_locals * sizeof (MonoInst*));     
7001         for (i = 0; i < cheader->num_locals; ++i)
7002                 cfg->locals [i] = mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
7003
7004         /* allocate start and end blocks */
7005         /* This is needed so if the inline is aborted, we can clean up */
7006         NEW_BBLOCK (cfg, sbblock);
7007         sbblock->real_offset = real_offset;
7008
7009         NEW_BBLOCK (cfg, ebblock);
7010         ebblock->block_num = cfg->num_bblocks++;
7011         ebblock->real_offset = real_offset;
7012
7013         prev_args = cfg->args;
7014         prev_arg_types = cfg->arg_types;
7015         prev_inlined_method = cfg->inlined_method;
7016         cfg->inlined_method = cmethod;
7017         cfg->ret_var_set = FALSE;
7018         cfg->inline_depth ++;
7019         prev_real_offset = cfg->real_offset;
7020         prev_cbb_hash = cfg->cbb_hash;
7021         prev_cil_offset_to_bb = cfg->cil_offset_to_bb;
7022         prev_cil_offset_to_bb_len = cfg->cil_offset_to_bb_len;
7023         prev_cil_start = cfg->cil_start;
7024         prev_cbb = cfg->cbb;
7025         prev_current_method = cfg->current_method;
7026         prev_generic_context = cfg->generic_context;
7027         prev_ret_var_set = cfg->ret_var_set;
7028         prev_disable_inline = cfg->disable_inline;
7029
7030         if (ip && *ip == CEE_CALLVIRT && !(cmethod->flags & METHOD_ATTRIBUTE_STATIC))
7031                 virtual = TRUE;
7032
7033         costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, rvar, sp, real_offset, virtual);
7034
7035         ret_var_set = cfg->ret_var_set;
7036
7037         cfg->inlined_method = prev_inlined_method;
7038         cfg->real_offset = prev_real_offset;
7039         cfg->cbb_hash = prev_cbb_hash;
7040         cfg->cil_offset_to_bb = prev_cil_offset_to_bb;
7041         cfg->cil_offset_to_bb_len = prev_cil_offset_to_bb_len;
7042         cfg->cil_start = prev_cil_start;
7043         cfg->locals = prev_locals;
7044         cfg->args = prev_args;
7045         cfg->arg_types = prev_arg_types;
7046         cfg->current_method = prev_current_method;
7047         cfg->generic_context = prev_generic_context;
7048         cfg->ret_var_set = prev_ret_var_set;
7049         cfg->disable_inline = prev_disable_inline;
7050         cfg->inline_depth --;
7051
7052         if ((costs >= 0 && costs < 60) || inline_always || (costs >= 0 && (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))) {
7053                 if (cfg->verbose_level > 2)
7054                         printf ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
7055                 
7056                 cfg->stat_inlined_methods++;
7057
7058                 /* always add some code to avoid block split failures */
7059                 MONO_INST_NEW (cfg, ins, OP_NOP);
7060                 MONO_ADD_INS (prev_cbb, ins);
7061
7062                 prev_cbb->next_bb = sbblock;
7063                 link_bblock (cfg, prev_cbb, sbblock);
7064
7065                 /* 
7066                  * Get rid of the begin and end bblocks if possible to aid local
7067                  * optimizations.
7068                  */
7069                 mono_merge_basic_blocks (cfg, prev_cbb, sbblock);
7070
7071                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] != ebblock))
7072                         mono_merge_basic_blocks (cfg, prev_cbb, prev_cbb->out_bb [0]);
7073
7074                 if ((ebblock->in_count == 1) && ebblock->in_bb [0]->out_count == 1) {
7075                         MonoBasicBlock *prev = ebblock->in_bb [0];
7076                         mono_merge_basic_blocks (cfg, prev, ebblock);
7077                         cfg->cbb = prev;
7078                         if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] == prev)) {
7079                                 mono_merge_basic_blocks (cfg, prev_cbb, prev);
7080                                 cfg->cbb = prev_cbb;
7081                         }
7082                 } else {
7083                         /* 
7084                          * Its possible that the rvar is set in some prev bblock, but not in others.
7085                          * (#1835).
7086                          */
7087                         if (rvar) {
7088                                 MonoBasicBlock *bb;
7089
7090                                 for (i = 0; i < ebblock->in_count; ++i) {
7091                                         bb = ebblock->in_bb [i];
7092
7093                                         if (bb->last_ins && bb->last_ins->opcode == OP_NOT_REACHED) {
7094                                                 cfg->cbb = bb;
7095
7096                                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
7097                                         }
7098                                 }
7099                         }
7100
7101                         cfg->cbb = ebblock;
7102                 }
7103
7104                 if (rvar) {
7105                         /*
7106                          * If the inlined method contains only a throw, then the ret var is not 
7107                          * set, so set it to a dummy value.
7108                          */
7109                         if (!ret_var_set)
7110                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
7111
7112                         EMIT_NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
7113                         *sp++ = ins;
7114                 }
7115                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
7116                 return costs + 1;
7117         } else {
7118                 if (cfg->verbose_level > 2)
7119                         printf ("INLINE ABORTED %s (cost %d)\n", mono_method_full_name (cmethod, TRUE), costs);
7120                 cfg->exception_type = MONO_EXCEPTION_NONE;
7121                 mono_loader_clear_error ();
7122
7123                 /* This gets rid of the newly added bblocks */
7124                 cfg->cbb = prev_cbb;
7125         }
7126         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
7127         return 0;
7128 }
7129
7130 /*
7131  * Some of these comments may well be out-of-date.
7132  * Design decisions: we do a single pass over the IL code (and we do bblock 
7133  * splitting/merging in the few cases when it's required: a back jump to an IL
7134  * address that was not already seen as bblock starting point).
7135  * Code is validated as we go (full verification is still better left to metadata/verify.c).
7136  * Complex operations are decomposed in simpler ones right away. We need to let the 
7137  * arch-specific code peek and poke inside this process somehow (except when the 
7138  * optimizations can take advantage of the full semantic info of coarse opcodes).
7139  * All the opcodes of the form opcode.s are 'normalized' to opcode.
7140  * MonoInst->opcode initially is the IL opcode or some simplification of that 
7141  * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific 
7142  * opcode with value bigger than OP_LAST.
7143  * At this point the IR can be handed over to an interpreter, a dumb code generator
7144  * or to the optimizing code generator that will translate it to SSA form.
7145  *
7146  * Profiling directed optimizations.
7147  * We may compile by default with few or no optimizations and instrument the code
7148  * or the user may indicate what methods to optimize the most either in a config file
7149  * or through repeated runs where the compiler applies offline the optimizations to 
7150  * each method and then decides if it was worth it.
7151  */
7152
7153 #define CHECK_TYPE(ins) if (!(ins)->type) UNVERIFIED
7154 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) UNVERIFIED
7155 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) UNVERIFIED
7156 #define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) UNVERIFIED
7157 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
7158 #define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
7159 #define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
7160 #define CHECK_TYPELOAD(klass) if (!(klass) || (klass)->exception_type) TYPE_LOAD_ERROR ((klass))
7161
7162 /* offset from br.s -> br like opcodes */
7163 #define BIG_BRANCH_OFFSET 13
7164
7165 static gboolean
7166 ip_in_bb (MonoCompile *cfg, MonoBasicBlock *bb, const guint8* ip)
7167 {
7168         MonoBasicBlock *b = cfg->cil_offset_to_bb [ip - cfg->cil_start];
7169
7170         return b == NULL || b == bb;
7171 }
7172
7173 static int
7174 get_basic_blocks (MonoCompile *cfg, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
7175 {
7176         unsigned char *ip = start;
7177         unsigned char *target;
7178         int i;
7179         guint cli_addr;
7180         MonoBasicBlock *bblock;
7181         const MonoOpcode *opcode;
7182
7183         while (ip < end) {
7184                 cli_addr = ip - start;
7185                 i = mono_opcode_value ((const guint8 **)&ip, end);
7186                 if (i < 0)
7187                         UNVERIFIED;
7188                 opcode = &mono_opcodes [i];
7189                 switch (opcode->argument) {
7190                 case MonoInlineNone:
7191                         ip++; 
7192                         break;
7193                 case MonoInlineString:
7194                 case MonoInlineType:
7195                 case MonoInlineField:
7196                 case MonoInlineMethod:
7197                 case MonoInlineTok:
7198                 case MonoInlineSig:
7199                 case MonoShortInlineR:
7200                 case MonoInlineI:
7201                         ip += 5;
7202                         break;
7203                 case MonoInlineVar:
7204                         ip += 3;
7205                         break;
7206                 case MonoShortInlineVar:
7207                 case MonoShortInlineI:
7208                         ip += 2;
7209                         break;
7210                 case MonoShortInlineBrTarget:
7211                         target = start + cli_addr + 2 + (signed char)ip [1];
7212                         GET_BBLOCK (cfg, bblock, target);
7213                         ip += 2;
7214                         if (ip < end)
7215                                 GET_BBLOCK (cfg, bblock, ip);
7216                         break;
7217                 case MonoInlineBrTarget:
7218                         target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
7219                         GET_BBLOCK (cfg, bblock, target);
7220                         ip += 5;
7221                         if (ip < end)
7222                                 GET_BBLOCK (cfg, bblock, ip);
7223                         break;
7224                 case MonoInlineSwitch: {
7225                         guint32 n = read32 (ip + 1);
7226                         guint32 j;
7227                         ip += 5;
7228                         cli_addr += 5 + 4 * n;
7229                         target = start + cli_addr;
7230                         GET_BBLOCK (cfg, bblock, target);
7231                         
7232                         for (j = 0; j < n; ++j) {
7233                                 target = start + cli_addr + (gint32)read32 (ip);
7234                                 GET_BBLOCK (cfg, bblock, target);
7235                                 ip += 4;
7236                         }
7237                         break;
7238                 }
7239                 case MonoInlineR:
7240                 case MonoInlineI8:
7241                         ip += 9;
7242                         break;
7243                 default:
7244                         g_assert_not_reached ();
7245                 }
7246
7247                 if (i == CEE_THROW) {
7248                         unsigned char *bb_start = ip - 1;
7249                         
7250                         /* Find the start of the bblock containing the throw */
7251                         bblock = NULL;
7252                         while ((bb_start >= start) && !bblock) {
7253                                 bblock = cfg->cil_offset_to_bb [(bb_start) - start];
7254                                 bb_start --;
7255                         }
7256                         if (bblock)
7257                                 bblock->out_of_line = 1;
7258                 }
7259         }
7260         return 0;
7261 unverified:
7262 exception_exit:
7263         *pos = ip;
7264         return 1;
7265 }
7266
7267 static inline MonoMethod *
7268 mini_get_method_allow_open (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
7269 {
7270         MonoMethod *method;
7271
7272         if (m->wrapper_type != MONO_WRAPPER_NONE) {
7273                 method = mono_method_get_wrapper_data (m, token);
7274                 if (context) {
7275                         MonoError error;
7276                         method = mono_class_inflate_generic_method_checked (method, context, &error);
7277                         g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
7278                 }
7279         } else {
7280                 method = mono_get_method_full (m->klass->image, token, klass, context);
7281         }
7282
7283         return method;
7284 }
7285
7286 static inline MonoMethod *
7287 mini_get_method (MonoCompile *cfg, MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
7288 {
7289         MonoMethod *method = mini_get_method_allow_open (m, token, klass, context);
7290
7291         if (method && cfg && !cfg->gshared && mono_class_is_open_constructed_type (&method->klass->byval_arg))
7292                 return NULL;
7293
7294         return method;
7295 }
7296
7297 static inline MonoClass*
7298 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
7299 {
7300         MonoError error;
7301         MonoClass *klass;
7302
7303         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7304                 klass = mono_method_get_wrapper_data (method, token);
7305                 if (context)
7306                         klass = mono_class_inflate_generic_class (klass, context);
7307         } else {
7308                 klass = mono_class_get_and_inflate_typespec_checked (method->klass->image, token, context, &error);
7309                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
7310         }
7311         if (klass)
7312                 mono_class_init (klass);
7313         return klass;
7314 }
7315
7316 static inline MonoMethodSignature*
7317 mini_get_signature (MonoMethod *method, guint32 token, MonoGenericContext *context)
7318 {
7319         MonoMethodSignature *fsig;
7320
7321         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7322                 fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
7323         } else {
7324                 fsig = mono_metadata_parse_signature (method->klass->image, token);
7325         }
7326         if (context) {
7327                 MonoError error;
7328                 fsig = mono_inflate_generic_signature(fsig, context, &error);
7329                 // FIXME:
7330                 g_assert(mono_error_ok(&error));
7331         }
7332         return fsig;
7333 }
7334
7335 static MonoMethod*
7336 throw_exception (void)
7337 {
7338         static MonoMethod *method = NULL;
7339
7340         if (!method) {
7341                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
7342                 method = mono_class_get_method_from_name (secman->securitymanager, "ThrowException", 1);
7343         }
7344         g_assert (method);
7345         return method;
7346 }
7347
7348 static void
7349 emit_throw_exception (MonoCompile *cfg, MonoException *ex)
7350 {
7351         MonoMethod *thrower = throw_exception ();
7352         MonoInst *args [1];
7353
7354         EMIT_NEW_PCONST (cfg, args [0], ex);
7355         mono_emit_method_call (cfg, thrower, args, NULL);
7356 }
7357
7358 /*
7359  * Return the original method is a wrapper is specified. We can only access 
7360  * the custom attributes from the original method.
7361  */
7362 static MonoMethod*
7363 get_original_method (MonoMethod *method)
7364 {
7365         if (method->wrapper_type == MONO_WRAPPER_NONE)
7366                 return method;
7367
7368         /* native code (which is like Critical) can call any managed method XXX FIXME XXX to validate all usages */
7369         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)
7370                 return NULL;
7371
7372         /* in other cases we need to find the original method */
7373         return mono_marshal_method_from_wrapper (method);
7374 }
7375
7376 static void
7377 ensure_method_is_allowed_to_access_field (MonoCompile *cfg, MonoMethod *caller, MonoClassField *field)
7378 {
7379         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
7380         MonoException *ex = mono_security_core_clr_is_field_access_allowed (get_original_method (caller), field);
7381         if (ex)
7382                 emit_throw_exception (cfg, ex);
7383 }
7384
7385 static void
7386 ensure_method_is_allowed_to_call_method (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee)
7387 {
7388         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
7389         MonoException *ex = mono_security_core_clr_is_call_allowed (get_original_method (caller), callee);
7390         if (ex)
7391                 emit_throw_exception (cfg, ex);
7392 }
7393
7394 /*
7395  * Check that the IL instructions at ip are the array initialization
7396  * sequence and return the pointer to the data and the size.
7397  */
7398 static const char*
7399 initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, MonoClass *klass, guint32 len, int *out_size, guint32 *out_field_token)
7400 {
7401         /*
7402          * newarr[System.Int32]
7403          * dup
7404          * ldtoken field valuetype ...
7405          * call void class [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle)
7406          */
7407         if (ip [0] == CEE_DUP && ip [1] == CEE_LDTOKEN && ip [5] == 0x4 && ip [6] == CEE_CALL) {
7408                 MonoError error;
7409                 guint32 token = read32 (ip + 7);
7410                 guint32 field_token = read32 (ip + 2);
7411                 guint32 field_index = field_token & 0xffffff;
7412                 guint32 rva;
7413                 const char *data_ptr;
7414                 int size = 0;
7415                 MonoMethod *cmethod;
7416                 MonoClass *dummy_class;
7417                 MonoClassField *field = mono_field_from_token_checked (method->klass->image, field_token, &dummy_class, NULL, &error);
7418                 int dummy_align;
7419
7420                 if (!field) {
7421                         mono_error_cleanup (&error); /* FIXME don't swallow the error */
7422                         return NULL;
7423                 }
7424
7425                 *out_field_token = field_token;
7426
7427                 cmethod = mini_get_method (NULL, method, token, NULL, NULL);
7428                 if (!cmethod)
7429                         return NULL;
7430                 if (strcmp (cmethod->name, "InitializeArray") || strcmp (cmethod->klass->name, "RuntimeHelpers") || cmethod->klass->image != mono_defaults.corlib)
7431                         return NULL;
7432                 switch (mono_type_get_underlying_type (&klass->byval_arg)->type) {
7433                 case MONO_TYPE_BOOLEAN:
7434                 case MONO_TYPE_I1:
7435                 case MONO_TYPE_U1:
7436                         size = 1; break;
7437                 /* we need to swap on big endian, so punt. Should we handle R4 and R8 as well? */
7438 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
7439                 case MONO_TYPE_CHAR:
7440                 case MONO_TYPE_I2:
7441                 case MONO_TYPE_U2:
7442                         size = 2; break;
7443                 case MONO_TYPE_I4:
7444                 case MONO_TYPE_U4:
7445                 case MONO_TYPE_R4:
7446                         size = 4; break;
7447                 case MONO_TYPE_R8:
7448                 case MONO_TYPE_I8:
7449                 case MONO_TYPE_U8:
7450                         size = 8; break;
7451 #endif
7452                 default:
7453                         return NULL;
7454                 }
7455                 size *= len;
7456                 if (size > mono_type_size (field->type, &dummy_align))
7457                     return NULL;
7458                 *out_size = size;
7459                 /*g_print ("optimized in %s: size: %d, numelems: %d\n", method->name, size, newarr->inst_newa_len->inst_c0);*/
7460                 if (!image_is_dynamic (method->klass->image)) {
7461                         field_index = read32 (ip + 2) & 0xffffff;
7462                         mono_metadata_field_info (method->klass->image, field_index - 1, NULL, &rva, NULL);
7463                         data_ptr = mono_image_rva_map (method->klass->image, rva);
7464                         /*g_print ("field: 0x%08x, rva: %d, rva_ptr: %p\n", read32 (ip + 2), rva, data_ptr);*/
7465                         /* for aot code we do the lookup on load */
7466                         if (aot && data_ptr)
7467                                 return GUINT_TO_POINTER (rva);
7468                 } else {
7469                         /*FIXME is it possible to AOT a SRE assembly not meant to be saved? */ 
7470                         g_assert (!aot);
7471                         data_ptr = mono_field_get_data (field);
7472                 }
7473                 return data_ptr;
7474         }
7475         return NULL;
7476 }
7477
7478 static void
7479 set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsigned char *ip)
7480 {
7481         char *method_fname = mono_method_full_name (method, TRUE);
7482         char *method_code;
7483         MonoMethodHeader *header = mono_method_get_header (method);
7484
7485         if (header->code_size == 0)
7486                 method_code = g_strdup ("method body is empty.");
7487         else
7488                 method_code = mono_disasm_code_one (NULL, method, ip, NULL);
7489         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
7490         cfg->exception_message = g_strdup_printf ("Invalid IL code in %s: %s\n", method_fname, method_code);
7491         g_free (method_fname);
7492         g_free (method_code);
7493         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
7494 }
7495
7496 static void
7497 set_exception_object (MonoCompile *cfg, MonoException *exception)
7498 {
7499         mono_cfg_set_exception (cfg, MONO_EXCEPTION_OBJECT_SUPPLIED);
7500         MONO_GC_REGISTER_ROOT_SINGLE (cfg->exception_ptr, MONO_ROOT_SOURCE_JIT, "jit exception");
7501         cfg->exception_ptr = exception;
7502 }
7503
7504 static void
7505 emit_stloc_ir (MonoCompile *cfg, MonoInst **sp, MonoMethodHeader *header, int n)
7506 {
7507         MonoInst *ins;
7508         guint32 opcode = mono_type_to_regmove (cfg, header->locals [n]);
7509         if ((opcode == OP_MOVE) && cfg->cbb->last_ins == sp [0]  &&
7510                         ((sp [0]->opcode == OP_ICONST) || (sp [0]->opcode == OP_I8CONST))) {
7511                 /* Optimize reg-reg moves away */
7512                 /* 
7513                  * Can't optimize other opcodes, since sp[0] might point to
7514                  * the last ins of a decomposed opcode.
7515                  */
7516                 sp [0]->dreg = (cfg)->locals [n]->dreg;
7517         } else {
7518                 EMIT_NEW_LOCSTORE (cfg, ins, n, *sp);
7519         }
7520 }
7521
7522 /*
7523  * ldloca inhibits many optimizations so try to get rid of it in common
7524  * cases.
7525  */
7526 static inline unsigned char *
7527 emit_optimized_ldloca_ir (MonoCompile *cfg, unsigned char *ip, unsigned char *end, int size)
7528 {
7529         int local, token;
7530         MonoClass *klass;
7531         MonoType *type;
7532
7533         if (size == 1) {
7534                 local = ip [1];
7535                 ip += 2;
7536         } else {
7537                 local = read16 (ip + 2);
7538                 ip += 4;
7539         }
7540         
7541         if (ip + 6 < end && (ip [0] == CEE_PREFIX1) && (ip [1] == CEE_INITOBJ) && ip_in_bb (cfg, cfg->cbb, ip + 1)) {
7542                 /* From the INITOBJ case */
7543                 token = read32 (ip + 2);
7544                 klass = mini_get_class (cfg->current_method, token, cfg->generic_context);
7545                 CHECK_TYPELOAD (klass);
7546                 type = mini_get_underlying_type (&klass->byval_arg);
7547                 emit_init_local (cfg, local, type, TRUE);
7548                 return ip + 6;
7549         }
7550  exception_exit:
7551         return NULL;
7552 }
7553
7554 static gboolean
7555 is_exception_class (MonoClass *klass)
7556 {
7557         while (klass) {
7558                 if (klass == mono_defaults.exception_class)
7559                         return TRUE;
7560                 klass = klass->parent;
7561         }
7562         return FALSE;
7563 }
7564
7565 /*
7566  * is_jit_optimizer_disabled:
7567  *
7568  *   Determine whenever M's assembly has a DebuggableAttribute with the
7569  * IsJITOptimizerDisabled flag set.
7570  */
7571 static gboolean
7572 is_jit_optimizer_disabled (MonoMethod *m)
7573 {
7574         MonoAssembly *ass = m->klass->image->assembly;
7575         MonoCustomAttrInfo* attrs;
7576         static MonoClass *klass;
7577         int i;
7578         gboolean val = FALSE;
7579
7580         g_assert (ass);
7581         if (ass->jit_optimizer_disabled_inited)
7582                 return ass->jit_optimizer_disabled;
7583
7584         if (!klass)
7585                 klass = mono_class_from_name (mono_defaults.corlib, "System.Diagnostics", "DebuggableAttribute");
7586         if (!klass) {
7587                 /* Linked away */
7588                 ass->jit_optimizer_disabled = FALSE;
7589                 mono_memory_barrier ();
7590                 ass->jit_optimizer_disabled_inited = TRUE;
7591                 return FALSE;
7592         }
7593
7594         attrs = mono_custom_attrs_from_assembly (ass);
7595         if (attrs) {
7596                 for (i = 0; i < attrs->num_attrs; ++i) {
7597                         MonoCustomAttrEntry *attr = &attrs->attrs [i];
7598                         const gchar *p;
7599                         MonoMethodSignature *sig;
7600
7601                         if (!attr->ctor || attr->ctor->klass != klass)
7602                                 continue;
7603                         /* Decode the attribute. See reflection.c */
7604                         p = (const char*)attr->data;
7605                         g_assert (read16 (p) == 0x0001);
7606                         p += 2;
7607
7608                         // FIXME: Support named parameters
7609                         sig = mono_method_signature (attr->ctor);
7610                         if (sig->param_count != 2 || sig->params [0]->type != MONO_TYPE_BOOLEAN || sig->params [1]->type != MONO_TYPE_BOOLEAN)
7611                                 continue;
7612                         /* Two boolean arguments */
7613                         p ++;
7614                         val = *p;
7615                 }
7616                 mono_custom_attrs_free (attrs);
7617         }
7618
7619         ass->jit_optimizer_disabled = val;
7620         mono_memory_barrier ();
7621         ass->jit_optimizer_disabled_inited = TRUE;
7622
7623         return val;
7624 }
7625
7626 static gboolean
7627 is_supported_tail_call (MonoCompile *cfg, MonoMethod *method, MonoMethod *cmethod, MonoMethodSignature *fsig, int call_opcode)
7628 {
7629         gboolean supported_tail_call;
7630         int i;
7631
7632         supported_tail_call = mono_arch_tail_call_supported (cfg, mono_method_signature (method), mono_method_signature (cmethod));
7633
7634         for (i = 0; i < fsig->param_count; ++i) {
7635                 if (fsig->params [i]->byref || fsig->params [i]->type == MONO_TYPE_PTR || fsig->params [i]->type == MONO_TYPE_FNPTR)
7636                         /* These can point to the current method's stack */
7637                         supported_tail_call = FALSE;
7638         }
7639         if (fsig->hasthis && cmethod->klass->valuetype)
7640                 /* this might point to the current method's stack */
7641                 supported_tail_call = FALSE;
7642         if (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
7643                 supported_tail_call = FALSE;
7644         if (cfg->method->save_lmf)
7645                 supported_tail_call = FALSE;
7646         if (cmethod->wrapper_type && cmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD)
7647                 supported_tail_call = FALSE;
7648         if (call_opcode != CEE_CALL)
7649                 supported_tail_call = FALSE;
7650
7651         /* Debugging support */
7652 #if 0
7653         if (supported_tail_call) {
7654                 if (!mono_debug_count ())
7655                         supported_tail_call = FALSE;
7656         }
7657 #endif
7658
7659         return supported_tail_call;
7660 }
7661
7662 /*
7663  * handle_ctor_call:
7664  *
7665  *   Handle calls made to ctors from NEWOBJ opcodes.
7666  */
7667 static void
7668 handle_ctor_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used,
7669                                   MonoInst **sp, guint8 *ip, int *inline_costs)
7670 {
7671         MonoInst *vtable_arg = NULL, *callvirt_this_arg = NULL, *ins;
7672
7673         if (cmethod->klass->valuetype && mono_class_generic_sharing_enabled (cmethod->klass) &&
7674                                         mono_method_is_generic_sharable (cmethod, TRUE)) {
7675                 if (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst) {
7676                         mono_class_vtable (cfg->domain, cmethod->klass);
7677                         CHECK_TYPELOAD (cmethod->klass);
7678
7679                         vtable_arg = emit_get_rgctx_method (cfg, context_used,
7680                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
7681                 } else {
7682                         if (context_used) {
7683                                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
7684                                                                                                    cmethod->klass, MONO_RGCTX_INFO_VTABLE);
7685                         } else {
7686                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
7687
7688                                 CHECK_TYPELOAD (cmethod->klass);
7689                                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
7690                         }
7691                 }
7692         }
7693
7694         /* Avoid virtual calls to ctors if possible */
7695         if (mono_class_is_marshalbyref (cmethod->klass))
7696                 callvirt_this_arg = sp [0];
7697
7698         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_ctor (cfg, cmethod, fsig, sp))) {
7699                 g_assert (MONO_TYPE_IS_VOID (fsig->ret));
7700                 CHECK_CFG_EXCEPTION;
7701         } else if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used && !vtable_arg &&
7702                            mono_method_check_inlining (cfg, cmethod) &&
7703                            !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE)) {
7704                 int costs;
7705
7706                 if ((costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, FALSE))) {
7707                         cfg->real_offset += 5;
7708
7709                         *inline_costs += costs - 5;
7710                 } else {
7711                         INLINE_FAILURE ("inline failure");
7712                         // FIXME-VT: Clean this up
7713                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))
7714                                 GSHAREDVT_FAILURE(*ip);
7715                         mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, callvirt_this_arg, NULL, NULL);
7716                 }
7717         } else if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
7718                 MonoInst *addr;
7719
7720                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE);
7721                 mono_emit_calli (cfg, fsig, sp, addr, NULL, vtable_arg);
7722         } else if (context_used &&
7723                            ((!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
7724                                  !mono_class_generic_sharing_enabled (cmethod->klass)) || cfg->gsharedvt)) {
7725                 MonoInst *cmethod_addr;
7726
7727                 /* Generic calls made out of gsharedvt methods cannot be patched, so use an indirect call */
7728
7729                 cmethod_addr = emit_get_rgctx_method (cfg, context_used,
7730                                                                                           cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
7731
7732                 mono_emit_calli (cfg, fsig, sp, cmethod_addr, NULL, vtable_arg);
7733         } else {
7734                 INLINE_FAILURE ("ctor call");
7735                 ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp,
7736                                                                                   callvirt_this_arg, NULL, vtable_arg);
7737         }
7738  exception_exit:
7739         return;
7740 }
7741
7742 static void
7743 emit_setret (MonoCompile *cfg, MonoInst *val)
7744 {
7745         MonoType *ret_type = mini_get_underlying_type (mono_method_signature (cfg->method)->ret);
7746         MonoInst *ins;
7747
7748         if (mini_type_to_stind (cfg, ret_type) == CEE_STOBJ) {
7749                 MonoInst *ret_addr;
7750
7751                 if (!cfg->vret_addr) {
7752                         EMIT_NEW_VARSTORE (cfg, ins, cfg->ret, ret_type, val);
7753                 } else {
7754                         EMIT_NEW_RETLOADA (cfg, ret_addr);
7755
7756                         EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STOREV_MEMBASE, ret_addr->dreg, 0, val->dreg);
7757                         ins->klass = mono_class_from_mono_type (ret_type);
7758                 }
7759         } else {
7760 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
7761                 if (COMPILE_SOFT_FLOAT (cfg) && !ret_type->byref && ret_type->type == MONO_TYPE_R4) {
7762                         MonoInst *iargs [1];
7763                         MonoInst *conv;
7764
7765                         iargs [0] = val;
7766                         conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
7767                         mono_arch_emit_setret (cfg, cfg->method, conv);
7768                 } else {
7769                         mono_arch_emit_setret (cfg, cfg->method, val);
7770                 }
7771 #else
7772                 mono_arch_emit_setret (cfg, cfg->method, val);
7773 #endif
7774         }
7775 }
7776
7777 static MonoMethodSignature*
7778 sig_to_rgctx_sig (MonoMethodSignature *sig)
7779 {
7780         // FIXME: memory allocation
7781         MonoMethodSignature *res;
7782         int i;
7783
7784         res = g_malloc (MONO_SIZEOF_METHOD_SIGNATURE + (sig->param_count + 1) * sizeof (MonoType*));
7785         memcpy (res, sig, MONO_SIZEOF_METHOD_SIGNATURE);
7786         res->param_count = sig->param_count + 1;
7787         for (i = 0; i < sig->param_count; ++i)
7788                 res->params [i] = sig->params [i];
7789         res->params [sig->param_count] = &mono_defaults.int_class->byval_arg;
7790         return res;
7791 }
7792
7793 /*
7794  * mono_method_to_ir:
7795  *
7796  *   Translate the .net IL into linear IR.
7797  */
7798 int
7799 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
7800                    MonoInst *return_var, MonoInst **inline_args, 
7801                    guint inline_offset, gboolean is_virtual_call)
7802 {
7803         MonoError error;
7804         MonoInst *ins, **sp, **stack_start;
7805         MonoBasicBlock *tblock = NULL, *init_localsbb = NULL;
7806         MonoSimpleBasicBlock *bb = NULL, *original_bb = NULL;
7807         MonoMethod *cmethod, *method_definition;
7808         MonoInst **arg_array;
7809         MonoMethodHeader *header;
7810         MonoImage *image;
7811         guint32 token, ins_flag;
7812         MonoClass *klass;
7813         MonoClass *constrained_class = NULL;
7814         unsigned char *ip, *end, *target, *err_pos;
7815         MonoMethodSignature *sig;
7816         MonoGenericContext *generic_context = NULL;
7817         MonoGenericContainer *generic_container = NULL;
7818         MonoType **param_types;
7819         int i, n, start_new_bblock, dreg;
7820         int num_calls = 0, inline_costs = 0;
7821         int breakpoint_id = 0;
7822         guint num_args;
7823         GSList *class_inits = NULL;
7824         gboolean dont_verify, dont_verify_stloc, readonly = FALSE;
7825         int context_used;
7826         gboolean init_locals, seq_points, skip_dead_blocks;
7827         gboolean sym_seq_points = FALSE;
7828         MonoDebugMethodInfo *minfo;
7829         MonoBitSet *seq_point_locs = NULL;
7830         MonoBitSet *seq_point_set_locs = NULL;
7831
7832         cfg->disable_inline = is_jit_optimizer_disabled (method);
7833
7834         /* serialization and xdomain stuff may need access to private fields and methods */
7835         dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
7836         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE;
7837         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH;
7838         dont_verify |= method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; /* bug #77896 */
7839         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP;
7840         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP_INVOKE;
7841
7842         /* still some type unsafety issues in marshal wrappers... (unknown is PtrToStructure) */
7843         dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE;
7844         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_UNKNOWN;
7845         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED;
7846         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_STELEMREF;
7847
7848         image = method->klass->image;
7849         header = mono_method_get_header (method);
7850         if (!header) {
7851                 MonoLoaderError *error;
7852
7853                 if ((error = mono_loader_get_last_error ())) {
7854                         mono_cfg_set_exception (cfg, error->exception_type);
7855                 } else {
7856                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
7857                         cfg->exception_message = g_strdup_printf ("Missing or incorrect header for method %s", cfg->method->name);
7858                 }
7859                 goto exception_exit;
7860         }
7861         generic_container = mono_method_get_generic_container (method);
7862         sig = mono_method_signature (method);
7863         num_args = sig->hasthis + sig->param_count;
7864         ip = (unsigned char*)header->code;
7865         cfg->cil_start = ip;
7866         end = ip + header->code_size;
7867         cfg->stat_cil_code_size += header->code_size;
7868
7869         seq_points = cfg->gen_seq_points && cfg->method == method;
7870
7871         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
7872                 /* We could hit a seq point before attaching to the JIT (#8338) */
7873                 seq_points = FALSE;
7874         }
7875
7876         if (cfg->gen_sdb_seq_points && cfg->method == method) {
7877                 minfo = mono_debug_lookup_method (method);
7878                 if (minfo) {
7879                         MonoSymSeqPoint *sps;
7880                         int i, n_il_offsets;
7881
7882                         mono_debug_get_seq_points (minfo, NULL, NULL, NULL, &sps, &n_il_offsets);
7883                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
7884                         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);
7885                         sym_seq_points = TRUE;
7886                         for (i = 0; i < n_il_offsets; ++i) {
7887                                 if (sps [i].il_offset < header->code_size)
7888                                         mono_bitset_set_fast (seq_point_locs, sps [i].il_offset);
7889                         }
7890                         g_free (sps);
7891                 } else if (!method->wrapper_type && !method->dynamic && mono_debug_image_has_debug_info (method->klass->image)) {
7892                         /* Methods without line number info like auto-generated property accessors */
7893                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
7894                         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);
7895                         sym_seq_points = TRUE;
7896                 }
7897         }
7898
7899         /* 
7900          * Methods without init_locals set could cause asserts in various passes
7901          * (#497220). To work around this, we emit dummy initialization opcodes
7902          * (OP_DUMMY_ICONST etc.) which generate no code. These are only supported
7903          * on some platforms.
7904          */
7905         if ((cfg->opt & MONO_OPT_UNSAFE) && cfg->backend->have_dummy_init)
7906                 init_locals = header->init_locals;
7907         else
7908                 init_locals = TRUE;
7909
7910         method_definition = method;
7911         while (method_definition->is_inflated) {
7912                 MonoMethodInflated *imethod = (MonoMethodInflated *) method_definition;
7913                 method_definition = imethod->declaring;
7914         }
7915
7916         /* SkipVerification is not allowed if core-clr is enabled */
7917         if (!dont_verify && mini_assembly_can_skip_verification (cfg->domain, method)) {
7918                 dont_verify = TRUE;
7919                 dont_verify_stloc = TRUE;
7920         }
7921
7922         if (sig->is_inflated)
7923                 generic_context = mono_method_get_context (method);
7924         else if (generic_container)
7925                 generic_context = &generic_container->context;
7926         cfg->generic_context = generic_context;
7927
7928         if (!cfg->gshared)
7929                 g_assert (!sig->has_type_parameters);
7930
7931         if (sig->generic_param_count && method->wrapper_type == MONO_WRAPPER_NONE) {
7932                 g_assert (method->is_inflated);
7933                 g_assert (mono_method_get_context (method)->method_inst);
7934         }
7935         if (method->is_inflated && mono_method_get_context (method)->method_inst)
7936                 g_assert (sig->generic_param_count);
7937
7938         if (cfg->method == method) {
7939                 cfg->real_offset = 0;
7940         } else {
7941                 cfg->real_offset = inline_offset;
7942         }
7943
7944         cfg->cil_offset_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoBasicBlock*) * header->code_size);
7945         cfg->cil_offset_to_bb_len = header->code_size;
7946
7947         cfg->current_method = method;
7948
7949         if (cfg->verbose_level > 2)
7950                 printf ("method to IR %s\n", mono_method_full_name (method, TRUE));
7951
7952         param_types = mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * num_args);
7953         if (sig->hasthis)
7954                 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
7955         for (n = 0; n < sig->param_count; ++n)
7956                 param_types [n + sig->hasthis] = sig->params [n];
7957         cfg->arg_types = param_types;
7958
7959         cfg->dont_inline = g_list_prepend (cfg->dont_inline, method);
7960         if (cfg->method == method) {
7961
7962                 if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
7963                         cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
7964
7965                 /* ENTRY BLOCK */
7966                 NEW_BBLOCK (cfg, start_bblock);
7967                 cfg->bb_entry = start_bblock;
7968                 start_bblock->cil_code = NULL;
7969                 start_bblock->cil_length = 0;
7970
7971                 /* EXIT BLOCK */
7972                 NEW_BBLOCK (cfg, end_bblock);
7973                 cfg->bb_exit = end_bblock;
7974                 end_bblock->cil_code = NULL;
7975                 end_bblock->cil_length = 0;
7976                 end_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
7977                 g_assert (cfg->num_bblocks == 2);
7978
7979                 arg_array = cfg->args;
7980
7981                 if (header->num_clauses) {
7982                         cfg->spvars = g_hash_table_new (NULL, NULL);
7983                         cfg->exvars = g_hash_table_new (NULL, NULL);
7984                 }
7985                 /* handle exception clauses */
7986                 for (i = 0; i < header->num_clauses; ++i) {
7987                         MonoBasicBlock *try_bb;
7988                         MonoExceptionClause *clause = &header->clauses [i];
7989                         GET_BBLOCK (cfg, try_bb, ip + clause->try_offset);
7990
7991                         try_bb->real_offset = clause->try_offset;
7992                         try_bb->try_start = TRUE;
7993                         try_bb->region = ((i + 1) << 8) | clause->flags;
7994                         GET_BBLOCK (cfg, tblock, ip + clause->handler_offset);
7995                         tblock->real_offset = clause->handler_offset;
7996                         tblock->flags |= BB_EXCEPTION_HANDLER;
7997
7998                         /*
7999                          * Linking the try block with the EH block hinders inlining as we won't be able to 
8000                          * merge the bblocks from inlining and produce an artificial hole for no good reason.
8001                          */
8002                         if (COMPILE_LLVM (cfg))
8003                                 link_bblock (cfg, try_bb, tblock);
8004
8005                         if (*(ip + clause->handler_offset) == CEE_POP)
8006                                 tblock->flags |= BB_EXCEPTION_DEAD_OBJ;
8007
8008                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
8009                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER ||
8010                             clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
8011                                 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
8012                                 MONO_ADD_INS (tblock, ins);
8013
8014                                 if (seq_points && clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY && clause->flags != MONO_EXCEPTION_CLAUSE_FILTER) {
8015                                         /* finally clauses already have a seq point */
8016                                         /* seq points for filter clauses are emitted below */
8017                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
8018                                         MONO_ADD_INS (tblock, ins);
8019                                 }
8020
8021                                 /* todo: is a fault block unsafe to optimize? */
8022                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
8023                                         tblock->flags |= BB_EXCEPTION_UNSAFE;
8024                         }
8025
8026                         /*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);
8027                           while (p < end) {
8028                           printf ("%s", mono_disasm_code_one (NULL, method, p, &p));
8029                           }*/
8030                         /* catch and filter blocks get the exception object on the stack */
8031                         if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
8032                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
8033
8034                                 /* mostly like handle_stack_args (), but just sets the input args */
8035                                 /* printf ("handling clause at IL_%04x\n", clause->handler_offset); */
8036                                 tblock->in_scount = 1;
8037                                 tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
8038                                 tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
8039
8040                                 cfg->cbb = tblock;
8041
8042 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
8043                                 /* The EH code passes in the exception in a register to both JITted and LLVM compiled code */
8044                                 if (!cfg->compile_llvm) {
8045                                         MONO_INST_NEW (cfg, ins, OP_GET_EX_OBJ);
8046                                         ins->dreg = tblock->in_stack [0]->dreg;
8047                                         MONO_ADD_INS (tblock, ins);
8048                                 }
8049 #else
8050                                 MonoInst *dummy_use;
8051
8052                                 /* 
8053                                  * Add a dummy use for the exvar so its liveness info will be
8054                                  * correct.
8055                                  */
8056                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, tblock->in_stack [0]);
8057 #endif
8058
8059                                 if (seq_points && clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
8060                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
8061                                         MONO_ADD_INS (tblock, ins);
8062                                 }
8063                                 
8064                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
8065                                         GET_BBLOCK (cfg, tblock, ip + clause->data.filter_offset);
8066                                         tblock->flags |= BB_EXCEPTION_HANDLER;
8067                                         tblock->real_offset = clause->data.filter_offset;
8068                                         tblock->in_scount = 1;
8069                                         tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
8070                                         /* The filter block shares the exvar with the handler block */
8071                                         tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
8072                                         MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
8073                                         MONO_ADD_INS (tblock, ins);
8074                                 }
8075                         }
8076
8077                         if (clause->flags != MONO_EXCEPTION_CLAUSE_FILTER &&
8078                                         clause->data.catch_class &&
8079                                         cfg->gshared &&
8080                                         mono_class_check_context_used (clause->data.catch_class)) {
8081                                 /*
8082                                  * In shared generic code with catch
8083                                  * clauses containing type variables
8084                                  * the exception handling code has to
8085                                  * be able to get to the rgctx.
8086                                  * Therefore we have to make sure that
8087                                  * the vtable/mrgctx argument (for
8088                                  * static or generic methods) or the
8089                                  * "this" argument (for non-static
8090                                  * methods) are live.
8091                                  */
8092                                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
8093                                                 mini_method_get_context (method)->method_inst ||
8094                                                 method->klass->valuetype) {
8095                                         mono_get_vtable_var (cfg);
8096                                 } else {
8097                                         MonoInst *dummy_use;
8098
8099                                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, arg_array [0]);
8100                                 }
8101                         }
8102                 }
8103         } else {
8104                 arg_array = (MonoInst **) alloca (sizeof (MonoInst *) * num_args);
8105                 cfg->cbb = start_bblock;
8106                 cfg->args = arg_array;
8107                 mono_save_args (cfg, sig, inline_args);
8108         }
8109
8110         /* FIRST CODE BLOCK */
8111         NEW_BBLOCK (cfg, tblock);
8112         tblock->cil_code = ip;
8113         cfg->cbb = tblock;
8114         cfg->ip = ip;
8115
8116         ADD_BBLOCK (cfg, tblock);
8117
8118         if (cfg->method == method) {
8119                 breakpoint_id = mono_debugger_method_has_breakpoint (method);
8120                 if (breakpoint_id) {
8121                         MONO_INST_NEW (cfg, ins, OP_BREAK);
8122                         MONO_ADD_INS (cfg->cbb, ins);
8123                 }
8124         }
8125
8126         /* we use a separate basic block for the initialization code */
8127         NEW_BBLOCK (cfg, init_localsbb);
8128         cfg->bb_init = init_localsbb;
8129         init_localsbb->real_offset = cfg->real_offset;
8130         start_bblock->next_bb = init_localsbb;
8131         init_localsbb->next_bb = cfg->cbb;
8132         link_bblock (cfg, start_bblock, init_localsbb);
8133         link_bblock (cfg, init_localsbb, cfg->cbb);
8134                 
8135         cfg->cbb = init_localsbb;
8136
8137         if (cfg->gsharedvt && cfg->method == method) {
8138                 MonoGSharedVtMethodInfo *info;
8139                 MonoInst *var, *locals_var;
8140                 int dreg;
8141
8142                 info = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoGSharedVtMethodInfo));
8143                 info->method = cfg->method;
8144                 info->count_entries = 16;
8145                 info->entries = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
8146                 cfg->gsharedvt_info = info;
8147
8148                 var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8149                 /* prevent it from being register allocated */
8150                 //var->flags |= MONO_INST_VOLATILE;
8151                 cfg->gsharedvt_info_var = var;
8152
8153                 ins = emit_get_rgctx_gsharedvt_method (cfg, mini_method_check_context_used (cfg, method), method, info);
8154                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, var->dreg, ins->dreg);
8155
8156                 /* Allocate locals */
8157                 locals_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8158                 /* prevent it from being register allocated */
8159                 //locals_var->flags |= MONO_INST_VOLATILE;
8160                 cfg->gsharedvt_locals_var = locals_var;
8161
8162                 dreg = alloc_ireg (cfg);
8163                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, dreg, var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, locals_size));
8164
8165                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
8166                 ins->dreg = locals_var->dreg;
8167                 ins->sreg1 = dreg;
8168                 MONO_ADD_INS (cfg->cbb, ins);
8169                 cfg->gsharedvt_locals_var_ins = ins;
8170                 
8171                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
8172                 /*
8173                 if (init_locals)
8174                         ins->flags |= MONO_INST_INIT;
8175                 */
8176         }
8177
8178         if (mono_security_core_clr_enabled ()) {
8179                 /* check if this is native code, e.g. an icall or a p/invoke */
8180                 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
8181                         MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
8182                         if (wrapped) {
8183                                 gboolean pinvk = (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL);
8184                                 gboolean icall = (wrapped->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL);
8185
8186                                 /* if this ia a native call then it can only be JITted from platform code */
8187                                 if ((icall || pinvk) && method->klass && method->klass->image) {
8188                                         if (!mono_security_core_clr_is_platform_image (method->klass->image)) {
8189                                                 MonoException *ex = icall ? mono_get_exception_security () : 
8190                                                         mono_get_exception_method_access ();
8191                                                 emit_throw_exception (cfg, ex);
8192                                         }
8193                                 }
8194                         }
8195                 }
8196         }
8197
8198         CHECK_CFG_EXCEPTION;
8199
8200         if (header->code_size == 0)
8201                 UNVERIFIED;
8202
8203         if (get_basic_blocks (cfg, header, cfg->real_offset, ip, end, &err_pos)) {
8204                 ip = err_pos;
8205                 UNVERIFIED;
8206         }
8207
8208         if (cfg->method == method)
8209                 mono_debug_init_method (cfg, cfg->cbb, breakpoint_id);
8210
8211         for (n = 0; n < header->num_locals; ++n) {
8212                 if (header->locals [n]->type == MONO_TYPE_VOID && !header->locals [n]->byref)
8213                         UNVERIFIED;
8214         }
8215         class_inits = NULL;
8216
8217         /* We force the vtable variable here for all shared methods
8218            for the possibility that they might show up in a stack
8219            trace where their exact instantiation is needed. */
8220         if (cfg->gshared && method == cfg->method) {
8221                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
8222                                 mini_method_get_context (method)->method_inst ||
8223                                 method->klass->valuetype) {
8224                         mono_get_vtable_var (cfg);
8225                 } else {
8226                         /* FIXME: Is there a better way to do this?
8227                            We need the variable live for the duration
8228                            of the whole method. */
8229                         cfg->args [0]->flags |= MONO_INST_VOLATILE;
8230                 }
8231         }
8232
8233         /* add a check for this != NULL to inlined methods */
8234         if (is_virtual_call) {
8235                 MonoInst *arg_ins;
8236
8237                 NEW_ARGLOAD (cfg, arg_ins, 0);
8238                 MONO_ADD_INS (cfg->cbb, arg_ins);
8239                 MONO_EMIT_NEW_CHECK_THIS (cfg, arg_ins->dreg);
8240         }
8241
8242         skip_dead_blocks = !dont_verify;
8243         if (skip_dead_blocks) {
8244                 original_bb = bb = mono_basic_block_split (method, &cfg->error);
8245                 CHECK_CFG_ERROR;
8246                 g_assert (bb);
8247         }
8248
8249         /* we use a spare stack slot in SWITCH and NEWOBJ and others */
8250         stack_start = sp = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
8251
8252         ins_flag = 0;
8253         start_new_bblock = 0;
8254         while (ip < end) {
8255                 if (cfg->method == method)
8256                         cfg->real_offset = ip - header->code;
8257                 else
8258                         cfg->real_offset = inline_offset;
8259                 cfg->ip = ip;
8260
8261                 context_used = 0;
8262
8263                 if (start_new_bblock) {
8264                         cfg->cbb->cil_length = ip - cfg->cbb->cil_code;
8265                         if (start_new_bblock == 2) {
8266                                 g_assert (ip == tblock->cil_code);
8267                         } else {
8268                                 GET_BBLOCK (cfg, tblock, ip);
8269                         }
8270                         cfg->cbb->next_bb = tblock;
8271                         cfg->cbb = tblock;
8272                         start_new_bblock = 0;
8273                         for (i = 0; i < cfg->cbb->in_scount; ++i) {
8274                                 if (cfg->verbose_level > 3)
8275                                         printf ("loading %d from temp %d\n", i, (int)cfg->cbb->in_stack [i]->inst_c0);
8276                                 EMIT_NEW_TEMPLOAD (cfg, ins, cfg->cbb->in_stack [i]->inst_c0);
8277                                 *sp++ = ins;
8278                         }
8279                         if (class_inits)
8280                                 g_slist_free (class_inits);
8281                         class_inits = NULL;
8282                 } else {
8283                         if ((tblock = cfg->cil_offset_to_bb [ip - cfg->cil_start]) && (tblock != cfg->cbb)) {
8284                                 link_bblock (cfg, cfg->cbb, tblock);
8285                                 if (sp != stack_start) {
8286                                         handle_stack_args (cfg, stack_start, sp - stack_start);
8287                                         sp = stack_start;
8288                                         CHECK_UNVERIFIABLE (cfg);
8289                                 }
8290                                 cfg->cbb->next_bb = tblock;
8291                                 cfg->cbb = tblock;
8292                                 for (i = 0; i < cfg->cbb->in_scount; ++i) {
8293                                         if (cfg->verbose_level > 3)
8294                                                 printf ("loading %d from temp %d\n", i, (int)cfg->cbb->in_stack [i]->inst_c0);
8295                                         EMIT_NEW_TEMPLOAD (cfg, ins, cfg->cbb->in_stack [i]->inst_c0);
8296                                         *sp++ = ins;
8297                                 }
8298                                 g_slist_free (class_inits);
8299                                 class_inits = NULL;
8300                         }
8301                 }
8302
8303                 if (skip_dead_blocks) {
8304                         int ip_offset = ip - header->code;
8305
8306                         if (ip_offset == bb->end)
8307                                 bb = bb->next;
8308
8309                         if (bb->dead) {
8310                                 int op_size = mono_opcode_size (ip, end);
8311                                 g_assert (op_size > 0); /*The BB formation pass must catch all bad ops*/
8312
8313                                 if (cfg->verbose_level > 3) printf ("SKIPPING DEAD OP at %x\n", ip_offset);
8314
8315                                 if (ip_offset + op_size == bb->end) {
8316                                         MONO_INST_NEW (cfg, ins, OP_NOP);
8317                                         MONO_ADD_INS (cfg->cbb, ins);
8318                                         start_new_bblock = 1;
8319                                 }
8320
8321                                 ip += op_size;
8322                                 continue;
8323                         }
8324                 }
8325                 /*
8326                  * Sequence points are points where the debugger can place a breakpoint.
8327                  * Currently, we generate these automatically at points where the IL
8328                  * stack is empty.
8329                  */
8330                 if (seq_points && ((!sym_seq_points && (sp == stack_start)) || (sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code)))) {
8331                         /*
8332                          * Make methods interruptable at the beginning, and at the targets of
8333                          * backward branches.
8334                          * Also, do this at the start of every bblock in methods with clauses too,
8335                          * to be able to handle instructions with inprecise control flow like
8336                          * throw/endfinally.
8337                          * Backward branches are handled at the end of method-to-ir ().
8338                          */
8339                         gboolean intr_loc = ip == header->code || (!cfg->cbb->last_ins && cfg->header->num_clauses);
8340                         gboolean sym_seq_point = sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code);
8341
8342                         /* Avoid sequence points on empty IL like .volatile */
8343                         // FIXME: Enable this
8344                         //if (!(cfg->cbb->last_ins && cfg->cbb->last_ins->opcode == OP_SEQ_POINT)) {
8345                         NEW_SEQ_POINT (cfg, ins, ip - header->code, intr_loc);
8346                         if ((sp != stack_start) && !sym_seq_point)
8347                                 ins->flags |= MONO_INST_NONEMPTY_STACK;
8348                         MONO_ADD_INS (cfg->cbb, ins);
8349
8350                         if (sym_seq_points)
8351                                 mono_bitset_set_fast (seq_point_set_locs, ip - header->code);
8352                 }
8353
8354                 cfg->cbb->real_offset = cfg->real_offset;
8355
8356                 if ((cfg->method == method) && cfg->coverage_info) {
8357                         guint32 cil_offset = ip - header->code;
8358                         cfg->coverage_info->data [cil_offset].cil_code = ip;
8359
8360                         /* TODO: Use an increment here */
8361 #if defined(TARGET_X86)
8362                         MONO_INST_NEW (cfg, ins, OP_STORE_MEM_IMM);
8363                         ins->inst_p0 = &(cfg->coverage_info->data [cil_offset].count);
8364                         ins->inst_imm = 1;
8365                         MONO_ADD_INS (cfg->cbb, ins);
8366 #else
8367                         EMIT_NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
8368                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, ins->dreg, 0, 1);
8369 #endif
8370                 }
8371
8372                 if (cfg->verbose_level > 3)
8373                         printf ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
8374
8375                 switch (*ip) {
8376                 case CEE_NOP:
8377                         if (seq_points && !sym_seq_points && sp != stack_start) {
8378                                 /*
8379                                  * The C# compiler uses these nops to notify the JIT that it should
8380                                  * insert seq points.
8381                                  */
8382                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, FALSE);
8383                                 MONO_ADD_INS (cfg->cbb, ins);
8384                         }
8385                         if (cfg->keep_cil_nops)
8386                                 MONO_INST_NEW (cfg, ins, OP_HARD_NOP);
8387                         else
8388                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8389                         ip++;
8390                         MONO_ADD_INS (cfg->cbb, ins);
8391                         break;
8392                 case CEE_BREAK:
8393                         if (should_insert_brekpoint (cfg->method)) {
8394                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
8395                         } else {
8396                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8397                         }
8398                         ip++;
8399                         MONO_ADD_INS (cfg->cbb, ins);
8400                         break;
8401                 case CEE_LDARG_0:
8402                 case CEE_LDARG_1:
8403                 case CEE_LDARG_2:
8404                 case CEE_LDARG_3:
8405                         CHECK_STACK_OVF (1);
8406                         n = (*ip)-CEE_LDARG_0;
8407                         CHECK_ARG (n);
8408                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8409                         ip++;
8410                         *sp++ = ins;
8411                         break;
8412                 case CEE_LDLOC_0:
8413                 case CEE_LDLOC_1:
8414                 case CEE_LDLOC_2:
8415                 case CEE_LDLOC_3:
8416                         CHECK_STACK_OVF (1);
8417                         n = (*ip)-CEE_LDLOC_0;
8418                         CHECK_LOCAL (n);
8419                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8420                         ip++;
8421                         *sp++ = ins;
8422                         break;
8423                 case CEE_STLOC_0:
8424                 case CEE_STLOC_1:
8425                 case CEE_STLOC_2:
8426                 case CEE_STLOC_3: {
8427                         CHECK_STACK (1);
8428                         n = (*ip)-CEE_STLOC_0;
8429                         CHECK_LOCAL (n);
8430                         --sp;
8431                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
8432                                 UNVERIFIED;
8433                         emit_stloc_ir (cfg, sp, header, n);
8434                         ++ip;
8435                         inline_costs += 1;
8436                         break;
8437                         }
8438                 case CEE_LDARG_S:
8439                         CHECK_OPSIZE (2);
8440                         CHECK_STACK_OVF (1);
8441                         n = ip [1];
8442                         CHECK_ARG (n);
8443                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8444                         *sp++ = ins;
8445                         ip += 2;
8446                         break;
8447                 case CEE_LDARGA_S:
8448                         CHECK_OPSIZE (2);
8449                         CHECK_STACK_OVF (1);
8450                         n = ip [1];
8451                         CHECK_ARG (n);
8452                         NEW_ARGLOADA (cfg, ins, n);
8453                         MONO_ADD_INS (cfg->cbb, ins);
8454                         *sp++ = ins;
8455                         ip += 2;
8456                         break;
8457                 case CEE_STARG_S:
8458                         CHECK_OPSIZE (2);
8459                         CHECK_STACK (1);
8460                         --sp;
8461                         n = ip [1];
8462                         CHECK_ARG (n);
8463                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [ip [1]], *sp))
8464                                 UNVERIFIED;
8465                         EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
8466                         ip += 2;
8467                         break;
8468                 case CEE_LDLOC_S:
8469                         CHECK_OPSIZE (2);
8470                         CHECK_STACK_OVF (1);
8471                         n = ip [1];
8472                         CHECK_LOCAL (n);
8473                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8474                         *sp++ = ins;
8475                         ip += 2;
8476                         break;
8477                 case CEE_LDLOCA_S: {
8478                         unsigned char *tmp_ip;
8479                         CHECK_OPSIZE (2);
8480                         CHECK_STACK_OVF (1);
8481                         CHECK_LOCAL (ip [1]);
8482
8483                         if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 1))) {
8484                                 ip = tmp_ip;
8485                                 inline_costs += 1;
8486                                 break;
8487                         }
8488
8489                         EMIT_NEW_LOCLOADA (cfg, ins, ip [1]);
8490                         *sp++ = ins;
8491                         ip += 2;
8492                         break;
8493                 }
8494                 case CEE_STLOC_S:
8495                         CHECK_OPSIZE (2);
8496                         CHECK_STACK (1);
8497                         --sp;
8498                         CHECK_LOCAL (ip [1]);
8499                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [ip [1]], *sp))
8500                                 UNVERIFIED;
8501                         emit_stloc_ir (cfg, sp, header, ip [1]);
8502                         ip += 2;
8503                         inline_costs += 1;
8504                         break;
8505                 case CEE_LDNULL:
8506                         CHECK_STACK_OVF (1);
8507                         EMIT_NEW_PCONST (cfg, ins, NULL);
8508                         ins->type = STACK_OBJ;
8509                         ++ip;
8510                         *sp++ = ins;
8511                         break;
8512                 case CEE_LDC_I4_M1:
8513                         CHECK_STACK_OVF (1);
8514                         EMIT_NEW_ICONST (cfg, ins, -1);
8515                         ++ip;
8516                         *sp++ = ins;
8517                         break;
8518                 case CEE_LDC_I4_0:
8519                 case CEE_LDC_I4_1:
8520                 case CEE_LDC_I4_2:
8521                 case CEE_LDC_I4_3:
8522                 case CEE_LDC_I4_4:
8523                 case CEE_LDC_I4_5:
8524                 case CEE_LDC_I4_6:
8525                 case CEE_LDC_I4_7:
8526                 case CEE_LDC_I4_8:
8527                         CHECK_STACK_OVF (1);
8528                         EMIT_NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
8529                         ++ip;
8530                         *sp++ = ins;
8531                         break;
8532                 case CEE_LDC_I4_S:
8533                         CHECK_OPSIZE (2);
8534                         CHECK_STACK_OVF (1);
8535                         ++ip;
8536                         EMIT_NEW_ICONST (cfg, ins, *((signed char*)ip));
8537                         ++ip;
8538                         *sp++ = ins;
8539                         break;
8540                 case CEE_LDC_I4:
8541                         CHECK_OPSIZE (5);
8542                         CHECK_STACK_OVF (1);
8543                         EMIT_NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
8544                         ip += 5;
8545                         *sp++ = ins;
8546                         break;
8547                 case CEE_LDC_I8:
8548                         CHECK_OPSIZE (9);
8549                         CHECK_STACK_OVF (1);
8550                         MONO_INST_NEW (cfg, ins, OP_I8CONST);
8551                         ins->type = STACK_I8;
8552                         ins->dreg = alloc_dreg (cfg, STACK_I8);
8553                         ++ip;
8554                         ins->inst_l = (gint64)read64 (ip);
8555                         MONO_ADD_INS (cfg->cbb, ins);
8556                         ip += 8;
8557                         *sp++ = ins;
8558                         break;
8559                 case CEE_LDC_R4: {
8560                         float *f;
8561                         gboolean use_aotconst = FALSE;
8562
8563 #ifdef TARGET_POWERPC
8564                         /* FIXME: Clean this up */
8565                         if (cfg->compile_aot)
8566                                 use_aotconst = TRUE;
8567 #endif
8568
8569                         /* FIXME: we should really allocate this only late in the compilation process */
8570                         f = mono_domain_alloc (cfg->domain, sizeof (float));
8571                         CHECK_OPSIZE (5);
8572                         CHECK_STACK_OVF (1);
8573
8574                         if (use_aotconst) {
8575                                 MonoInst *cons;
8576                                 int dreg;
8577
8578                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R4, f);
8579
8580                                 dreg = alloc_freg (cfg);
8581                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR4_MEMBASE, dreg, cons->dreg, 0);
8582                                 ins->type = cfg->r4_stack_type;
8583                         } else {
8584                                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
8585                                 ins->type = cfg->r4_stack_type;
8586                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8587                                 ins->inst_p0 = f;
8588                                 MONO_ADD_INS (cfg->cbb, ins);
8589                         }
8590                         ++ip;
8591                         readr4 (ip, f);
8592                         ip += 4;
8593                         *sp++ = ins;                    
8594                         break;
8595                 }
8596                 case CEE_LDC_R8: {
8597                         double *d;
8598                         gboolean use_aotconst = FALSE;
8599
8600 #ifdef TARGET_POWERPC
8601                         /* FIXME: Clean this up */
8602                         if (cfg->compile_aot)
8603                                 use_aotconst = TRUE;
8604 #endif
8605
8606                         /* FIXME: we should really allocate this only late in the compilation process */
8607                         d = mono_domain_alloc (cfg->domain, sizeof (double));
8608                         CHECK_OPSIZE (9);
8609                         CHECK_STACK_OVF (1);
8610
8611                         if (use_aotconst) {
8612                                 MonoInst *cons;
8613                                 int dreg;
8614
8615                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R8, d);
8616
8617                                 dreg = alloc_freg (cfg);
8618                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR8_MEMBASE, dreg, cons->dreg, 0);
8619                                 ins->type = STACK_R8;
8620                         } else {
8621                                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
8622                                 ins->type = STACK_R8;
8623                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8624                                 ins->inst_p0 = d;
8625                                 MONO_ADD_INS (cfg->cbb, ins);
8626                         }
8627                         ++ip;
8628                         readr8 (ip, d);
8629                         ip += 8;
8630                         *sp++ = ins;
8631                         break;
8632                 }
8633                 case CEE_DUP: {
8634                         MonoInst *temp, *store;
8635                         CHECK_STACK (1);
8636                         CHECK_STACK_OVF (1);
8637                         sp--;
8638                         ins = *sp;
8639
8640                         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
8641                         EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
8642
8643                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8644                         *sp++ = ins;
8645
8646                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8647                         *sp++ = ins;
8648
8649                         ++ip;
8650                         inline_costs += 2;
8651                         break;
8652                 }
8653                 case CEE_POP:
8654                         CHECK_STACK (1);
8655                         ip++;
8656                         --sp;
8657
8658 #ifdef TARGET_X86
8659                         if (sp [0]->type == STACK_R8)
8660                                 /* we need to pop the value from the x86 FP stack */
8661                                 MONO_EMIT_NEW_UNALU (cfg, OP_X86_FPOP, -1, sp [0]->dreg);
8662 #endif
8663                         break;
8664                 case CEE_JMP: {
8665                         MonoCallInst *call;
8666                         MonoMethodSignature *fsig;
8667                         int i, n;
8668
8669                         INLINE_FAILURE ("jmp");
8670                         GSHAREDVT_FAILURE (*ip);
8671
8672                         CHECK_OPSIZE (5);
8673                         if (stack_start != sp)
8674                                 UNVERIFIED;
8675                         token = read32 (ip + 1);
8676                         /* FIXME: check the signature matches */
8677                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
8678
8679                         if (!cmethod || mono_loader_get_last_error ())
8680                                 LOAD_ERROR;
8681  
8682                         if (cfg->gshared && mono_method_check_context_used (cmethod))
8683                                 GENERIC_SHARING_FAILURE (CEE_JMP);
8684
8685                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
8686
8687                         fsig = mono_method_signature (cmethod);
8688                         n = fsig->param_count + fsig->hasthis;
8689                         if (cfg->llvm_only) {
8690                                 MonoInst **args;
8691
8692                                 args = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
8693                                 for (i = 0; i < n; ++i)
8694                                         EMIT_NEW_ARGLOAD (cfg, args [i], i);
8695                                 ins = mono_emit_method_call_full (cfg, cmethod, fsig, TRUE, args, NULL, NULL, NULL);
8696                                 /*
8697                                  * The code in mono-basic-block.c treats the rest of the code as dead, but we
8698                                  * have to emit a normal return since llvm expects it.
8699                                  */
8700                                 if (cfg->ret)
8701                                         emit_setret (cfg, ins);
8702                                 MONO_INST_NEW (cfg, ins, OP_BR);
8703                                 ins->inst_target_bb = end_bblock;
8704                                 MONO_ADD_INS (cfg->cbb, ins);
8705                                 link_bblock (cfg, cfg->cbb, end_bblock);
8706                                 ip += 5;
8707                                 break;
8708                         } else if (cfg->backend->have_op_tail_call) {
8709                                 /* Handle tail calls similarly to calls */
8710                                 DISABLE_AOT (cfg);
8711
8712                                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
8713                                 call->method = cmethod;
8714                                 call->tail_call = TRUE;
8715                                 call->signature = mono_method_signature (cmethod);
8716                                 call->args = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
8717                                 call->inst.inst_p0 = cmethod;
8718                                 for (i = 0; i < n; ++i)
8719                                         EMIT_NEW_ARGLOAD (cfg, call->args [i], i);
8720
8721                                 mono_arch_emit_call (cfg, call);
8722                                 cfg->param_area = MAX(cfg->param_area, call->stack_usage);
8723                                 MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
8724                         } else {
8725                                 for (i = 0; i < num_args; ++i)
8726                                         /* Prevent arguments from being optimized away */
8727                                         arg_array [i]->flags |= MONO_INST_VOLATILE;
8728
8729                                 MONO_INST_NEW_CALL (cfg, call, OP_JMP);
8730                                 ins = (MonoInst*)call;
8731                                 ins->inst_p0 = cmethod;
8732                                 MONO_ADD_INS (cfg->cbb, ins);
8733                         }
8734
8735                         ip += 5;
8736                         start_new_bblock = 1;
8737                         break;
8738                 }
8739                 case CEE_CALLI: {
8740                         MonoInst *addr;
8741                         MonoMethodSignature *fsig;
8742
8743                         CHECK_OPSIZE (5);
8744                         token = read32 (ip + 1);
8745
8746                         ins = NULL;
8747
8748                         //GSHAREDVT_FAILURE (*ip);
8749                         cmethod = NULL;
8750                         CHECK_STACK (1);
8751                         --sp;
8752                         addr = *sp;
8753                         fsig = mini_get_signature (method, token, generic_context);
8754
8755                         if (method->dynamic && fsig->pinvoke) {
8756                                 MonoInst *args [3];
8757
8758                                 /*
8759                                  * This is a call through a function pointer using a pinvoke
8760                                  * signature. Have to create a wrapper and call that instead.
8761                                  * FIXME: This is very slow, need to create a wrapper at JIT time
8762                                  * instead based on the signature.
8763                                  */
8764                                 EMIT_NEW_IMAGECONST (cfg, args [0], method->klass->image);
8765                                 EMIT_NEW_PCONST (cfg, args [1], fsig);
8766                                 args [2] = addr;
8767                                 addr = mono_emit_jit_icall (cfg, mono_get_native_calli_wrapper, args);
8768                         }
8769
8770                         n = fsig->param_count + fsig->hasthis;
8771
8772                         CHECK_STACK (n);
8773
8774                         //g_assert (!virtual || fsig->hasthis);
8775
8776                         sp -= n;
8777
8778                         inline_costs += 10 * num_calls++;
8779
8780                         /*
8781                          * Making generic calls out of gsharedvt methods.
8782                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
8783                          * patching gshared method addresses into a gsharedvt method.
8784                          */
8785                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
8786                                 /*
8787                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
8788                                  */
8789                                 MonoInst *callee = addr;
8790
8791                                 if (method->wrapper_type != MONO_WRAPPER_DELEGATE_INVOKE)
8792                                         /* Not tested */
8793                                         GSHAREDVT_FAILURE (*ip);
8794
8795                                 addr = emit_get_rgctx_sig (cfg, context_used,
8796                                                                                           fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
8797                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
8798                                 goto calli_end;
8799                         }
8800
8801                         /* Prevent inlining of methods with indirect calls */
8802                         INLINE_FAILURE ("indirect call");
8803
8804                         if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST || addr->opcode == OP_GOT_ENTRY) {
8805                                 int info_type;
8806                                 gpointer info_data;
8807
8808                                 /*
8809                                  * Instead of emitting an indirect call, emit a direct call
8810                                  * with the contents of the aotconst as the patch info.
8811                                  */
8812                                 if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST) {
8813                                         info_type = addr->inst_c1;
8814                                         info_data = addr->inst_p0;
8815                                 } else {
8816                                         info_type = addr->inst_right->inst_c1;
8817                                         info_data = addr->inst_right->inst_left;
8818                                 }
8819
8820                                 if (info_type == MONO_PATCH_INFO_ICALL_ADDR || info_type == MONO_PATCH_INFO_JIT_ICALL_ADDR) {
8821                                         ins = (MonoInst*)mono_emit_abs_call (cfg, info_type, info_data, fsig, sp);
8822                                         NULLIFY_INS (addr);
8823                                         goto calli_end;
8824                                 }
8825                         }
8826                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8827
8828                         calli_end:
8829
8830                         /* End of call, INS should contain the result of the call, if any */
8831
8832                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8833                                 g_assert (ins);
8834                                 *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
8835                         }
8836
8837                         CHECK_CFG_EXCEPTION;
8838
8839                         ip += 5;
8840                         ins_flag = 0;
8841                         constrained_class = NULL;
8842                         break;
8843                 }
8844                 case CEE_CALL:
8845                 case CEE_CALLVIRT: {
8846                         MonoInst *addr = NULL;
8847                         MonoMethodSignature *fsig = NULL;
8848                         int array_rank = 0;
8849                         int virtual = *ip == CEE_CALLVIRT;
8850                         gboolean pass_imt_from_rgctx = FALSE;
8851                         MonoInst *imt_arg = NULL;
8852                         MonoInst *keep_this_alive = NULL;
8853                         gboolean pass_vtable = FALSE;
8854                         gboolean pass_mrgctx = FALSE;
8855                         MonoInst *vtable_arg = NULL;
8856                         gboolean check_this = FALSE;
8857                         gboolean supported_tail_call = FALSE;
8858                         gboolean tail_call = FALSE;
8859                         gboolean need_seq_point = FALSE;
8860                         guint32 call_opcode = *ip;
8861                         gboolean emit_widen = TRUE;
8862                         gboolean push_res = TRUE;
8863                         gboolean skip_ret = FALSE;
8864                         gboolean delegate_invoke = FALSE;
8865                         gboolean direct_icall = FALSE;
8866                         gboolean constrained_partial_call = FALSE;
8867                         MonoMethod *cil_method;
8868
8869                         CHECK_OPSIZE (5);
8870                         token = read32 (ip + 1);
8871
8872                         ins = NULL;
8873
8874                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
8875                         cil_method = cmethod;
8876                                 
8877                         if (constrained_class) {
8878                                 if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->gshared) {
8879                                         if (!mini_is_gsharedvt_klass (constrained_class)) {
8880                                                 g_assert (!cmethod->klass->valuetype);
8881                                                 if (!mini_type_is_reference (&constrained_class->byval_arg))
8882                                                         constrained_partial_call = TRUE;
8883                                         }
8884                                 }
8885
8886                                 if (method->wrapper_type != MONO_WRAPPER_NONE) {
8887                                         if (cfg->verbose_level > 2)
8888                                                 printf ("DM Constrained call to %s\n", mono_type_get_full_name (constrained_class));
8889                                         if (!((constrained_class->byval_arg.type == MONO_TYPE_VAR ||
8890                                                    constrained_class->byval_arg.type == MONO_TYPE_MVAR) &&
8891                                                   cfg->gshared)) {
8892                                                 cmethod = mono_get_method_constrained_with_method (image, cil_method, constrained_class, generic_context, &cfg->error);
8893                                                 CHECK_CFG_ERROR;
8894                                         }
8895                                 } else {
8896                                         if (cfg->verbose_level > 2)
8897                                                 printf ("Constrained call to %s\n", mono_type_get_full_name (constrained_class));
8898
8899                                         if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->gshared) {
8900                                                 /* 
8901                                                  * This is needed since get_method_constrained can't find 
8902                                                  * the method in klass representing a type var.
8903                                                  * The type var is guaranteed to be a reference type in this
8904                                                  * case.
8905                                                  */
8906                                                 if (!mini_is_gsharedvt_klass (constrained_class))
8907                                                         g_assert (!cmethod->klass->valuetype);
8908                                         } else {
8909                                                 cmethod = mono_get_method_constrained_checked (image, token, constrained_class, generic_context, &cil_method, &cfg->error);
8910                                                 CHECK_CFG_ERROR;
8911                                         }
8912                                 }
8913                         }
8914                                         
8915                         if (!cmethod || mono_loader_get_last_error ())
8916                                 LOAD_ERROR;
8917                         if (!dont_verify && !cfg->skip_visibility) {
8918                                 MonoMethod *target_method = cil_method;
8919                                 if (method->is_inflated) {
8920                                         target_method = mini_get_method_allow_open (method, token, NULL, &(mono_method_get_generic_container (method_definition)->context));
8921                                 }
8922                                 if (!mono_method_can_access_method (method_definition, target_method) &&
8923                                         !mono_method_can_access_method (method, cil_method))
8924                                         METHOD_ACCESS_FAILURE (method, cil_method);
8925                         }
8926
8927                         if (mono_security_core_clr_enabled ())
8928                                 ensure_method_is_allowed_to_call_method (cfg, method, cil_method);
8929
8930                         if (!virtual && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
8931                                 /* MS.NET seems to silently convert this to a callvirt */
8932                                 virtual = 1;
8933
8934                         {
8935                                 /*
8936                                  * MS.NET accepts non virtual calls to virtual final methods of transparent proxy classes and
8937                                  * converts to a callvirt.
8938                                  *
8939                                  * tests/bug-515884.il is an example of this behavior
8940                                  */
8941                                 const int test_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_STATIC;
8942                                 const int expected_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL;
8943                                 if (!virtual && mono_class_is_marshalbyref (cmethod->klass) && (cmethod->flags & test_flags) == expected_flags && cfg->method->wrapper_type == MONO_WRAPPER_NONE)
8944                                         virtual = 1;
8945                         }
8946
8947                         if (!cmethod->klass->inited)
8948                                 if (!mono_class_init (cmethod->klass))
8949                                         TYPE_LOAD_ERROR (cmethod->klass);
8950
8951                         fsig = mono_method_signature (cmethod);
8952                         if (!fsig)
8953                                 LOAD_ERROR;
8954                         if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
8955                                 mini_class_is_system_array (cmethod->klass)) {
8956                                 array_rank = cmethod->klass->rank;
8957                         } else if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && icall_is_direct_callable (cfg, cmethod)) {
8958                                 direct_icall = TRUE;
8959                         } else if (fsig->pinvoke) {
8960                                 MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
8961                                 fsig = mono_method_signature (wrapper);
8962                         } else if (constrained_class) {
8963                         } else {
8964                                 fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
8965                                 CHECK_CFG_ERROR;
8966                         }
8967
8968                         /* See code below */
8969                         if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
8970                                 MonoBasicBlock *tbb;
8971
8972                                 GET_BBLOCK (cfg, tbb, ip + 5);
8973                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
8974                                         /*
8975                                          * We want to extend the try block to cover the call, but we can't do it if the
8976                                          * call is made directly since its followed by an exception check.
8977                                          */
8978                                         direct_icall = FALSE;
8979                                 }
8980                         }
8981
8982                         mono_save_token_info (cfg, image, token, cil_method);
8983
8984                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip + 5 - header->code)))
8985                                 need_seq_point = TRUE;
8986
8987                         /* Don't support calls made using type arguments for now */
8988                         /*
8989                           if (cfg->gsharedvt) {
8990                           if (mini_is_gsharedvt_signature (fsig))
8991                           GSHAREDVT_FAILURE (*ip);
8992                           }
8993                         */
8994
8995                         if (cmethod->string_ctor && method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE)
8996                                 g_assert_not_reached ();
8997
8998                         n = fsig->param_count + fsig->hasthis;
8999
9000                         if (!cfg->gshared && cmethod->klass->generic_container)
9001                                 UNVERIFIED;
9002
9003                         if (!cfg->gshared)
9004                                 g_assert (!mono_method_check_context_used (cmethod));
9005
9006                         CHECK_STACK (n);
9007
9008                         //g_assert (!virtual || fsig->hasthis);
9009
9010                         sp -= n;
9011
9012                         if (constrained_class) {
9013                                 if (mini_is_gsharedvt_klass (constrained_class)) {
9014                                         if ((cmethod->klass != mono_defaults.object_class) && constrained_class->valuetype && cmethod->klass->valuetype) {
9015                                                 /* The 'Own method' case below */
9016                                         } else if (cmethod->klass->image != mono_defaults.corlib && !(cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !cmethod->klass->valuetype) {
9017                                                 /* 'The type parameter is instantiated as a reference type' case below. */
9018                                         } else {
9019                                                 ins = handle_constrained_gsharedvt_call (cfg, cmethod, fsig, sp, constrained_class, &emit_widen);
9020                                                 CHECK_CFG_EXCEPTION;
9021                                                 g_assert (ins);
9022                                                 goto call_end;
9023                                         }
9024                                 }
9025
9026                                 /*
9027                                  * We have the `constrained.' prefix opcode.
9028                                  */
9029                                 if (constrained_partial_call) {
9030                                         gboolean need_box = TRUE;
9031
9032                                         /*
9033                                          * The receiver is a valuetype, but the exact type is not known at compile time. This means the
9034                                          * called method is not known at compile time either. The called method could end up being
9035                                          * one of the methods on the parent classes (object/valuetype/enum), in which case we need
9036                                          * to box the receiver.
9037                                          * A simple solution would be to box always and make a normal virtual call, but that would
9038                                          * be bad performance wise.
9039                                          */
9040                                         if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE && cmethod->klass->generic_class) {
9041                                                 /*
9042                                                  * The parent classes implement no generic interfaces, so the called method will be a vtype method, so no boxing neccessary.
9043                                                  */
9044                                                 need_box = FALSE;
9045                                         }
9046
9047                                         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)) {
9048                                                 /* The called method is not virtual, i.e. Object:GetType (), the receiver is a vtype, has to box */
9049                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9050                                                 ins->klass = constrained_class;
9051                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9052                                                 CHECK_CFG_EXCEPTION;
9053                                         } else if (need_box) {
9054                                                 MonoInst *box_type;
9055                                                 MonoBasicBlock *is_ref_bb, *end_bb;
9056                                                 MonoInst *nonbox_call;
9057
9058                                                 /*
9059                                                  * Determine at runtime whenever the called method is defined on object/valuetype/enum, and emit a boxing call
9060                                                  * if needed.
9061                                                  * FIXME: It is possible to inline the called method in a lot of cases, i.e. for T_INT,
9062                                                  * the no-box case goes to a method in Int32, while the box case goes to a method in Enum.
9063                                                  */
9064                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
9065
9066                                                 NEW_BBLOCK (cfg, is_ref_bb);
9067                                                 NEW_BBLOCK (cfg, end_bb);
9068
9069                                                 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);
9070                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, box_type->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
9071                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
9072
9073                                                 /* Non-ref case */
9074                                                 nonbox_call = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9075
9076                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
9077
9078                                                 /* Ref case */
9079                                                 MONO_START_BB (cfg, is_ref_bb);
9080                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9081                                                 ins->klass = constrained_class;
9082                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9083                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9084
9085                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
9086
9087                                                 MONO_START_BB (cfg, end_bb);
9088                                                 cfg->cbb = end_bb;
9089
9090                                                 nonbox_call->dreg = ins->dreg;
9091                                                 goto call_end;
9092                                         } else {
9093                                                 g_assert (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE);
9094                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
9095                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9096                                                 goto call_end;
9097                                         }
9098                                 } else if (constrained_class->valuetype && (cmethod->klass == mono_defaults.object_class || cmethod->klass == mono_defaults.enum_class->parent || cmethod->klass == mono_defaults.enum_class)) {
9099                                         /*
9100                                          * The type parameter is instantiated as a valuetype,
9101                                          * but that type doesn't override the method we're
9102                                          * calling, so we need to box `this'.
9103                                          */
9104                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9105                                         ins->klass = constrained_class;
9106                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9107                                         CHECK_CFG_EXCEPTION;
9108                                 } else if (!constrained_class->valuetype) {
9109                                         int dreg = alloc_ireg_ref (cfg);
9110
9111                                         /*
9112                                          * The type parameter is instantiated as a reference
9113                                          * type.  We have a managed pointer on the stack, so
9114                                          * we need to dereference it here.
9115                                          */
9116                                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, sp [0]->dreg, 0);
9117                                         ins->type = STACK_OBJ;
9118                                         sp [0] = ins;
9119                                 } else {
9120                                         if (cmethod->klass->valuetype) {
9121                                                 /* Own method */
9122                                         } else {
9123                                                 /* Interface method */
9124                                                 int ioffset, slot;
9125
9126                                                 mono_class_setup_vtable (constrained_class);
9127                                                 CHECK_TYPELOAD (constrained_class);
9128                                                 ioffset = mono_class_interface_offset (constrained_class, cmethod->klass);
9129                                                 if (ioffset == -1)
9130                                                         TYPE_LOAD_ERROR (constrained_class);
9131                                                 slot = mono_method_get_vtable_slot (cmethod);
9132                                                 if (slot == -1)
9133                                                         TYPE_LOAD_ERROR (cmethod->klass);
9134                                                 cmethod = constrained_class->vtable [ioffset + slot];
9135
9136                                                 if (cmethod->klass == mono_defaults.enum_class) {
9137                                                         /* Enum implements some interfaces, so treat this as the first case */
9138                                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9139                                                         ins->klass = constrained_class;
9140                                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9141                                                         CHECK_CFG_EXCEPTION;
9142                                                 }
9143                                         }
9144                                         virtual = 0;
9145                                 }
9146                                 constrained_class = NULL;
9147                         }
9148
9149                         if (check_call_signature (cfg, fsig, sp))
9150                                 UNVERIFIED;
9151
9152                         if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (cmethod->name, "Invoke"))
9153                                 delegate_invoke = TRUE;
9154
9155                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_sharable_method (cfg, cmethod, fsig, sp))) {
9156                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9157                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
9158                                         emit_widen = FALSE;
9159                                 }
9160
9161                                 goto call_end;
9162                         }
9163
9164                         /* 
9165                          * If the callee is a shared method, then its static cctor
9166                          * might not get called after the call was patched.
9167                          */
9168                         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)) {
9169                                 emit_class_init (cfg, cmethod->klass);
9170                                 CHECK_TYPELOAD (cmethod->klass);
9171                         }
9172
9173                         check_method_sharing (cfg, cmethod, &pass_vtable, &pass_mrgctx);
9174
9175                         if (cfg->gshared) {
9176                                 MonoGenericContext *cmethod_context = mono_method_get_context (cmethod);
9177
9178                                 context_used = mini_method_check_context_used (cfg, cmethod);
9179
9180                                 if (context_used && (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
9181                                         /* Generic method interface
9182                                            calls are resolved via a
9183                                            helper function and don't
9184                                            need an imt. */
9185                                         if (!cmethod_context || !cmethod_context->method_inst)
9186                                                 pass_imt_from_rgctx = TRUE;
9187                                 }
9188
9189                                 /*
9190                                  * If a shared method calls another
9191                                  * shared method then the caller must
9192                                  * have a generic sharing context
9193                                  * because the magic trampoline
9194                                  * requires it.  FIXME: We shouldn't
9195                                  * have to force the vtable/mrgctx
9196                                  * variable here.  Instead there
9197                                  * should be a flag in the cfg to
9198                                  * request a generic sharing context.
9199                                  */
9200                                 if (context_used &&
9201                                                 ((method->flags & METHOD_ATTRIBUTE_STATIC) || method->klass->valuetype))
9202                                         mono_get_vtable_var (cfg);
9203                         }
9204
9205                         if (pass_vtable) {
9206                                 if (context_used) {
9207                                         vtable_arg = emit_get_rgctx_klass (cfg, context_used, cmethod->klass, MONO_RGCTX_INFO_VTABLE);
9208                                 } else {
9209                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
9210
9211                                         CHECK_TYPELOAD (cmethod->klass);
9212                                         EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
9213                                 }
9214                         }
9215
9216                         if (pass_mrgctx) {
9217                                 g_assert (!vtable_arg);
9218
9219                                 if (!cfg->compile_aot) {
9220                                         /* 
9221                                          * emit_get_rgctx_method () calls mono_class_vtable () so check 
9222                                          * for type load errors before.
9223                                          */
9224                                         mono_class_setup_vtable (cmethod->klass);
9225                                         CHECK_TYPELOAD (cmethod->klass);
9226                                 }
9227
9228                                 vtable_arg = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
9229
9230                                 /* !marshalbyref is needed to properly handle generic methods + remoting */
9231                                 if ((!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
9232                                          MONO_METHOD_IS_FINAL (cmethod)) &&
9233                                         !mono_class_is_marshalbyref (cmethod->klass)) {
9234                                         if (virtual)
9235                                                 check_this = TRUE;
9236                                         virtual = 0;
9237                                 }
9238                         }
9239
9240                         if (pass_imt_from_rgctx) {
9241                                 g_assert (!pass_vtable);
9242
9243                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9244                                         cmethod, MONO_RGCTX_INFO_METHOD);
9245                         }
9246
9247                         if (check_this)
9248                                 MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9249
9250                         /* Calling virtual generic methods */
9251                         if (virtual && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) && 
9252                             !(MONO_METHOD_IS_FINAL (cmethod) && 
9253                               cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) &&
9254                             fsig->generic_param_count && 
9255                                 !(cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) &&
9256                                 !cfg->llvm_only) {
9257                                 MonoInst *this_temp, *this_arg_temp, *store;
9258                                 MonoInst *iargs [4];
9259
9260                                 g_assert (fsig->is_inflated);
9261
9262                                 /* Prevent inlining of methods that contain indirect calls */
9263                                 INLINE_FAILURE ("virtual generic call");
9264
9265                                 if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))
9266                                         GSHAREDVT_FAILURE (*ip);
9267
9268                                 if (cfg->backend->have_generalized_imt_thunk && cfg->backend->gshared_supported && cmethod->wrapper_type == MONO_WRAPPER_NONE) {
9269                                         g_assert (!imt_arg);
9270                                         if (!context_used)
9271                                                 g_assert (cmethod->is_inflated);
9272                                         imt_arg = emit_get_rgctx_method (cfg, context_used,
9273                                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
9274                                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, sp [0], imt_arg, NULL);
9275                                 } else {
9276                                         this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
9277                                         NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
9278                                         MONO_ADD_INS (cfg->cbb, store);
9279
9280                                         /* FIXME: This should be a managed pointer */
9281                                         this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
9282
9283                                         EMIT_NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
9284                                         iargs [1] = emit_get_rgctx_method (cfg, context_used,
9285                                                                                                            cmethod, MONO_RGCTX_INFO_METHOD);
9286                                         EMIT_NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
9287                                         addr = mono_emit_jit_icall (cfg,
9288                                                                                                 mono_helper_compile_generic_method, iargs);
9289
9290                                         EMIT_NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
9291
9292                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9293                                 }
9294
9295                                 goto call_end;
9296                         }
9297
9298                         /*
9299                          * Implement a workaround for the inherent races involved in locking:
9300                          * Monitor.Enter ()
9301                          * try {
9302                          * } finally {
9303                          *    Monitor.Exit ()
9304                          * }
9305                          * If a thread abort happens between the call to Monitor.Enter () and the start of the
9306                          * try block, the Exit () won't be executed, see:
9307                          * http://www.bluebytesoftware.com/blog/2007/01/30/MonitorEnterThreadAbortsAndOrphanedLocks.aspx
9308                          * To work around this, we extend such try blocks to include the last x bytes
9309                          * of the Monitor.Enter () call.
9310                          */
9311                         if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
9312                                 MonoBasicBlock *tbb;
9313
9314                                 GET_BBLOCK (cfg, tbb, ip + 5);
9315                                 /* 
9316                                  * Only extend try blocks with a finally, to avoid catching exceptions thrown
9317                                  * from Monitor.Enter like ArgumentNullException.
9318                                  */
9319                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
9320                                         /* Mark this bblock as needing to be extended */
9321                                         tbb->extend_try_block = TRUE;
9322                                 }
9323                         }
9324
9325                         /* Conversion to a JIT intrinsic */
9326                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_method (cfg, cmethod, fsig, sp))) {
9327                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9328                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
9329                                         emit_widen = FALSE;
9330                                 }
9331                                 goto call_end;
9332                         }
9333
9334                         /* Inlining */
9335                         if ((cfg->opt & MONO_OPT_INLINE) &&
9336                                 (!virtual || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || MONO_METHOD_IS_FINAL (cmethod)) &&
9337                             mono_method_check_inlining (cfg, cmethod)) {
9338                                 int costs;
9339                                 gboolean always = FALSE;
9340
9341                                 if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
9342                                         (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
9343                                         /* Prevent inlining of methods that call wrappers */
9344                                         INLINE_FAILURE ("wrapper call");
9345                                         cmethod = mono_marshal_get_native_wrapper (cmethod, TRUE, FALSE);
9346                                         always = TRUE;
9347                                 }
9348
9349                                 costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, always);
9350                                 if (costs) {
9351                                         cfg->real_offset += 5;
9352
9353                                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9354                                                 /* *sp is already set by inline_method */
9355                                                 sp++;
9356                                                 push_res = FALSE;
9357                                         }
9358
9359                                         inline_costs += costs;
9360
9361                                         goto call_end;
9362                                 }
9363                         }
9364
9365                         /* Tail recursion elimination */
9366                         if ((cfg->opt & MONO_OPT_TAILC) && call_opcode == CEE_CALL && cmethod == method && ip [5] == CEE_RET && !vtable_arg) {
9367                                 gboolean has_vtargs = FALSE;
9368                                 int i;
9369
9370                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9371                                 INLINE_FAILURE ("tail call");
9372
9373                                 /* keep it simple */
9374                                 for (i =  fsig->param_count - 1; i >= 0; i--) {
9375                                         if (MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->params [i])) 
9376                                                 has_vtargs = TRUE;
9377                                 }
9378
9379                                 if (!has_vtargs) {
9380                                         for (i = 0; i < n; ++i)
9381                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9382                                         MONO_INST_NEW (cfg, ins, OP_BR);
9383                                         MONO_ADD_INS (cfg->cbb, ins);
9384                                         tblock = start_bblock->out_bb [0];
9385                                         link_bblock (cfg, cfg->cbb, tblock);
9386                                         ins->inst_target_bb = tblock;
9387                                         start_new_bblock = 1;
9388
9389                                         /* skip the CEE_RET, too */
9390                                         if (ip_in_bb (cfg, cfg->cbb, ip + 5))
9391                                                 skip_ret = TRUE;
9392                                         push_res = FALSE;
9393                                         goto call_end;
9394                                 }
9395                         }
9396
9397                         inline_costs += 10 * num_calls++;
9398
9399                         /*
9400                          * Making generic calls out of gsharedvt methods.
9401                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
9402                          * patching gshared method addresses into a gsharedvt method.
9403                          */
9404                         if (cfg->gsharedvt && (mini_is_gsharedvt_signature (fsig) || cmethod->is_inflated || cmethod->klass->generic_class) &&
9405                                 !(cmethod->klass->rank && cmethod->klass->byval_arg.type != MONO_TYPE_SZARRAY)) {
9406                                 MonoRgctxInfoType info_type;
9407
9408                                 if (virtual) {
9409                                         //if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
9410                                                 //GSHAREDVT_FAILURE (*ip);
9411                                         // disable for possible remoting calls
9412                                         if (fsig->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class))
9413                                                 GSHAREDVT_FAILURE (*ip);
9414                                         if (fsig->generic_param_count) {
9415                                                 /* virtual generic call */
9416                                                 g_assert (!imt_arg);
9417                                                 /* Same as the virtual generic case above */
9418                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9419                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9420                                                 /* This is not needed, as the trampoline code will pass one, and it might be passed in the same reg as the imt arg */
9421                                                 vtable_arg = NULL;
9422                                         } else if ((cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !imt_arg) {
9423                                                 /* This can happen when we call a fully instantiated iface method */
9424                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9425                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9426                                                 vtable_arg = NULL;
9427                                         }
9428                                 }
9429
9430                                 if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (cmethod->name, "Invoke")))
9431                                         keep_this_alive = sp [0];
9432
9433                                 if (virtual && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))
9434                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
9435                                 else
9436                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE;
9437                                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, info_type);
9438
9439                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9440                                 goto call_end;
9441                         }
9442
9443                         /* Generic sharing */
9444
9445                         /*
9446                          * Use this if the callee is gsharedvt sharable too, since
9447                          * at runtime we might find an instantiation so the call cannot
9448                          * be patched (the 'no_patch' code path in mini-trampolines.c).
9449                          */
9450                         if (context_used && !imt_arg && !array_rank && !delegate_invoke &&
9451                                 (!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
9452                                  !mono_class_generic_sharing_enabled (cmethod->klass)) &&
9453                                 (!virtual || MONO_METHOD_IS_FINAL (cmethod) ||
9454                                  !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))) {
9455                                 INLINE_FAILURE ("gshared");
9456
9457                                 g_assert (cfg->gshared && cmethod);
9458                                 g_assert (!addr);
9459
9460                                 /*
9461                                  * We are compiling a call to a
9462                                  * generic method from shared code,
9463                                  * which means that we have to look up
9464                                  * the method in the rgctx and do an
9465                                  * indirect call.
9466                                  */
9467                                 if (fsig->hasthis)
9468                                         MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9469
9470                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
9471                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9472                                 goto call_end;
9473                         }
9474
9475                         /* Direct calls to icalls */
9476                         if (direct_icall) {
9477                                 MonoMethod *wrapper;
9478                                 int costs;
9479
9480                                 /* Inline the wrapper */
9481                                 wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
9482
9483                                 costs = inline_method (cfg, wrapper, fsig, sp, ip, cfg->real_offset, TRUE);
9484                                 g_assert (costs > 0);
9485                                 cfg->real_offset += 5;
9486
9487                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9488                                         /* *sp is already set by inline_method */
9489                                         sp++;
9490                                         push_res = FALSE;
9491                                 }
9492
9493                                 inline_costs += costs;
9494
9495                                 goto call_end;
9496                         }
9497                                         
9498                         /* Array methods */
9499                         if (array_rank) {
9500                                 MonoInst *addr;
9501
9502                                 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ 
9503                                         MonoInst *val = sp [fsig->param_count];
9504
9505                                         if (val->type == STACK_OBJ) {
9506                                                 MonoInst *iargs [2];
9507
9508                                                 iargs [0] = sp [0];
9509                                                 iargs [1] = val;
9510                                                 
9511                                                 mono_emit_jit_icall (cfg, mono_helper_stelem_ref_check, iargs);
9512                                         }
9513                                         
9514                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, TRUE);
9515                                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, fsig->params [fsig->param_count - 1], addr->dreg, 0, val->dreg);
9516                                         if (cfg->gen_write_barriers && val->type == STACK_OBJ && !(val->opcode == OP_PCONST && val->inst_c0 == 0))
9517                                                 emit_write_barrier (cfg, addr, val);
9518                                         if (cfg->gen_write_barriers && mini_is_gsharedvt_klass (cmethod->klass))
9519                                                 GSHAREDVT_FAILURE (*ip);
9520                                 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
9521                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9522
9523                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, addr->dreg, 0);
9524                                 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
9525                                         if (!cmethod->klass->element_class->valuetype && !readonly)
9526                                                 mini_emit_check_array_type (cfg, sp [0], cmethod->klass);
9527                                         CHECK_TYPELOAD (cmethod->klass);
9528                                         
9529                                         readonly = FALSE;
9530                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9531                                         ins = addr;
9532                                 } else {
9533                                         g_assert_not_reached ();
9534                                 }
9535
9536                                 emit_widen = FALSE;
9537                                 goto call_end;
9538                         }
9539
9540                         ins = mini_redirect_call (cfg, cmethod, fsig, sp, virtual ? sp [0] : NULL);
9541                         if (ins)
9542                                 goto call_end;
9543
9544                         /* Tail prefix / tail call optimization */
9545
9546                         /* FIXME: Enabling TAILC breaks some inlining/stack trace/etc tests */
9547                         /* FIXME: runtime generic context pointer for jumps? */
9548                         /* FIXME: handle this for generic sharing eventually */
9549                         if ((ins_flag & MONO_INST_TAILCALL) &&
9550                                 !vtable_arg && !cfg->gshared && is_supported_tail_call (cfg, method, cmethod, fsig, call_opcode))
9551                                 supported_tail_call = TRUE;
9552
9553                         if (supported_tail_call) {
9554                                 MonoCallInst *call;
9555
9556                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9557                                 INLINE_FAILURE ("tail call");
9558
9559                                 //printf ("HIT: %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
9560
9561                                 if (cfg->backend->have_op_tail_call) {
9562                                         /* Handle tail calls similarly to normal calls */
9563                                         tail_call = TRUE;
9564                                 } else {
9565                                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
9566
9567                                         MONO_INST_NEW_CALL (cfg, call, OP_JMP);
9568                                         call->tail_call = TRUE;
9569                                         call->method = cmethod;
9570                                         call->signature = mono_method_signature (cmethod);
9571
9572                                         /*
9573                                          * We implement tail calls by storing the actual arguments into the 
9574                                          * argument variables, then emitting a CEE_JMP.
9575                                          */
9576                                         for (i = 0; i < n; ++i) {
9577                                                 /* Prevent argument from being register allocated */
9578                                                 arg_array [i]->flags |= MONO_INST_VOLATILE;
9579                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9580                                         }
9581                                         ins = (MonoInst*)call;
9582                                         ins->inst_p0 = cmethod;
9583                                         ins->inst_p1 = arg_array [0];
9584                                         MONO_ADD_INS (cfg->cbb, ins);
9585                                         link_bblock (cfg, cfg->cbb, end_bblock);
9586                                         start_new_bblock = 1;
9587
9588                                         // FIXME: Eliminate unreachable epilogs
9589
9590                                         /*
9591                                          * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9592                                          * only reachable from this call.
9593                                          */
9594                                         GET_BBLOCK (cfg, tblock, ip + 5);
9595                                         if (tblock == cfg->cbb || tblock->in_count == 0)
9596                                                 skip_ret = TRUE;
9597                                         push_res = FALSE;
9598
9599                                         goto call_end;
9600                                 }
9601                         }
9602
9603                         /* 
9604                          * Synchronized wrappers.
9605                          * Its hard to determine where to replace a method with its synchronized
9606                          * wrapper without causing an infinite recursion. The current solution is
9607                          * to add the synchronized wrapper in the trampolines, and to
9608                          * change the called method to a dummy wrapper, and resolve that wrapper
9609                          * to the real method in mono_jit_compile_method ().
9610                          */
9611                         if (cfg->method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
9612                                 MonoMethod *orig = mono_marshal_method_from_wrapper (cfg->method);
9613                                 if (cmethod == orig || (cmethod->is_inflated && mono_method_get_declaring_generic_method (cmethod) == orig))
9614                                         cmethod = mono_marshal_get_synchronized_inner_wrapper (cmethod);
9615                         }
9616
9617                         /*
9618                          * Interface calls in llvm-only mode are complicated becase the callee might need an rgctx arg,
9619                          * (i.e. its a vtype method), and there is no way to for the caller to know this at compile time.
9620                          * So we make resolve_iface_call return the rgctx, and do two calls with different signatures
9621                          * based on whenever there is an rgctx or not.
9622                          */
9623                         if (cfg->llvm_only && virtual && cmethod && (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
9624                                 MonoInst *args_buf [16], *icall_args [16];
9625                                 MonoInst **args;
9626                                 MonoBasicBlock *rgctx_bb, *end_bb;
9627                                 MonoInst *call1, *call2, *call_target;
9628                                 MonoMethodSignature *rgctx_sig;
9629                                 int rgctx_reg, tmp_reg;
9630
9631                                 MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
9632
9633                                 NEW_BBLOCK (cfg, rgctx_bb);
9634                                 NEW_BBLOCK (cfg, end_bb);
9635
9636                                 // FIXME: Optimize this
9637
9638                                 guint32 imt_slot = mono_method_get_imt_slot (cmethod);
9639
9640                                 icall_args [0] = sp [0];
9641                                 EMIT_NEW_ICONST (cfg, icall_args [1], imt_slot);
9642                                 if (imt_arg) {
9643                                         icall_args [2] = imt_arg;
9644                                 } else {
9645                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_METHODCONST, cmethod);
9646                                         icall_args [2] = ins;
9647                                 }
9648
9649                                 rgctx_reg = alloc_preg (cfg);
9650                                 MONO_EMIT_NEW_PCONST (cfg, rgctx_reg, NULL);
9651                                 EMIT_NEW_VARLOADA_VREG (cfg, icall_args [3], rgctx_reg, &mono_defaults.int_class->byval_arg);
9652                                 //EMIT_NEW_PCONST (cfg, icall_args [3], NULL);
9653
9654                                 call_target = mono_emit_jit_icall (cfg, mono_resolve_iface_call, icall_args);
9655
9656                                 // FIXME: Only do this if needed (generic calls)
9657
9658                                 // Check whenever to pass an rgctx
9659                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rgctx_reg, 0);
9660                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, rgctx_bb);
9661                                 /* Non rgctx case */
9662                                 call1 = mono_emit_calli (cfg, fsig, sp, call_target, NULL, vtable_arg);
9663                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
9664                                 /* Rgctx case */
9665                                 MONO_START_BB (cfg, rgctx_bb);
9666                                 /* Make a call with an rgctx */
9667                                 if (fsig->param_count + 2 < 16)
9668                                         args = args_buf;
9669                                 else
9670                                         args = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (fsig->param_count + 2));
9671                                 args [0] = sp [0];
9672                                 for (i = 0; i < fsig->param_count; ++i)
9673                                         args [i + 1] = sp [i + 1];
9674                                 tmp_reg = alloc_preg (cfg);
9675                                 EMIT_NEW_UNALU (cfg, args [fsig->param_count + 1], OP_MOVE, tmp_reg, rgctx_reg);
9676                                 rgctx_sig = sig_to_rgctx_sig (fsig);
9677                                 call2 = mono_emit_calli (cfg, rgctx_sig, args, call_target, NULL, NULL);
9678                                 call2->dreg = call1->dreg;
9679                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
9680                                 /* End */
9681                                 MONO_START_BB (cfg, end_bb);
9682                                 ins = call1;
9683                                 goto call_end;
9684                         }
9685
9686                         /* Common call */
9687                         INLINE_FAILURE ("call");
9688                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, tail_call, sp, virtual ? sp [0] : NULL,
9689                                                                                           imt_arg, vtable_arg);
9690
9691                         if (tail_call && !cfg->llvm_only) {
9692                                 link_bblock (cfg, cfg->cbb, end_bblock);
9693                                 start_new_bblock = 1;
9694
9695                                 // FIXME: Eliminate unreachable epilogs
9696
9697                                 /*
9698                                  * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9699                                  * only reachable from this call.
9700                                  */
9701                                 GET_BBLOCK (cfg, tblock, ip + 5);
9702                                 if (tblock == cfg->cbb || tblock->in_count == 0)
9703                                         skip_ret = TRUE;
9704                                 push_res = FALSE;
9705                         }
9706
9707                         call_end:
9708
9709                         /* End of call, INS should contain the result of the call, if any */
9710
9711                         if (push_res && !MONO_TYPE_IS_VOID (fsig->ret)) {
9712                                 g_assert (ins);
9713                                 if (emit_widen)
9714                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
9715                                 else
9716                                         *sp++ = ins;
9717                         }
9718
9719                         if (keep_this_alive) {
9720                                 MonoInst *dummy_use;
9721
9722                                 /* See mono_emit_method_call_full () */
9723                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, keep_this_alive);
9724                         }
9725
9726                         CHECK_CFG_EXCEPTION;
9727
9728                         ip += 5;
9729                         if (skip_ret) {
9730                                 g_assert (*ip == CEE_RET);
9731                                 ip += 1;
9732                         }
9733                         ins_flag = 0;
9734                         constrained_class = NULL;
9735                         if (need_seq_point)
9736                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
9737                         break;
9738                 }
9739                 case CEE_RET:
9740                         if (cfg->method != method) {
9741                                 /* return from inlined method */
9742                                 /* 
9743                                  * If in_count == 0, that means the ret is unreachable due to
9744                                  * being preceeded by a throw. In that case, inline_method () will
9745                                  * handle setting the return value 
9746                                  * (test case: test_0_inline_throw ()).
9747                                  */
9748                                 if (return_var && cfg->cbb->in_count) {
9749                                         MonoType *ret_type = mono_method_signature (method)->ret;
9750
9751                                         MonoInst *store;
9752                                         CHECK_STACK (1);
9753                                         --sp;
9754
9755                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
9756                                                 UNVERIFIED;
9757
9758                                         //g_assert (returnvar != -1);
9759                                         EMIT_NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
9760                                         cfg->ret_var_set = TRUE;
9761                                 } 
9762                         } else {
9763                                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
9764
9765                                 if (cfg->lmf_var && cfg->cbb->in_count && !cfg->llvm_only)
9766                                         emit_pop_lmf (cfg);
9767
9768                                 if (cfg->ret) {
9769                                         MonoType *ret_type = mini_get_underlying_type (mono_method_signature (method)->ret);
9770
9771                                         if (seq_points && !sym_seq_points) {
9772                                                 /* 
9773                                                  * Place a seq point here too even through the IL stack is not
9774                                                  * empty, so a step over on
9775                                                  * call <FOO>
9776                                                  * ret
9777                                                  * will work correctly.
9778                                                  */
9779                                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, TRUE);
9780                                                 MONO_ADD_INS (cfg->cbb, ins);
9781                                         }
9782
9783                                         g_assert (!return_var);
9784                                         CHECK_STACK (1);
9785                                         --sp;
9786
9787                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
9788                                                 UNVERIFIED;
9789
9790                                         emit_setret (cfg, *sp);
9791                                 }
9792                         }
9793                         if (sp != stack_start)
9794                                 UNVERIFIED;
9795                         MONO_INST_NEW (cfg, ins, OP_BR);
9796                         ip++;
9797                         ins->inst_target_bb = end_bblock;
9798                         MONO_ADD_INS (cfg->cbb, ins);
9799                         link_bblock (cfg, cfg->cbb, end_bblock);
9800                         start_new_bblock = 1;
9801                         break;
9802                 case CEE_BR_S:
9803                         CHECK_OPSIZE (2);
9804                         MONO_INST_NEW (cfg, ins, OP_BR);
9805                         ip++;
9806                         target = ip + 1 + (signed char)(*ip);
9807                         ++ip;
9808                         GET_BBLOCK (cfg, tblock, target);
9809                         link_bblock (cfg, cfg->cbb, tblock);
9810                         ins->inst_target_bb = tblock;
9811                         if (sp != stack_start) {
9812                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9813                                 sp = stack_start;
9814                                 CHECK_UNVERIFIABLE (cfg);
9815                         }
9816                         MONO_ADD_INS (cfg->cbb, ins);
9817                         start_new_bblock = 1;
9818                         inline_costs += BRANCH_COST;
9819                         break;
9820                 case CEE_BEQ_S:
9821                 case CEE_BGE_S:
9822                 case CEE_BGT_S:
9823                 case CEE_BLE_S:
9824                 case CEE_BLT_S:
9825                 case CEE_BNE_UN_S:
9826                 case CEE_BGE_UN_S:
9827                 case CEE_BGT_UN_S:
9828                 case CEE_BLE_UN_S:
9829                 case CEE_BLT_UN_S:
9830                         CHECK_OPSIZE (2);
9831                         CHECK_STACK (2);
9832                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
9833                         ip++;
9834                         target = ip + 1 + *(signed char*)ip;
9835                         ip++;
9836
9837                         ADD_BINCOND (NULL);
9838
9839                         sp = stack_start;
9840                         inline_costs += BRANCH_COST;
9841                         break;
9842                 case CEE_BR:
9843                         CHECK_OPSIZE (5);
9844                         MONO_INST_NEW (cfg, ins, OP_BR);
9845                         ip++;
9846
9847                         target = ip + 4 + (gint32)read32(ip);
9848                         ip += 4;
9849                         GET_BBLOCK (cfg, tblock, target);
9850                         link_bblock (cfg, cfg->cbb, tblock);
9851                         ins->inst_target_bb = tblock;
9852                         if (sp != stack_start) {
9853                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9854                                 sp = stack_start;
9855                                 CHECK_UNVERIFIABLE (cfg);
9856                         }
9857
9858                         MONO_ADD_INS (cfg->cbb, ins);
9859
9860                         start_new_bblock = 1;
9861                         inline_costs += BRANCH_COST;
9862                         break;
9863                 case CEE_BRFALSE_S:
9864                 case CEE_BRTRUE_S:
9865                 case CEE_BRFALSE:
9866                 case CEE_BRTRUE: {
9867                         MonoInst *cmp;
9868                         gboolean is_short = ((*ip) == CEE_BRFALSE_S) || ((*ip) == CEE_BRTRUE_S);
9869                         gboolean is_true = ((*ip) == CEE_BRTRUE_S) || ((*ip) == CEE_BRTRUE);
9870                         guint32 opsize = is_short ? 1 : 4;
9871
9872                         CHECK_OPSIZE (opsize);
9873                         CHECK_STACK (1);
9874                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
9875                                 UNVERIFIED;
9876                         ip ++;
9877                         target = ip + opsize + (is_short ? *(signed char*)ip : (gint32)read32(ip));
9878                         ip += opsize;
9879
9880                         sp--;
9881
9882                         GET_BBLOCK (cfg, tblock, target);
9883                         link_bblock (cfg, cfg->cbb, tblock);
9884                         GET_BBLOCK (cfg, tblock, ip);
9885                         link_bblock (cfg, cfg->cbb, tblock);
9886
9887                         if (sp != stack_start) {
9888                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9889                                 CHECK_UNVERIFIABLE (cfg);
9890                         }
9891
9892                         MONO_INST_NEW(cfg, cmp, OP_ICOMPARE_IMM);
9893                         cmp->sreg1 = sp [0]->dreg;
9894                         type_from_op (cfg, cmp, sp [0], NULL);
9895                         CHECK_TYPE (cmp);
9896
9897 #if SIZEOF_REGISTER == 4
9898                         if (cmp->opcode == OP_LCOMPARE_IMM) {
9899                                 /* Convert it to OP_LCOMPARE */
9900                                 MONO_INST_NEW (cfg, ins, OP_I8CONST);
9901                                 ins->type = STACK_I8;
9902                                 ins->dreg = alloc_dreg (cfg, STACK_I8);
9903                                 ins->inst_l = 0;
9904                                 MONO_ADD_INS (cfg->cbb, ins);
9905                                 cmp->opcode = OP_LCOMPARE;
9906                                 cmp->sreg2 = ins->dreg;
9907                         }
9908 #endif
9909                         MONO_ADD_INS (cfg->cbb, cmp);
9910
9911                         MONO_INST_NEW (cfg, ins, is_true ? CEE_BNE_UN : CEE_BEQ);
9912                         type_from_op (cfg, ins, sp [0], NULL);
9913                         MONO_ADD_INS (cfg->cbb, ins);
9914                         ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);
9915                         GET_BBLOCK (cfg, tblock, target);
9916                         ins->inst_true_bb = tblock;
9917                         GET_BBLOCK (cfg, tblock, ip);
9918                         ins->inst_false_bb = tblock;
9919                         start_new_bblock = 2;
9920
9921                         sp = stack_start;
9922                         inline_costs += BRANCH_COST;
9923                         break;
9924                 }
9925                 case CEE_BEQ:
9926                 case CEE_BGE:
9927                 case CEE_BGT:
9928                 case CEE_BLE:
9929                 case CEE_BLT:
9930                 case CEE_BNE_UN:
9931                 case CEE_BGE_UN:
9932                 case CEE_BGT_UN:
9933                 case CEE_BLE_UN:
9934                 case CEE_BLT_UN:
9935                         CHECK_OPSIZE (5);
9936                         CHECK_STACK (2);
9937                         MONO_INST_NEW (cfg, ins, *ip);
9938                         ip++;
9939                         target = ip + 4 + (gint32)read32(ip);
9940                         ip += 4;
9941
9942                         ADD_BINCOND (NULL);
9943
9944                         sp = stack_start;
9945                         inline_costs += BRANCH_COST;
9946                         break;
9947                 case CEE_SWITCH: {
9948                         MonoInst *src1;
9949                         MonoBasicBlock **targets;
9950                         MonoBasicBlock *default_bblock;
9951                         MonoJumpInfoBBTable *table;
9952                         int offset_reg = alloc_preg (cfg);
9953                         int target_reg = alloc_preg (cfg);
9954                         int table_reg = alloc_preg (cfg);
9955                         int sum_reg = alloc_preg (cfg);
9956                         gboolean use_op_switch;
9957
9958                         CHECK_OPSIZE (5);
9959                         CHECK_STACK (1);
9960                         n = read32 (ip + 1);
9961                         --sp;
9962                         src1 = sp [0];
9963                         if ((src1->type != STACK_I4) && (src1->type != STACK_PTR)) 
9964                                 UNVERIFIED;
9965
9966                         ip += 5;
9967                         CHECK_OPSIZE (n * sizeof (guint32));
9968                         target = ip + n * sizeof (guint32);
9969
9970                         GET_BBLOCK (cfg, default_bblock, target);
9971                         default_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
9972
9973                         targets = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * n);
9974                         for (i = 0; i < n; ++i) {
9975                                 GET_BBLOCK (cfg, tblock, target + (gint32)read32(ip));
9976                                 targets [i] = tblock;
9977                                 targets [i]->flags |= BB_INDIRECT_JUMP_TARGET;
9978                                 ip += 4;
9979                         }
9980
9981                         if (sp != stack_start) {
9982                                 /* 
9983                                  * Link the current bb with the targets as well, so handle_stack_args
9984                                  * will set their in_stack correctly.
9985                                  */
9986                                 link_bblock (cfg, cfg->cbb, default_bblock);
9987                                 for (i = 0; i < n; ++i)
9988                                         link_bblock (cfg, cfg->cbb, targets [i]);
9989
9990                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9991                                 sp = stack_start;
9992                                 CHECK_UNVERIFIABLE (cfg);
9993
9994                                 /* Undo the links */
9995                                 mono_unlink_bblock (cfg, cfg->cbb, default_bblock);
9996                                 for (i = 0; i < n; ++i)
9997                                         mono_unlink_bblock (cfg, cfg->cbb, targets [i]);
9998                         }
9999
10000                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, src1->dreg, n);
10001                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBGE_UN, default_bblock);
10002
10003                         for (i = 0; i < n; ++i)
10004                                 link_bblock (cfg, cfg->cbb, targets [i]);
10005
10006                         table = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
10007                         table->table = targets;
10008                         table->table_size = n;
10009
10010                         use_op_switch = FALSE;
10011 #ifdef TARGET_ARM
10012                         /* ARM implements SWITCH statements differently */
10013                         /* FIXME: Make it use the generic implementation */
10014                         if (!cfg->compile_aot)
10015                                 use_op_switch = TRUE;
10016 #endif
10017
10018                         if (COMPILE_LLVM (cfg))
10019                                 use_op_switch = TRUE;
10020
10021                         cfg->cbb->has_jump_table = 1;
10022
10023                         if (use_op_switch) {
10024                                 MONO_INST_NEW (cfg, ins, OP_SWITCH);
10025                                 ins->sreg1 = src1->dreg;
10026                                 ins->inst_p0 = table;
10027                                 ins->inst_many_bb = targets;
10028                                 ins->klass = GUINT_TO_POINTER (n);
10029                                 MONO_ADD_INS (cfg->cbb, ins);
10030                         } else {
10031                                 if (sizeof (gpointer) == 8)
10032                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 3);
10033                                 else
10034                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 2);
10035
10036 #if SIZEOF_REGISTER == 8
10037                                 /* The upper word might not be zero, and we add it to a 64 bit address later */
10038                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, offset_reg, offset_reg);
10039 #endif
10040
10041                                 if (cfg->compile_aot) {
10042                                         MONO_EMIT_NEW_AOTCONST (cfg, table_reg, table, MONO_PATCH_INFO_SWITCH);
10043                                 } else {
10044                                         MONO_INST_NEW (cfg, ins, OP_JUMP_TABLE);
10045                                         ins->inst_c1 = MONO_PATCH_INFO_SWITCH;
10046                                         ins->inst_p0 = table;
10047                                         ins->dreg = table_reg;
10048                                         MONO_ADD_INS (cfg->cbb, ins);
10049                                 }
10050
10051                                 /* FIXME: Use load_memindex */
10052                                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, table_reg, offset_reg);
10053                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, target_reg, sum_reg, 0);
10054                                 MONO_EMIT_NEW_UNALU (cfg, OP_BR_REG, -1, target_reg);
10055                         }
10056                         start_new_bblock = 1;
10057                         inline_costs += (BRANCH_COST * 2);
10058                         break;
10059                 }
10060                 case CEE_LDIND_I1:
10061                 case CEE_LDIND_U1:
10062                 case CEE_LDIND_I2:
10063                 case CEE_LDIND_U2:
10064                 case CEE_LDIND_I4:
10065                 case CEE_LDIND_U4:
10066                 case CEE_LDIND_I8:
10067                 case CEE_LDIND_I:
10068                 case CEE_LDIND_R4:
10069                 case CEE_LDIND_R8:
10070                 case CEE_LDIND_REF:
10071                         CHECK_STACK (1);
10072                         --sp;
10073
10074                         switch (*ip) {
10075                         case CEE_LDIND_R4:
10076                         case CEE_LDIND_R8:
10077                                 dreg = alloc_freg (cfg);
10078                                 break;
10079                         case CEE_LDIND_I8:
10080                                 dreg = alloc_lreg (cfg);
10081                                 break;
10082                         case CEE_LDIND_REF:
10083                                 dreg = alloc_ireg_ref (cfg);
10084                                 break;
10085                         default:
10086                                 dreg = alloc_preg (cfg);
10087                         }
10088
10089                         NEW_LOAD_MEMBASE (cfg, ins, ldind_to_load_membase (*ip), dreg, sp [0]->dreg, 0);
10090                         ins->type = ldind_type [*ip - CEE_LDIND_I1];
10091                         if (*ip == CEE_LDIND_R4)
10092                                 ins->type = cfg->r4_stack_type;
10093                         ins->flags |= ins_flag;
10094                         MONO_ADD_INS (cfg->cbb, ins);
10095                         *sp++ = ins;
10096                         if (ins_flag & MONO_INST_VOLATILE) {
10097                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10098                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10099                         }
10100                         ins_flag = 0;
10101                         ++ip;
10102                         break;
10103                 case CEE_STIND_REF:
10104                 case CEE_STIND_I1:
10105                 case CEE_STIND_I2:
10106                 case CEE_STIND_I4:
10107                 case CEE_STIND_I8:
10108                 case CEE_STIND_R4:
10109                 case CEE_STIND_R8:
10110                 case CEE_STIND_I:
10111                         CHECK_STACK (2);
10112                         sp -= 2;
10113
10114                         if (ins_flag & MONO_INST_VOLATILE) {
10115                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
10116                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
10117                         }
10118
10119                         NEW_STORE_MEMBASE (cfg, ins, stind_to_store_membase (*ip), sp [0]->dreg, 0, sp [1]->dreg);
10120                         ins->flags |= ins_flag;
10121                         ins_flag = 0;
10122
10123                         MONO_ADD_INS (cfg->cbb, ins);
10124
10125                         if (cfg->gen_write_barriers && *ip == CEE_STIND_REF && method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER && !((sp [1]->opcode == OP_PCONST) && (sp [1]->inst_p0 == 0)))
10126                                 emit_write_barrier (cfg, sp [0], sp [1]);
10127
10128                         inline_costs += 1;
10129                         ++ip;
10130                         break;
10131
10132                 case CEE_MUL:
10133                         CHECK_STACK (2);
10134
10135                         MONO_INST_NEW (cfg, ins, (*ip));
10136                         sp -= 2;
10137                         ins->sreg1 = sp [0]->dreg;
10138                         ins->sreg2 = sp [1]->dreg;
10139                         type_from_op (cfg, ins, sp [0], sp [1]);
10140                         CHECK_TYPE (ins);
10141                         ins->dreg = alloc_dreg ((cfg), (ins)->type);
10142
10143                         /* Use the immediate opcodes if possible */
10144                         if ((sp [1]->opcode == OP_ICONST) && mono_arch_is_inst_imm (sp [1]->inst_c0)) {
10145                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
10146                                 if (imm_opcode != -1) {
10147                                         ins->opcode = imm_opcode;
10148                                         ins->inst_p1 = (gpointer)(gssize)(sp [1]->inst_c0);
10149                                         ins->sreg2 = -1;
10150
10151                                         NULLIFY_INS (sp [1]);
10152                                 }
10153                         }
10154
10155                         MONO_ADD_INS ((cfg)->cbb, (ins));
10156
10157                         *sp++ = mono_decompose_opcode (cfg, ins);
10158                         ip++;
10159                         break;
10160                 case CEE_ADD:
10161                 case CEE_SUB:
10162                 case CEE_DIV:
10163                 case CEE_DIV_UN:
10164                 case CEE_REM:
10165                 case CEE_REM_UN:
10166                 case CEE_AND:
10167                 case CEE_OR:
10168                 case CEE_XOR:
10169                 case CEE_SHL:
10170                 case CEE_SHR:
10171                 case CEE_SHR_UN:
10172                         CHECK_STACK (2);
10173
10174                         MONO_INST_NEW (cfg, ins, (*ip));
10175                         sp -= 2;
10176                         ins->sreg1 = sp [0]->dreg;
10177                         ins->sreg2 = sp [1]->dreg;
10178                         type_from_op (cfg, ins, sp [0], sp [1]);
10179                         CHECK_TYPE (ins);
10180                         add_widen_op (cfg, ins, &sp [0], &sp [1]);
10181                         ins->dreg = alloc_dreg ((cfg), (ins)->type);
10182
10183                         /* FIXME: Pass opcode to is_inst_imm */
10184
10185                         /* Use the immediate opcodes if possible */
10186                         if (((sp [1]->opcode == OP_ICONST) || (sp [1]->opcode == OP_I8CONST)) && mono_arch_is_inst_imm (sp [1]->opcode == OP_ICONST ? sp [1]->inst_c0 : sp [1]->inst_l)) {
10187                                 int imm_opcode;
10188
10189                                 imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
10190 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
10191                                 /* Keep emulated opcodes which are optimized away later */
10192                                 if ((ins->opcode == OP_IREM_UN || ins->opcode == OP_IDIV_UN_IMM) && (cfg->opt & (MONO_OPT_CONSPROP | MONO_OPT_COPYPROP)) && sp [1]->opcode == OP_ICONST && mono_is_power_of_two (sp [1]->inst_c0) >= 0) {
10193                                         imm_opcode = mono_op_to_op_imm (ins->opcode);
10194                                 }
10195 #endif
10196                                 if (imm_opcode != -1) {
10197                                         ins->opcode = imm_opcode;
10198                                         if (sp [1]->opcode == OP_I8CONST) {
10199 #if SIZEOF_REGISTER == 8
10200                                                 ins->inst_imm = sp [1]->inst_l;
10201 #else
10202                                                 ins->inst_ls_word = sp [1]->inst_ls_word;
10203                                                 ins->inst_ms_word = sp [1]->inst_ms_word;
10204 #endif
10205                                         }
10206                                         else
10207                                                 ins->inst_imm = (gssize)(sp [1]->inst_c0);
10208                                         ins->sreg2 = -1;
10209
10210                                         /* Might be followed by an instruction added by add_widen_op */
10211                                         if (sp [1]->next == NULL)
10212                                                 NULLIFY_INS (sp [1]);
10213                                 }
10214                         }
10215                         MONO_ADD_INS ((cfg)->cbb, (ins));
10216
10217                         *sp++ = mono_decompose_opcode (cfg, ins);
10218                         ip++;
10219                         break;
10220                 case CEE_NEG:
10221                 case CEE_NOT:
10222                 case CEE_CONV_I1:
10223                 case CEE_CONV_I2:
10224                 case CEE_CONV_I4:
10225                 case CEE_CONV_R4:
10226                 case CEE_CONV_R8:
10227                 case CEE_CONV_U4:
10228                 case CEE_CONV_I8:
10229                 case CEE_CONV_U8:
10230                 case CEE_CONV_OVF_I8:
10231                 case CEE_CONV_OVF_U8:
10232                 case CEE_CONV_R_UN:
10233                         CHECK_STACK (1);
10234
10235                         /* Special case this earlier so we have long constants in the IR */
10236                         if ((((*ip) == CEE_CONV_I8) || ((*ip) == CEE_CONV_U8)) && (sp [-1]->opcode == OP_ICONST)) {
10237                                 int data = sp [-1]->inst_c0;
10238                                 sp [-1]->opcode = OP_I8CONST;
10239                                 sp [-1]->type = STACK_I8;
10240 #if SIZEOF_REGISTER == 8
10241                                 if ((*ip) == CEE_CONV_U8)
10242                                         sp [-1]->inst_c0 = (guint32)data;
10243                                 else
10244                                         sp [-1]->inst_c0 = data;
10245 #else
10246                                 sp [-1]->inst_ls_word = data;
10247                                 if ((*ip) == CEE_CONV_U8)
10248                                         sp [-1]->inst_ms_word = 0;
10249                                 else
10250                                         sp [-1]->inst_ms_word = (data < 0) ? -1 : 0;
10251 #endif
10252                                 sp [-1]->dreg = alloc_dreg (cfg, STACK_I8);
10253                         }
10254                         else {
10255                                 ADD_UNOP (*ip);
10256                         }
10257                         ip++;
10258                         break;
10259                 case CEE_CONV_OVF_I4:
10260                 case CEE_CONV_OVF_I1:
10261                 case CEE_CONV_OVF_I2:
10262                 case CEE_CONV_OVF_I:
10263                 case CEE_CONV_OVF_U:
10264                         CHECK_STACK (1);
10265
10266                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
10267                                 ADD_UNOP (CEE_CONV_OVF_I8);
10268                                 ADD_UNOP (*ip);
10269                         } else {
10270                                 ADD_UNOP (*ip);
10271                         }
10272                         ip++;
10273                         break;
10274                 case CEE_CONV_OVF_U1:
10275                 case CEE_CONV_OVF_U2:
10276                 case CEE_CONV_OVF_U4:
10277                         CHECK_STACK (1);
10278
10279                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
10280                                 ADD_UNOP (CEE_CONV_OVF_U8);
10281                                 ADD_UNOP (*ip);
10282                         } else {
10283                                 ADD_UNOP (*ip);
10284                         }
10285                         ip++;
10286                         break;
10287                 case CEE_CONV_OVF_I1_UN:
10288                 case CEE_CONV_OVF_I2_UN:
10289                 case CEE_CONV_OVF_I4_UN:
10290                 case CEE_CONV_OVF_I8_UN:
10291                 case CEE_CONV_OVF_U1_UN:
10292                 case CEE_CONV_OVF_U2_UN:
10293                 case CEE_CONV_OVF_U4_UN:
10294                 case CEE_CONV_OVF_U8_UN:
10295                 case CEE_CONV_OVF_I_UN:
10296                 case CEE_CONV_OVF_U_UN:
10297                 case CEE_CONV_U2:
10298                 case CEE_CONV_U1:
10299                 case CEE_CONV_I:
10300                 case CEE_CONV_U:
10301                         CHECK_STACK (1);
10302                         ADD_UNOP (*ip);
10303                         CHECK_CFG_EXCEPTION;
10304                         ip++;
10305                         break;
10306                 case CEE_ADD_OVF:
10307                 case CEE_ADD_OVF_UN:
10308                 case CEE_MUL_OVF:
10309                 case CEE_MUL_OVF_UN:
10310                 case CEE_SUB_OVF:
10311                 case CEE_SUB_OVF_UN:
10312                         CHECK_STACK (2);
10313                         ADD_BINOP (*ip);
10314                         ip++;
10315                         break;
10316                 case CEE_CPOBJ:
10317                         GSHAREDVT_FAILURE (*ip);
10318                         CHECK_OPSIZE (5);
10319                         CHECK_STACK (2);
10320                         token = read32 (ip + 1);
10321                         klass = mini_get_class (method, token, generic_context);
10322                         CHECK_TYPELOAD (klass);
10323                         sp -= 2;
10324                         if (generic_class_is_reference_type (cfg, klass)) {
10325                                 MonoInst *store, *load;
10326                                 int dreg = alloc_ireg_ref (cfg);
10327
10328                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, dreg, sp [1]->dreg, 0);
10329                                 load->flags |= ins_flag;
10330                                 MONO_ADD_INS (cfg->cbb, load);
10331
10332                                 NEW_STORE_MEMBASE (cfg, store, OP_STORE_MEMBASE_REG, sp [0]->dreg, 0, dreg);
10333                                 store->flags |= ins_flag;
10334                                 MONO_ADD_INS (cfg->cbb, store);
10335
10336                                 if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER)
10337                                         emit_write_barrier (cfg, sp [0], sp [1]);
10338                         } else {
10339                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
10340                         }
10341                         ins_flag = 0;
10342                         ip += 5;
10343                         break;
10344                 case CEE_LDOBJ: {
10345                         int loc_index = -1;
10346                         int stloc_len = 0;
10347
10348                         CHECK_OPSIZE (5);
10349                         CHECK_STACK (1);
10350                         --sp;
10351                         token = read32 (ip + 1);
10352                         klass = mini_get_class (method, token, generic_context);
10353                         CHECK_TYPELOAD (klass);
10354
10355                         /* Optimize the common ldobj+stloc combination */
10356                         switch (ip [5]) {
10357                         case CEE_STLOC_S:
10358                                 loc_index = ip [6];
10359                                 stloc_len = 2;
10360                                 break;
10361                         case CEE_STLOC_0:
10362                         case CEE_STLOC_1:
10363                         case CEE_STLOC_2:
10364                         case CEE_STLOC_3:
10365                                 loc_index = ip [5] - CEE_STLOC_0;
10366                                 stloc_len = 1;
10367                                 break;
10368                         default:
10369                                 break;
10370                         }
10371
10372                         if ((loc_index != -1) && ip_in_bb (cfg, cfg->cbb, ip + 5)) {
10373                                 CHECK_LOCAL (loc_index);
10374
10375                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10376                                 ins->dreg = cfg->locals [loc_index]->dreg;
10377                                 ins->flags |= ins_flag;
10378                                 ip += 5;
10379                                 ip += stloc_len;
10380                                 if (ins_flag & MONO_INST_VOLATILE) {
10381                                         /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10382                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10383                                 }
10384                                 ins_flag = 0;
10385                                 break;
10386                         }
10387
10388                         /* Optimize the ldobj+stobj combination */
10389                         /* The reference case ends up being a load+store anyway */
10390                         /* Skip this if the operation is volatile. */
10391                         if (((ip [5] == CEE_STOBJ) && ip_in_bb (cfg, cfg->cbb, ip + 5) && read32 (ip + 6) == token) && !generic_class_is_reference_type (cfg, klass) && !(ins_flag & MONO_INST_VOLATILE)) {
10392                                 CHECK_STACK (1);
10393
10394                                 sp --;
10395
10396                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
10397
10398                                 ip += 5 + 5;
10399                                 ins_flag = 0;
10400                                 break;
10401                         }
10402
10403                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10404                         ins->flags |= ins_flag;
10405                         *sp++ = ins;
10406
10407                         if (ins_flag & MONO_INST_VOLATILE) {
10408                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10409                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10410                         }
10411
10412                         ip += 5;
10413                         ins_flag = 0;
10414                         inline_costs += 1;
10415                         break;
10416                 }
10417                 case CEE_LDSTR:
10418                         CHECK_STACK_OVF (1);
10419                         CHECK_OPSIZE (5);
10420                         n = read32 (ip + 1);
10421
10422                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
10423                                 EMIT_NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
10424                                 ins->type = STACK_OBJ;
10425                                 *sp = ins;
10426                         }
10427                         else if (method->wrapper_type != MONO_WRAPPER_NONE) {
10428                                 MonoInst *iargs [1];
10429                                 char *str = mono_method_get_wrapper_data (method, n);
10430
10431                                 if (cfg->compile_aot)
10432                                         EMIT_NEW_LDSTRLITCONST (cfg, iargs [0], str);
10433                                 else
10434                                         EMIT_NEW_PCONST (cfg, iargs [0], str);
10435                                 *sp = mono_emit_jit_icall (cfg, mono_string_new_wrapper, iargs);
10436                         } else {
10437                                 if (cfg->opt & MONO_OPT_SHARED) {
10438                                         MonoInst *iargs [3];
10439
10440                                         if (cfg->compile_aot) {
10441                                                 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
10442                                         }
10443                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10444                                         EMIT_NEW_IMAGECONST (cfg, iargs [1], image);
10445                                         EMIT_NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
10446                                         *sp = mono_emit_jit_icall (cfg, mono_ldstr, iargs);
10447                                         mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
10448                                 } else {
10449                                         if (cfg->cbb->out_of_line) {
10450                                                 MonoInst *iargs [2];
10451
10452                                                 if (image == mono_defaults.corlib) {
10453                                                         /* 
10454                                                          * Avoid relocations in AOT and save some space by using a 
10455                                                          * version of helper_ldstr specialized to mscorlib.
10456                                                          */
10457                                                         EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (n));
10458                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr_mscorlib, iargs);
10459                                                 } else {
10460                                                         /* Avoid creating the string object */
10461                                                         EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
10462                                                         EMIT_NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n));
10463                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr, iargs);
10464                                                 }
10465                                         } 
10466                                         else
10467                                         if (cfg->compile_aot) {
10468                                                 NEW_LDSTRCONST (cfg, ins, image, n);
10469                                                 *sp = ins;
10470                                                 MONO_ADD_INS (cfg->cbb, ins);
10471                                         } 
10472                                         else {
10473                                                 NEW_PCONST (cfg, ins, NULL);
10474                                                 ins->type = STACK_OBJ;
10475                                                 ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
10476                                                 if (!ins->inst_p0)
10477                                                         OUT_OF_MEMORY_FAILURE;
10478
10479                                                 *sp = ins;
10480                                                 MONO_ADD_INS (cfg->cbb, ins);
10481                                         }
10482                                 }
10483                         }
10484
10485                         sp++;
10486                         ip += 5;
10487                         break;
10488                 case CEE_NEWOBJ: {
10489                         MonoInst *iargs [2];
10490                         MonoMethodSignature *fsig;
10491                         MonoInst this_ins;
10492                         MonoInst *alloc;
10493                         MonoInst *vtable_arg = NULL;
10494
10495                         CHECK_OPSIZE (5);
10496                         token = read32 (ip + 1);
10497                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
10498                         if (!cmethod || mono_loader_get_last_error ())
10499                                 LOAD_ERROR;
10500                         fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
10501                         CHECK_CFG_ERROR;
10502
10503                         mono_save_token_info (cfg, image, token, cmethod);
10504
10505                         if (!mono_class_init (cmethod->klass))
10506                                 TYPE_LOAD_ERROR (cmethod->klass);
10507
10508                         context_used = mini_method_check_context_used (cfg, cmethod);
10509
10510                         if (mono_security_core_clr_enabled ())
10511                                 ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
10512
10513                         if (cfg->gshared && cmethod && cmethod->klass != method->klass && cmethod->klass->generic_class && mono_method_is_generic_sharable (cmethod, TRUE) && mono_class_needs_cctor_run (cmethod->klass, method)) {
10514                                 emit_class_init (cfg, cmethod->klass);
10515                                 CHECK_TYPELOAD (cmethod->klass);
10516                         }
10517
10518                         /*
10519                         if (cfg->gsharedvt) {
10520                                 if (mini_is_gsharedvt_variable_signature (sig))
10521                                         GSHAREDVT_FAILURE (*ip);
10522                         }
10523                         */
10524
10525                         n = fsig->param_count;
10526                         CHECK_STACK (n);
10527
10528                         /* 
10529                          * Generate smaller code for the common newobj <exception> instruction in
10530                          * argument checking code.
10531                          */
10532                         if (cfg->cbb->out_of_line && cmethod->klass->image == mono_defaults.corlib &&
10533                                 is_exception_class (cmethod->klass) && n <= 2 &&
10534                                 ((n < 1) || (!fsig->params [0]->byref && fsig->params [0]->type == MONO_TYPE_STRING)) && 
10535                                 ((n < 2) || (!fsig->params [1]->byref && fsig->params [1]->type == MONO_TYPE_STRING))) {
10536                                 MonoInst *iargs [3];
10537
10538                                 sp -= n;
10539
10540                                 EMIT_NEW_ICONST (cfg, iargs [0], cmethod->klass->type_token);
10541                                 switch (n) {
10542                                 case 0:
10543                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_0, iargs);
10544                                         break;
10545                                 case 1:
10546                                         iargs [1] = sp [0];
10547                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_1, iargs);
10548                                         break;
10549                                 case 2:
10550                                         iargs [1] = sp [0];
10551                                         iargs [2] = sp [1];
10552                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_2, iargs);
10553                                         break;
10554                                 default:
10555                                         g_assert_not_reached ();
10556                                 }
10557
10558                                 ip += 5;
10559                                 inline_costs += 5;
10560                                 break;
10561                         }
10562
10563                         /* move the args to allow room for 'this' in the first position */
10564                         while (n--) {
10565                                 --sp;
10566                                 sp [1] = sp [0];
10567                         }
10568
10569                         /* check_call_signature () requires sp[0] to be set */
10570                         this_ins.type = STACK_OBJ;
10571                         sp [0] = &this_ins;
10572                         if (check_call_signature (cfg, fsig, sp))
10573                                 UNVERIFIED;
10574
10575                         iargs [0] = NULL;
10576
10577                         if (mini_class_is_system_array (cmethod->klass)) {
10578                                 *sp = emit_get_rgctx_method (cfg, context_used,
10579                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
10580
10581                                 /* Avoid varargs in the common case */
10582                                 if (fsig->param_count == 1)
10583                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_1, sp);
10584                                 else if (fsig->param_count == 2)
10585                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_2, sp);
10586                                 else if (fsig->param_count == 3)
10587                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_3, sp);
10588                                 else if (fsig->param_count == 4)
10589                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_4, sp);
10590                                 else
10591                                         alloc = handle_array_new (cfg, fsig->param_count, sp, ip);
10592                         } else if (cmethod->string_ctor) {
10593                                 g_assert (!context_used);
10594                                 g_assert (!vtable_arg);
10595                                 /* we simply pass a null pointer */
10596                                 EMIT_NEW_PCONST (cfg, *sp, NULL); 
10597                                 /* now call the string ctor */
10598                                 alloc = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, NULL, NULL, NULL);
10599                         } else {
10600                                 if (cmethod->klass->valuetype) {
10601                                         iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
10602                                         emit_init_rvar (cfg, iargs [0]->dreg, &cmethod->klass->byval_arg);
10603                                         EMIT_NEW_TEMPLOADA (cfg, *sp, iargs [0]->inst_c0);
10604
10605                                         alloc = NULL;
10606
10607                                         /* 
10608                                          * The code generated by mini_emit_virtual_call () expects
10609                                          * iargs [0] to be a boxed instance, but luckily the vcall
10610                                          * will be transformed into a normal call there.
10611                                          */
10612                                 } else if (context_used) {
10613                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, context_used);
10614                                         *sp = alloc;
10615                                 } else {
10616                                         MonoVTable *vtable = NULL;
10617
10618                                         if (!cfg->compile_aot)
10619                                                 vtable = mono_class_vtable (cfg->domain, cmethod->klass);
10620                                         CHECK_TYPELOAD (cmethod->klass);
10621
10622                                         /*
10623                                          * TypeInitializationExceptions thrown from the mono_runtime_class_init
10624                                          * call in mono_jit_runtime_invoke () can abort the finalizer thread.
10625                                          * As a workaround, we call class cctors before allocating objects.
10626                                          */
10627                                         if (mini_field_access_needs_cctor_run (cfg, method, cmethod->klass, vtable) && !(g_slist_find (class_inits, cmethod->klass))) {
10628                                                 emit_class_init (cfg, cmethod->klass);
10629                                                 if (cfg->verbose_level > 2)
10630                                                         printf ("class %s.%s needs init call for ctor\n", cmethod->klass->name_space, cmethod->klass->name);
10631                                                 class_inits = g_slist_prepend (class_inits, cmethod->klass);
10632                                         }
10633
10634                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, 0);
10635                                         *sp = alloc;
10636                                 }
10637                                 CHECK_CFG_EXCEPTION; /*for handle_alloc*/
10638
10639                                 if (alloc)
10640                                         MONO_EMIT_NEW_UNALU (cfg, OP_NOT_NULL, -1, alloc->dreg);
10641
10642                                 /* Now call the actual ctor */
10643                                 handle_ctor_call (cfg, cmethod, fsig, context_used, sp, ip, &inline_costs);
10644                                 CHECK_CFG_EXCEPTION;
10645                         }
10646
10647                         if (alloc == NULL) {
10648                                 /* Valuetype */
10649                                 EMIT_NEW_TEMPLOAD (cfg, ins, iargs [0]->inst_c0);
10650                                 type_to_eval_stack_type (cfg, &ins->klass->byval_arg, ins);
10651                                 *sp++= ins;
10652                         } else {
10653                                 *sp++ = alloc;
10654                         }
10655                         
10656                         ip += 5;
10657                         inline_costs += 5;
10658                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip - header->code)))
10659                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
10660                         break;
10661                 }
10662                 case CEE_CASTCLASS:
10663                         CHECK_STACK (1);
10664                         --sp;
10665                         CHECK_OPSIZE (5);
10666                         token = read32 (ip + 1);
10667                         klass = mini_get_class (method, token, generic_context);
10668                         CHECK_TYPELOAD (klass);
10669                         if (sp [0]->type != STACK_OBJ)
10670                                 UNVERIFIED;
10671
10672                         ins = handle_castclass (cfg, klass, *sp, ip, &inline_costs);
10673                         CHECK_CFG_EXCEPTION;
10674
10675                         *sp ++ = ins;
10676                         ip += 5;
10677                         break;
10678                 case CEE_ISINST: {
10679                         CHECK_STACK (1);
10680                         --sp;
10681                         CHECK_OPSIZE (5);
10682                         token = read32 (ip + 1);
10683                         klass = mini_get_class (method, token, generic_context);
10684                         CHECK_TYPELOAD (klass);
10685                         if (sp [0]->type != STACK_OBJ)
10686                                 UNVERIFIED;
10687  
10688                         context_used = mini_class_check_context_used (cfg, klass);
10689
10690                         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
10691                                 MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
10692                                 MonoInst *args [3];
10693                                 int idx;
10694
10695                                 /* obj */
10696                                 args [0] = *sp;
10697
10698                                 /* klass */
10699                                 EMIT_NEW_CLASSCONST (cfg, args [1], klass);
10700
10701                                 /* inline cache*/
10702                                 idx = get_castclass_cache_idx (cfg);
10703                                 args [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
10704
10705                                 *sp++ = mono_emit_method_call (cfg, mono_isinst, args, NULL);
10706                                 ip += 5;
10707                                 inline_costs += 2;
10708                         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
10709                                 MonoMethod *mono_isinst;
10710                                 MonoInst *iargs [1];
10711                                 int costs;
10712
10713                                 mono_isinst = mono_marshal_get_isinst (klass); 
10714                                 iargs [0] = sp [0];
10715
10716                                 costs = inline_method (cfg, mono_isinst, mono_method_signature (mono_isinst), 
10717                                                                            iargs, ip, cfg->real_offset, TRUE);
10718                                 CHECK_CFG_EXCEPTION;
10719                                 g_assert (costs > 0);
10720                                 
10721                                 ip += 5;
10722                                 cfg->real_offset += 5;
10723
10724                                 *sp++= iargs [0];
10725
10726                                 inline_costs += costs;
10727                         }
10728                         else {
10729                                 ins = handle_isinst (cfg, klass, *sp, context_used);
10730                                 CHECK_CFG_EXCEPTION;
10731                                 *sp ++ = ins;
10732                                 ip += 5;
10733                         }
10734                         break;
10735                 }
10736                 case CEE_UNBOX_ANY: {
10737                         MonoInst *res, *addr;
10738
10739                         CHECK_STACK (1);
10740                         --sp;
10741                         CHECK_OPSIZE (5);
10742                         token = read32 (ip + 1);
10743                         klass = mini_get_class (method, token, generic_context);
10744                         CHECK_TYPELOAD (klass);
10745
10746                         mono_save_token_info (cfg, image, token, klass);
10747
10748                         context_used = mini_class_check_context_used (cfg, klass);
10749
10750                         if (mini_is_gsharedvt_klass (klass)) {
10751                                 res = handle_unbox_gsharedvt (cfg, klass, *sp);
10752                                 inline_costs += 2;
10753                         } else if (generic_class_is_reference_type (cfg, klass)) {
10754                                 res = handle_castclass (cfg, klass, *sp, ip, &inline_costs);
10755                                 CHECK_CFG_EXCEPTION;
10756                         } else if (mono_class_is_nullable (klass)) {
10757                                 res = handle_unbox_nullable (cfg, *sp, klass, context_used);
10758                         } else {
10759                                 addr = handle_unbox (cfg, klass, sp, context_used);
10760                                 /* LDOBJ */
10761                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
10762                                 res = ins;
10763                                 inline_costs += 2;
10764                         }
10765
10766                         *sp ++ = res;
10767                         ip += 5;
10768                         break;
10769                 }
10770                 case CEE_BOX: {
10771                         MonoInst *val;
10772                         MonoClass *enum_class;
10773                         MonoMethod *has_flag;
10774
10775                         CHECK_STACK (1);
10776                         --sp;
10777                         val = *sp;
10778                         CHECK_OPSIZE (5);
10779                         token = read32 (ip + 1);
10780                         klass = mini_get_class (method, token, generic_context);
10781                         CHECK_TYPELOAD (klass);
10782
10783                         mono_save_token_info (cfg, image, token, klass);
10784
10785                         context_used = mini_class_check_context_used (cfg, klass);
10786
10787                         if (generic_class_is_reference_type (cfg, klass)) {
10788                                 *sp++ = val;
10789                                 ip += 5;
10790                                 break;
10791                         }
10792
10793                         if (klass == mono_defaults.void_class)
10794                                 UNVERIFIED;
10795                         if (target_type_is_incompatible (cfg, &klass->byval_arg, *sp))
10796                                 UNVERIFIED;
10797                         /* frequent check in generic code: box (struct), brtrue */
10798
10799                         /*
10800                          * Look for:
10801                          *
10802                          *   <push int/long ptr>
10803                          *   <push int/long>
10804                          *   box MyFlags
10805                          *   constrained. MyFlags
10806                          *   callvirt instace bool class [mscorlib] System.Enum::HasFlag (class [mscorlib] System.Enum)
10807                          *
10808                          * If we find this sequence and the operand types on box and constrained
10809                          * are equal, we can emit a specialized instruction sequence instead of
10810                          * the very slow HasFlag () call.
10811                          */
10812                         if ((cfg->opt & MONO_OPT_INTRINS) &&
10813                             /* Cheap checks first. */
10814                             ip + 5 + 6 + 5 < end &&
10815                             ip [5] == CEE_PREFIX1 &&
10816                             ip [6] == CEE_CONSTRAINED_ &&
10817                             ip [11] == CEE_CALLVIRT &&
10818                             ip_in_bb (cfg, cfg->cbb, ip + 5 + 6 + 5) &&
10819                             mono_class_is_enum (klass) &&
10820                             (enum_class = mini_get_class (method, read32 (ip + 7), generic_context)) &&
10821                             (has_flag = mini_get_method (cfg, method, read32 (ip + 12), NULL, generic_context)) &&
10822                             has_flag->klass == mono_defaults.enum_class &&
10823                             !strcmp (has_flag->name, "HasFlag") &&
10824                             has_flag->signature->hasthis &&
10825                             has_flag->signature->param_count == 1) {
10826                                 CHECK_TYPELOAD (enum_class);
10827
10828                                 if (enum_class == klass) {
10829                                         MonoInst *enum_this, *enum_flag;
10830
10831                                         ip += 5 + 6 + 5;
10832                                         --sp;
10833
10834                                         enum_this = sp [0];
10835                                         enum_flag = sp [1];
10836
10837                                         *sp++ = handle_enum_has_flag (cfg, klass, enum_this, enum_flag);
10838                                         break;
10839                                 }
10840                         }
10841
10842                         // FIXME: LLVM can't handle the inconsistent bb linking
10843                         if (!mono_class_is_nullable (klass) &&
10844                                 !mini_is_gsharedvt_klass (klass) &&
10845                                 ip + 5 < end && ip_in_bb (cfg, cfg->cbb, ip + 5) &&
10846                                 (ip [5] == CEE_BRTRUE || 
10847                                  ip [5] == CEE_BRTRUE_S ||
10848                                  ip [5] == CEE_BRFALSE ||
10849                                  ip [5] == CEE_BRFALSE_S)) {
10850                                 gboolean is_true = ip [5] == CEE_BRTRUE || ip [5] == CEE_BRTRUE_S;
10851                                 int dreg;
10852                                 MonoBasicBlock *true_bb, *false_bb;
10853
10854                                 ip += 5;
10855
10856                                 if (cfg->verbose_level > 3) {
10857                                         printf ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
10858                                         printf ("<box+brtrue opt>\n");
10859                                 }
10860
10861                                 switch (*ip) {
10862                                 case CEE_BRTRUE_S:
10863                                 case CEE_BRFALSE_S:
10864                                         CHECK_OPSIZE (2);
10865                                         ip++;
10866                                         target = ip + 1 + (signed char)(*ip);
10867                                         ip++;
10868                                         break;
10869                                 case CEE_BRTRUE:
10870                                 case CEE_BRFALSE:
10871                                         CHECK_OPSIZE (5);
10872                                         ip++;
10873                                         target = ip + 4 + (gint)(read32 (ip));
10874                                         ip += 4;
10875                                         break;
10876                                 default:
10877                                         g_assert_not_reached ();
10878                                 }
10879
10880                                 /* 
10881                                  * We need to link both bblocks, since it is needed for handling stack
10882                                  * arguments correctly (See test_0_box_brtrue_opt_regress_81102).
10883                                  * Branching to only one of them would lead to inconsistencies, so
10884                                  * generate an ICONST+BRTRUE, the branch opts will get rid of them.
10885                                  */
10886                                 GET_BBLOCK (cfg, true_bb, target);
10887                                 GET_BBLOCK (cfg, false_bb, ip);
10888
10889                                 mono_link_bblock (cfg, cfg->cbb, true_bb);
10890                                 mono_link_bblock (cfg, cfg->cbb, false_bb);
10891
10892                                 if (sp != stack_start) {
10893                                         handle_stack_args (cfg, stack_start, sp - stack_start);
10894                                         sp = stack_start;
10895                                         CHECK_UNVERIFIABLE (cfg);
10896                                 }
10897
10898                                 if (COMPILE_LLVM (cfg)) {
10899                                         dreg = alloc_ireg (cfg);
10900                                         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
10901                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, dreg, is_true ? 0 : 1);
10902
10903                                         MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, OP_IBEQ, true_bb, false_bb);
10904                                 } else {
10905                                         /* The JIT can't eliminate the iconst+compare */
10906                                         MONO_INST_NEW (cfg, ins, OP_BR);
10907                                         ins->inst_target_bb = is_true ? true_bb : false_bb;
10908                                         MONO_ADD_INS (cfg->cbb, ins);
10909                                 }
10910
10911                                 start_new_bblock = 1;
10912                                 break;
10913                         }
10914
10915                         *sp++ = handle_box (cfg, val, klass, context_used);
10916
10917                         CHECK_CFG_EXCEPTION;
10918                         ip += 5;
10919                         inline_costs += 1;
10920                         break;
10921                 }
10922                 case CEE_UNBOX: {
10923                         CHECK_STACK (1);
10924                         --sp;
10925                         CHECK_OPSIZE (5);
10926                         token = read32 (ip + 1);
10927                         klass = mini_get_class (method, token, generic_context);
10928                         CHECK_TYPELOAD (klass);
10929
10930                         mono_save_token_info (cfg, image, token, klass);
10931
10932                         context_used = mini_class_check_context_used (cfg, klass);
10933
10934                         if (mono_class_is_nullable (klass)) {
10935                                 MonoInst *val;
10936
10937                                 val = handle_unbox_nullable (cfg, *sp, klass, context_used);
10938                                 EMIT_NEW_VARLOADA (cfg, ins, get_vreg_to_inst (cfg, val->dreg), &val->klass->byval_arg);
10939
10940                                 *sp++= ins;
10941                         } else {
10942                                 ins = handle_unbox (cfg, klass, sp, context_used);
10943                                 *sp++ = ins;
10944                         }
10945                         ip += 5;
10946                         inline_costs += 2;
10947                         break;
10948                 }
10949                 case CEE_LDFLD:
10950                 case CEE_LDFLDA:
10951                 case CEE_STFLD:
10952                 case CEE_LDSFLD:
10953                 case CEE_LDSFLDA:
10954                 case CEE_STSFLD: {
10955                         MonoClassField *field;
10956 #ifndef DISABLE_REMOTING
10957                         int costs;
10958 #endif
10959                         guint foffset;
10960                         gboolean is_instance;
10961                         int op;
10962                         gpointer addr = NULL;
10963                         gboolean is_special_static;
10964                         MonoType *ftype;
10965                         MonoInst *store_val = NULL;
10966                         MonoInst *thread_ins;
10967
10968                         op = *ip;
10969                         is_instance = (op == CEE_LDFLD || op == CEE_LDFLDA || op == CEE_STFLD);
10970                         if (is_instance) {
10971                                 if (op == CEE_STFLD) {
10972                                         CHECK_STACK (2);
10973                                         sp -= 2;
10974                                         store_val = sp [1];
10975                                 } else {
10976                                         CHECK_STACK (1);
10977                                         --sp;
10978                                 }
10979                                 if (sp [0]->type == STACK_I4 || sp [0]->type == STACK_I8 || sp [0]->type == STACK_R8)
10980                                         UNVERIFIED;
10981                                 if (*ip != CEE_LDFLD && sp [0]->type == STACK_VTYPE)
10982                                         UNVERIFIED;
10983                         } else {
10984                                 if (op == CEE_STSFLD) {
10985                                         CHECK_STACK (1);
10986                                         sp--;
10987                                         store_val = sp [0];
10988                                 }
10989                         }
10990
10991                         CHECK_OPSIZE (5);
10992                         token = read32 (ip + 1);
10993                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
10994                                 field = mono_method_get_wrapper_data (method, token);
10995                                 klass = field->parent;
10996                         }
10997                         else {
10998                                 field = mono_field_from_token_checked (image, token, &klass, generic_context, &cfg->error);
10999                                 CHECK_CFG_ERROR;
11000                         }
11001                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
11002                                 FIELD_ACCESS_FAILURE (method, field);
11003                         mono_class_init (klass);
11004
11005                         /* if the class is Critical then transparent code cannot access it's fields */
11006                         if (!is_instance && mono_security_core_clr_enabled ())
11007                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
11008
11009                         /* XXX this is technically required but, so far (SL2), no [SecurityCritical] types (not many exists) have
11010                            any visible *instance* field  (in fact there's a single case for a static field in Marshal) XXX
11011                         if (mono_security_core_clr_enabled ())
11012                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
11013                         */
11014
11015                         ftype = mono_field_get_type (field);
11016
11017                         /*
11018                          * LDFLD etc. is usable on static fields as well, so convert those cases to
11019                          * the static case.
11020                          */
11021                         if (is_instance && ftype->attrs & FIELD_ATTRIBUTE_STATIC) {
11022                                 switch (op) {
11023                                 case CEE_LDFLD:
11024                                         op = CEE_LDSFLD;
11025                                         break;
11026                                 case CEE_STFLD:
11027                                         op = CEE_STSFLD;
11028                                         break;
11029                                 case CEE_LDFLDA:
11030                                         op = CEE_LDSFLDA;
11031                                         break;
11032                                 default:
11033                                         g_assert_not_reached ();
11034                                 }
11035                                 is_instance = FALSE;
11036                         }
11037
11038                         context_used = mini_class_check_context_used (cfg, klass);
11039
11040                         /* INSTANCE CASE */
11041
11042                         foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
11043                         if (op == CEE_STFLD) {
11044                                 if (target_type_is_incompatible (cfg, field->type, sp [1]))
11045                                         UNVERIFIED;
11046 #ifndef DISABLE_REMOTING
11047                                 if ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class) {
11048                                         MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type); 
11049                                         MonoInst *iargs [5];
11050
11051                                         GSHAREDVT_FAILURE (op);
11052
11053                                         iargs [0] = sp [0];
11054                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11055                                         EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
11056                                         EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : 
11057                                                     field->offset);
11058                                         iargs [4] = sp [1];
11059
11060                                         if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
11061                                                 costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), 
11062                                                                                            iargs, ip, cfg->real_offset, TRUE);
11063                                                 CHECK_CFG_EXCEPTION;
11064                                                 g_assert (costs > 0);
11065                                                       
11066                                                 cfg->real_offset += 5;
11067
11068                                                 inline_costs += costs;
11069                                         } else {
11070                                                 mono_emit_method_call (cfg, stfld_wrapper, iargs, NULL);
11071                                         }
11072                                 } else
11073 #endif
11074                                 {
11075                                         MonoInst *store;
11076
11077                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
11078
11079                                         if (mini_is_gsharedvt_klass (klass)) {
11080                                                 MonoInst *offset_ins;
11081
11082                                                 context_used = mini_class_check_context_used (cfg, klass);
11083
11084                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11085                                                 /* The value is offset by 1 */
11086                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
11087                                                 dreg = alloc_ireg_mp (cfg);
11088                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11089                                                 /* The decomposition will call mini_emit_stobj () which will emit a wbarrier if needed */
11090                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, dreg, 0, sp [1]->dreg);
11091                                         } else {
11092                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, sp [0]->dreg, foffset, sp [1]->dreg);
11093                                         }
11094                                         if (sp [0]->opcode != OP_LDADDR)
11095                                                 store->flags |= MONO_INST_FAULT;
11096
11097                                 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)) {
11098                                         /* insert call to write barrier */
11099                                         MonoInst *ptr;
11100                                         int dreg;
11101
11102                                         dreg = alloc_ireg_mp (cfg);
11103                                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
11104                                         emit_write_barrier (cfg, ptr, sp [1]);
11105                                 }
11106
11107                                         store->flags |= ins_flag;
11108                                 }
11109                                 ins_flag = 0;
11110                                 ip += 5;
11111                                 break;
11112                         }
11113
11114 #ifndef DISABLE_REMOTING
11115                         if (is_instance && ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class)) {
11116                                 MonoMethod *wrapper = (op == CEE_LDFLDA) ? mono_marshal_get_ldflda_wrapper (field->type) : mono_marshal_get_ldfld_wrapper (field->type); 
11117                                 MonoInst *iargs [4];
11118
11119                                 GSHAREDVT_FAILURE (op);
11120
11121                                 iargs [0] = sp [0];
11122                                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11123                                 EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
11124                                 EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
11125                                 if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
11126                                         costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), 
11127                                                                                    iargs, ip, cfg->real_offset, TRUE);
11128                                         CHECK_CFG_EXCEPTION;
11129                                         g_assert (costs > 0);
11130                                                       
11131                                         cfg->real_offset += 5;
11132
11133                                         *sp++ = iargs [0];
11134
11135                                         inline_costs += costs;
11136                                 } else {
11137                                         ins = mono_emit_method_call (cfg, wrapper, iargs, NULL);
11138                                         *sp++ = ins;
11139                                 }
11140                         } else 
11141 #endif
11142                         if (is_instance) {
11143                                 if (sp [0]->type == STACK_VTYPE) {
11144                                         MonoInst *var;
11145
11146                                         /* Have to compute the address of the variable */
11147
11148                                         var = get_vreg_to_inst (cfg, sp [0]->dreg);
11149                                         if (!var)
11150                                                 var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, sp [0]->dreg);
11151                                         else
11152                                                 g_assert (var->klass == klass);
11153                                         
11154                                         EMIT_NEW_VARLOADA (cfg, ins, var, &var->klass->byval_arg);
11155                                         sp [0] = ins;
11156                                 }
11157
11158                                 if (op == CEE_LDFLDA) {
11159                                         if (sp [0]->type == STACK_OBJ) {
11160                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
11161                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "NullReferenceException");
11162                                         }
11163
11164                                         dreg = alloc_ireg_mp (cfg);
11165
11166                                         if (mini_is_gsharedvt_klass (klass)) {
11167                                                 MonoInst *offset_ins;
11168
11169                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11170                                                 /* The value is offset by 1 */
11171                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
11172                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11173                                         } else {
11174                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
11175                                         }
11176                                         ins->klass = mono_class_from_mono_type (field->type);
11177                                         ins->type = STACK_MP;
11178                                         *sp++ = ins;
11179                                 } else {
11180                                         MonoInst *load;
11181
11182                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
11183
11184                                         if (mini_is_gsharedvt_klass (klass)) {
11185                                                 MonoInst *offset_ins;
11186
11187                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11188                                                 /* The value is offset by 1 */
11189                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
11190                                                 dreg = alloc_ireg_mp (cfg);
11191                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11192                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, dreg, 0);
11193                                         } else {
11194                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, sp [0]->dreg, foffset);
11195                                         }
11196                                         load->flags |= ins_flag;
11197                                         if (sp [0]->opcode != OP_LDADDR)
11198                                                 load->flags |= MONO_INST_FAULT;
11199                                         *sp++ = load;
11200                                 }
11201                         }
11202
11203                         if (is_instance) {
11204                                 ins_flag = 0;
11205                                 ip += 5;
11206                                 break;
11207                         }
11208
11209                         /* STATIC CASE */
11210                         context_used = mini_class_check_context_used (cfg, klass);
11211
11212                         if (ftype->attrs & FIELD_ATTRIBUTE_LITERAL)
11213                                 UNVERIFIED;
11214
11215                         /* The special_static_fields field is init'd in mono_class_vtable, so it needs
11216                          * to be called here.
11217                          */
11218                         if (!context_used && !(cfg->opt & MONO_OPT_SHARED)) {
11219                                 mono_class_vtable (cfg->domain, klass);
11220                                 CHECK_TYPELOAD (klass);
11221                         }
11222                         mono_domain_lock (cfg->domain);
11223                         if (cfg->domain->special_static_fields)
11224                                 addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
11225                         mono_domain_unlock (cfg->domain);
11226
11227                         is_special_static = mono_class_field_is_special_static (field);
11228
11229                         if (is_special_static && ((gsize)addr & 0x80000000) == 0)
11230                                 thread_ins = mono_get_thread_intrinsic (cfg);
11231                         else
11232                                 thread_ins = NULL;
11233
11234                         /* Generate IR to compute the field address */
11235                         if (is_special_static && ((gsize)addr & 0x80000000) == 0 && thread_ins && !(cfg->opt & MONO_OPT_SHARED) && !context_used) {
11236                                 /*
11237                                  * Fast access to TLS data
11238                                  * Inline version of get_thread_static_data () in
11239                                  * threads.c.
11240                                  */
11241                                 guint32 offset;
11242                                 int idx, static_data_reg, array_reg, dreg;
11243
11244                                 GSHAREDVT_FAILURE (op);
11245
11246                                 MONO_ADD_INS (cfg->cbb, thread_ins);
11247                                 static_data_reg = alloc_ireg (cfg);
11248                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, MONO_STRUCT_OFFSET (MonoInternalThread, static_data));
11249
11250                                 if (cfg->compile_aot) {
11251                                         int offset_reg, offset2_reg, idx_reg;
11252
11253                                         /* For TLS variables, this will return the TLS offset */
11254                                         EMIT_NEW_SFLDACONST (cfg, ins, field);
11255                                         offset_reg = ins->dreg;
11256                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset_reg, offset_reg, 0x7fffffff);
11257                                         idx_reg = alloc_ireg (cfg);
11258                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, idx_reg, offset_reg, 0x3f);
11259                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
11260                                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
11261                                         array_reg = alloc_ireg (cfg);
11262                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
11263                                         offset2_reg = alloc_ireg (cfg);
11264                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, offset2_reg, offset_reg, 6);
11265                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset2_reg, 0x1ffffff);
11266                                         dreg = alloc_ireg (cfg);
11267                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, array_reg, offset2_reg);
11268                                 } else {
11269                                         offset = (gsize)addr & 0x7fffffff;
11270                                         idx = offset & 0x3f;
11271
11272                                         array_reg = alloc_ireg (cfg);
11273                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, idx * sizeof (gpointer));
11274                                         dreg = alloc_ireg (cfg);
11275                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_ADD_IMM, dreg, array_reg, ((offset >> 6) & 0x1ffffff));
11276                                 }
11277                         } else if ((cfg->opt & MONO_OPT_SHARED) ||
11278                                         (cfg->compile_aot && is_special_static) ||
11279                                         (context_used && is_special_static)) {
11280                                 MonoInst *iargs [2];
11281
11282                                 g_assert (field->parent);
11283                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11284                                 if (context_used) {
11285                                         iargs [1] = emit_get_rgctx_field (cfg, context_used,
11286                                                 field, MONO_RGCTX_INFO_CLASS_FIELD);
11287                                 } else {
11288                                         EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
11289                                 }
11290                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
11291                         } else if (context_used) {
11292                                 MonoInst *static_data;
11293
11294                                 /*
11295                                 g_print ("sharing static field access in %s.%s.%s - depth %d offset %d\n",
11296                                         method->klass->name_space, method->klass->name, method->name,
11297                                         depth, field->offset);
11298                                 */
11299
11300                                 if (mono_class_needs_cctor_run (klass, method))
11301                                         emit_class_init (cfg, klass);
11302
11303                                 /*
11304                                  * The pointer we're computing here is
11305                                  *
11306                                  *   super_info.static_data + field->offset
11307                                  */
11308                                 static_data = emit_get_rgctx_klass (cfg, context_used,
11309                                         klass, MONO_RGCTX_INFO_STATIC_DATA);
11310
11311                                 if (mini_is_gsharedvt_klass (klass)) {
11312                                         MonoInst *offset_ins;
11313
11314                                         offset_ins = emit_get_rgctx_field (cfg, context_used, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11315                                         /* The value is offset by 1 */
11316                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
11317                                         dreg = alloc_ireg_mp (cfg);
11318                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, static_data->dreg, offset_ins->dreg);
11319                                 } else if (field->offset == 0) {
11320                                         ins = static_data;
11321                                 } else {
11322                                         int addr_reg = mono_alloc_preg (cfg);
11323                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, addr_reg, static_data->dreg, field->offset);
11324                                 }
11325                                 } else if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
11326                                 MonoInst *iargs [2];
11327
11328                                 g_assert (field->parent);
11329                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11330                                 EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
11331                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
11332                         } else {
11333                                 MonoVTable *vtable = NULL;
11334
11335                                 if (!cfg->compile_aot)
11336                                         vtable = mono_class_vtable (cfg->domain, klass);
11337                                 CHECK_TYPELOAD (klass);
11338
11339                                 if (!addr) {
11340                                         if (mini_field_access_needs_cctor_run (cfg, method, klass, vtable)) {
11341                                                 if (!(g_slist_find (class_inits, klass))) {
11342                                                         emit_class_init (cfg, klass);
11343                                                         if (cfg->verbose_level > 2)
11344                                                                 printf ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, mono_field_get_name (field));
11345                                                         class_inits = g_slist_prepend (class_inits, klass);
11346                                                 }
11347                                         } else {
11348                                                 if (cfg->run_cctors) {
11349                                                         MonoException *ex;
11350                                                         /* This makes so that inline cannot trigger */
11351                                                         /* .cctors: too many apps depend on them */
11352                                                         /* running with a specific order... */
11353                                                         g_assert (vtable);
11354                                                         if (! vtable->initialized)
11355                                                                 INLINE_FAILURE ("class init");
11356                                                         ex = mono_runtime_class_init_full (vtable, FALSE);
11357                                                         if (ex) {
11358                                                                 set_exception_object (cfg, ex);
11359                                                                 goto exception_exit;
11360                                                         }
11361                                                 }
11362                                         }
11363                                         if (cfg->compile_aot)
11364                                                 EMIT_NEW_SFLDACONST (cfg, ins, field);
11365                                         else {
11366                                                 g_assert (vtable);
11367                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11368                                                 g_assert (addr);
11369                                                 EMIT_NEW_PCONST (cfg, ins, addr);
11370                                         }
11371                                 } else {
11372                                         MonoInst *iargs [1];
11373                                         EMIT_NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
11374                                         ins = mono_emit_jit_icall (cfg, mono_get_special_static_data, iargs);
11375                                 }
11376                         }
11377
11378                         /* Generate IR to do the actual load/store operation */
11379
11380                         if ((op == CEE_STFLD || op == CEE_STSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11381                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11382                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11383                         }
11384
11385                         if (op == CEE_LDSFLDA) {
11386                                 ins->klass = mono_class_from_mono_type (ftype);
11387                                 ins->type = STACK_PTR;
11388                                 *sp++ = ins;
11389                         } else if (op == CEE_STSFLD) {
11390                                 MonoInst *store;
11391
11392                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, ftype, ins->dreg, 0, store_val->dreg);
11393                                 store->flags |= ins_flag;
11394                         } else {
11395                                 gboolean is_const = FALSE;
11396                                 MonoVTable *vtable = NULL;
11397                                 gpointer addr = NULL;
11398
11399                                 if (!context_used) {
11400                                         vtable = mono_class_vtable (cfg->domain, klass);
11401                                         CHECK_TYPELOAD (klass);
11402                                 }
11403                                 if ((ftype->attrs & FIELD_ATTRIBUTE_INIT_ONLY) && (((addr = mono_aot_readonly_field_override (field)) != NULL) ||
11404                                                 (!context_used && !((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && vtable->initialized))) {
11405                                         int ro_type = ftype->type;
11406                                         if (!addr)
11407                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11408                                         if (ro_type == MONO_TYPE_VALUETYPE && ftype->data.klass->enumtype) {
11409                                                 ro_type = mono_class_enum_basetype (ftype->data.klass)->type;
11410                                         }
11411
11412                                         GSHAREDVT_FAILURE (op);
11413
11414                                         /* printf ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, mono_field_get_name (field));*/
11415                                         is_const = TRUE;
11416                                         switch (ro_type) {
11417                                         case MONO_TYPE_BOOLEAN:
11418                                         case MONO_TYPE_U1:
11419                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint8 *)addr));
11420                                                 sp++;
11421                                                 break;
11422                                         case MONO_TYPE_I1:
11423                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint8 *)addr));
11424                                                 sp++;
11425                                                 break;                                          
11426                                         case MONO_TYPE_CHAR:
11427                                         case MONO_TYPE_U2:
11428                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint16 *)addr));
11429                                                 sp++;
11430                                                 break;
11431                                         case MONO_TYPE_I2:
11432                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint16 *)addr));
11433                                                 sp++;
11434                                                 break;
11435                                                 break;
11436                                         case MONO_TYPE_I4:
11437                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint32 *)addr));
11438                                                 sp++;
11439                                                 break;                                          
11440                                         case MONO_TYPE_U4:
11441                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint32 *)addr));
11442                                                 sp++;
11443                                                 break;
11444                                         case MONO_TYPE_I:
11445                                         case MONO_TYPE_U:
11446                                         case MONO_TYPE_PTR:
11447                                         case MONO_TYPE_FNPTR:
11448                                                 EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11449                                                 type_to_eval_stack_type ((cfg), field->type, *sp);
11450                                                 sp++;
11451                                                 break;
11452                                         case MONO_TYPE_STRING:
11453                                         case MONO_TYPE_OBJECT:
11454                                         case MONO_TYPE_CLASS:
11455                                         case MONO_TYPE_SZARRAY:
11456                                         case MONO_TYPE_ARRAY:
11457                                                 if (!mono_gc_is_moving ()) {
11458                                                         EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11459                                                         type_to_eval_stack_type ((cfg), field->type, *sp);
11460                                                         sp++;
11461                                                 } else {
11462                                                         is_const = FALSE;
11463                                                 }
11464                                                 break;
11465                                         case MONO_TYPE_I8:
11466                                         case MONO_TYPE_U8:
11467                                                 EMIT_NEW_I8CONST (cfg, *sp, *((gint64 *)addr));
11468                                                 sp++;
11469                                                 break;
11470                                         case MONO_TYPE_R4:
11471                                         case MONO_TYPE_R8:
11472                                         case MONO_TYPE_VALUETYPE:
11473                                         default:
11474                                                 is_const = FALSE;
11475                                                 break;
11476                                         }
11477                                 }
11478
11479                                 if (!is_const) {
11480                                         MonoInst *load;
11481
11482                                         CHECK_STACK_OVF (1);
11483
11484                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, ins->dreg, 0);
11485                                         load->flags |= ins_flag;
11486                                         ins_flag = 0;
11487                                         *sp++ = load;
11488                                 }
11489                         }
11490
11491                         if ((op == CEE_LDFLD || op == CEE_LDSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11492                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
11493                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
11494                         }
11495
11496                         ins_flag = 0;
11497                         ip += 5;
11498                         break;
11499                 }
11500                 case CEE_STOBJ:
11501                         CHECK_STACK (2);
11502                         sp -= 2;
11503                         CHECK_OPSIZE (5);
11504                         token = read32 (ip + 1);
11505                         klass = mini_get_class (method, token, generic_context);
11506                         CHECK_TYPELOAD (klass);
11507                         if (ins_flag & MONO_INST_VOLATILE) {
11508                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11509                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11510                         }
11511                         /* FIXME: should check item at sp [1] is compatible with the type of the store. */
11512                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0, sp [1]->dreg);
11513                         ins->flags |= ins_flag;
11514                         if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER &&
11515                                         generic_class_is_reference_type (cfg, klass)) {
11516                                 /* insert call to write barrier */
11517                                 emit_write_barrier (cfg, sp [0], sp [1]);
11518                         }
11519                         ins_flag = 0;
11520                         ip += 5;
11521                         inline_costs += 1;
11522                         break;
11523
11524                         /*
11525                          * Array opcodes
11526                          */
11527                 case CEE_NEWARR: {
11528                         MonoInst *len_ins;
11529                         const char *data_ptr;
11530                         int data_size = 0;
11531                         guint32 field_token;
11532
11533                         CHECK_STACK (1);
11534                         --sp;
11535
11536                         CHECK_OPSIZE (5);
11537                         token = read32 (ip + 1);
11538
11539                         klass = mini_get_class (method, token, generic_context);
11540                         CHECK_TYPELOAD (klass);
11541
11542                         context_used = mini_class_check_context_used (cfg, klass);
11543
11544                         if (sp [0]->type == STACK_I8 || (SIZEOF_VOID_P == 8 && sp [0]->type == STACK_PTR)) {
11545                                 MONO_INST_NEW (cfg, ins, OP_LCONV_TO_OVF_U4);
11546                                 ins->sreg1 = sp [0]->dreg;
11547                                 ins->type = STACK_I4;
11548                                 ins->dreg = alloc_ireg (cfg);
11549                                 MONO_ADD_INS (cfg->cbb, ins);
11550                                 *sp = mono_decompose_opcode (cfg, ins);
11551                         }
11552
11553                         if (context_used) {
11554                                 MonoInst *args [3];
11555                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11556                                 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
11557
11558                                 /* FIXME: Use OP_NEWARR and decompose later to help abcrem */
11559
11560                                 /* vtable */
11561                                 args [0] = emit_get_rgctx_klass (cfg, context_used,
11562                                         array_class, MONO_RGCTX_INFO_VTABLE);
11563                                 /* array len */
11564                                 args [1] = sp [0];
11565
11566                                 if (managed_alloc)
11567                                         ins = mono_emit_method_call (cfg, managed_alloc, args, NULL);
11568                                 else
11569                                         ins = mono_emit_jit_icall (cfg, mono_array_new_specific, args);
11570                         } else {
11571                                 if (cfg->opt & MONO_OPT_SHARED) {
11572                                         /* Decompose now to avoid problems with references to the domainvar */
11573                                         MonoInst *iargs [3];
11574
11575                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11576                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11577                                         iargs [2] = sp [0];
11578
11579                                         ins = mono_emit_jit_icall (cfg, mono_array_new, iargs);
11580                                 } else {
11581                                         /* Decompose later since it is needed by abcrem */
11582                                         MonoClass *array_type = mono_array_class_get (klass, 1);
11583                                         mono_class_vtable (cfg->domain, array_type);
11584                                         CHECK_TYPELOAD (array_type);
11585
11586                                         MONO_INST_NEW (cfg, ins, OP_NEWARR);
11587                                         ins->dreg = alloc_ireg_ref (cfg);
11588                                         ins->sreg1 = sp [0]->dreg;
11589                                         ins->inst_newa_class = klass;
11590                                         ins->type = STACK_OBJ;
11591                                         ins->klass = array_type;
11592                                         MONO_ADD_INS (cfg->cbb, ins);
11593                                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11594                                         cfg->cbb->has_array_access = TRUE;
11595
11596                                         /* Needed so mono_emit_load_get_addr () gets called */
11597                                         mono_get_got_var (cfg);
11598                                 }
11599                         }
11600
11601                         len_ins = sp [0];
11602                         ip += 5;
11603                         *sp++ = ins;
11604                         inline_costs += 1;
11605
11606                         /* 
11607                          * we inline/optimize the initialization sequence if possible.
11608                          * we should also allocate the array as not cleared, since we spend as much time clearing to 0 as initializing
11609                          * for small sizes open code the memcpy
11610                          * ensure the rva field is big enough
11611                          */
11612                         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))) {
11613                                 MonoMethod *memcpy_method = get_memcpy_method ();
11614                                 MonoInst *iargs [3];
11615                                 int add_reg = alloc_ireg_mp (cfg);
11616
11617                                 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, add_reg, ins->dreg, MONO_STRUCT_OFFSET (MonoArray, vector));
11618                                 if (cfg->compile_aot) {
11619                                         EMIT_NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(field_token), STACK_PTR, NULL);
11620                                 } else {
11621                                         EMIT_NEW_PCONST (cfg, iargs [1], (char*)data_ptr);
11622                                 }
11623                                 EMIT_NEW_ICONST (cfg, iargs [2], data_size);
11624                                 mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
11625                                 ip += 11;
11626                         }
11627
11628                         break;
11629                 }
11630                 case CEE_LDLEN:
11631                         CHECK_STACK (1);
11632                         --sp;
11633                         if (sp [0]->type != STACK_OBJ)
11634                                 UNVERIFIED;
11635
11636                         MONO_INST_NEW (cfg, ins, OP_LDLEN);
11637                         ins->dreg = alloc_preg (cfg);
11638                         ins->sreg1 = sp [0]->dreg;
11639                         ins->type = STACK_I4;
11640                         /* This flag will be inherited by the decomposition */
11641                         ins->flags |= MONO_INST_FAULT;
11642                         MONO_ADD_INS (cfg->cbb, ins);
11643                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11644                         cfg->cbb->has_array_access = TRUE;
11645                         ip ++;
11646                         *sp++ = ins;
11647                         break;
11648                 case CEE_LDELEMA:
11649                         CHECK_STACK (2);
11650                         sp -= 2;
11651                         CHECK_OPSIZE (5);
11652                         if (sp [0]->type != STACK_OBJ)
11653                                 UNVERIFIED;
11654
11655                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11656
11657                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11658                         CHECK_TYPELOAD (klass);
11659                         /* we need to make sure that this array is exactly the type it needs
11660                          * to be for correctness. the wrappers are lax with their usage
11661                          * so we need to ignore them here
11662                          */
11663                         if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE && !readonly) {
11664                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11665                                 mini_emit_check_array_type (cfg, sp [0], array_class);
11666                                 CHECK_TYPELOAD (array_class);
11667                         }
11668
11669                         readonly = FALSE;
11670                         ins = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11671                         *sp++ = ins;
11672                         ip += 5;
11673                         break;
11674                 case CEE_LDELEM:
11675                 case CEE_LDELEM_I1:
11676                 case CEE_LDELEM_U1:
11677                 case CEE_LDELEM_I2:
11678                 case CEE_LDELEM_U2:
11679                 case CEE_LDELEM_I4:
11680                 case CEE_LDELEM_U4:
11681                 case CEE_LDELEM_I8:
11682                 case CEE_LDELEM_I:
11683                 case CEE_LDELEM_R4:
11684                 case CEE_LDELEM_R8:
11685                 case CEE_LDELEM_REF: {
11686                         MonoInst *addr;
11687
11688                         CHECK_STACK (2);
11689                         sp -= 2;
11690
11691                         if (*ip == CEE_LDELEM) {
11692                                 CHECK_OPSIZE (5);
11693                                 token = read32 (ip + 1);
11694                                 klass = mini_get_class (method, token, generic_context);
11695                                 CHECK_TYPELOAD (klass);
11696                                 mono_class_init (klass);
11697                         }
11698                         else
11699                                 klass = array_access_to_klass (*ip);
11700
11701                         if (sp [0]->type != STACK_OBJ)
11702                                 UNVERIFIED;
11703
11704                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11705
11706                         if (mini_is_gsharedvt_variable_klass (klass)) {
11707                                 // FIXME-VT: OP_ICONST optimization
11708                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11709                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11710                                 ins->opcode = OP_LOADV_MEMBASE;
11711                         } else if (sp [1]->opcode == OP_ICONST) {
11712                                 int array_reg = sp [0]->dreg;
11713                                 int index_reg = sp [1]->dreg;
11714                                 int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
11715
11716                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
11717                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset);
11718                         } else {
11719                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11720                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11721                         }
11722                         *sp++ = ins;
11723                         if (*ip == CEE_LDELEM)
11724                                 ip += 5;
11725                         else
11726                                 ++ip;
11727                         break;
11728                 }
11729                 case CEE_STELEM_I:
11730                 case CEE_STELEM_I1:
11731                 case CEE_STELEM_I2:
11732                 case CEE_STELEM_I4:
11733                 case CEE_STELEM_I8:
11734                 case CEE_STELEM_R4:
11735                 case CEE_STELEM_R8:
11736                 case CEE_STELEM_REF:
11737                 case CEE_STELEM: {
11738                         CHECK_STACK (3);
11739                         sp -= 3;
11740
11741                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11742
11743                         if (*ip == CEE_STELEM) {
11744                                 CHECK_OPSIZE (5);
11745                                 token = read32 (ip + 1);
11746                                 klass = mini_get_class (method, token, generic_context);
11747                                 CHECK_TYPELOAD (klass);
11748                                 mono_class_init (klass);
11749                         }
11750                         else
11751                                 klass = array_access_to_klass (*ip);
11752
11753                         if (sp [0]->type != STACK_OBJ)
11754                                 UNVERIFIED;
11755
11756                         emit_array_store (cfg, klass, sp, TRUE);
11757
11758                         if (*ip == CEE_STELEM)
11759                                 ip += 5;
11760                         else
11761                                 ++ip;
11762                         inline_costs += 1;
11763                         break;
11764                 }
11765                 case CEE_CKFINITE: {
11766                         CHECK_STACK (1);
11767                         --sp;
11768
11769                         if (cfg->llvm_only) {
11770                                 MonoInst *iargs [1];
11771
11772                                 iargs [0] = sp [0];
11773                                 *sp++ = mono_emit_jit_icall (cfg, mono_ckfinite, iargs);
11774                         } else  {
11775                                 MONO_INST_NEW (cfg, ins, OP_CKFINITE);
11776                                 ins->sreg1 = sp [0]->dreg;
11777                                 ins->dreg = alloc_freg (cfg);
11778                                 ins->type = STACK_R8;
11779                                 MONO_ADD_INS (cfg->cbb, ins);
11780
11781                                 *sp++ = mono_decompose_opcode (cfg, ins);
11782                         }
11783
11784                         ++ip;
11785                         break;
11786                 }
11787                 case CEE_REFANYVAL: {
11788                         MonoInst *src_var, *src;
11789
11790                         int klass_reg = alloc_preg (cfg);
11791                         int dreg = alloc_preg (cfg);
11792
11793                         GSHAREDVT_FAILURE (*ip);
11794
11795                         CHECK_STACK (1);
11796                         MONO_INST_NEW (cfg, ins, *ip);
11797                         --sp;
11798                         CHECK_OPSIZE (5);
11799                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11800                         CHECK_TYPELOAD (klass);
11801
11802                         context_used = mini_class_check_context_used (cfg, klass);
11803
11804                         // FIXME:
11805                         src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
11806                         if (!src_var)
11807                                 src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
11808                         EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
11809                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass));
11810
11811                         if (context_used) {
11812                                 MonoInst *klass_ins;
11813
11814                                 klass_ins = emit_get_rgctx_klass (cfg, context_used,
11815                                                 klass, MONO_RGCTX_INFO_KLASS);
11816
11817                                 // FIXME:
11818                                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_ins->dreg);
11819                                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
11820                         } else {
11821                                 mini_emit_class_check (cfg, klass_reg, klass);
11822                         }
11823                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value));
11824                         ins->type = STACK_MP;
11825                         ins->klass = klass;
11826                         *sp++ = ins;
11827                         ip += 5;
11828                         break;
11829                 }
11830                 case CEE_MKREFANY: {
11831                         MonoInst *loc, *addr;
11832
11833                         GSHAREDVT_FAILURE (*ip);
11834
11835                         CHECK_STACK (1);
11836                         MONO_INST_NEW (cfg, ins, *ip);
11837                         --sp;
11838                         CHECK_OPSIZE (5);
11839                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11840                         CHECK_TYPELOAD (klass);
11841
11842                         context_used = mini_class_check_context_used (cfg, klass);
11843
11844                         loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
11845                         EMIT_NEW_TEMPLOADA (cfg, addr, loc->inst_c0);
11846
11847                         if (context_used) {
11848                                 MonoInst *const_ins;
11849                                 int type_reg = alloc_preg (cfg);
11850
11851                                 const_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
11852                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_ins->dreg);
11853                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_ins->dreg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
11854                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
11855                         } else if (cfg->compile_aot) {
11856                                 int const_reg = alloc_preg (cfg);
11857                                 int type_reg = alloc_preg (cfg);
11858
11859                                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
11860                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_reg);
11861                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_reg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
11862                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
11863                         } else {
11864                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), &klass->byval_arg);
11865                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), klass);
11866                         }
11867                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value), sp [0]->dreg);
11868
11869                         EMIT_NEW_TEMPLOAD (cfg, ins, loc->inst_c0);
11870                         ins->type = STACK_VTYPE;
11871                         ins->klass = mono_defaults.typed_reference_class;
11872                         *sp++ = ins;
11873                         ip += 5;
11874                         break;
11875                 }
11876                 case CEE_LDTOKEN: {
11877                         gpointer handle;
11878                         MonoClass *handle_class;
11879
11880                         CHECK_STACK_OVF (1);
11881
11882                         CHECK_OPSIZE (5);
11883                         n = read32 (ip + 1);
11884
11885                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD ||
11886                                         method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
11887                                 handle = mono_method_get_wrapper_data (method, n);
11888                                 handle_class = mono_method_get_wrapper_data (method, n + 1);
11889                                 if (handle_class == mono_defaults.typehandle_class)
11890                                         handle = &((MonoClass*)handle)->byval_arg;
11891                         }
11892                         else {
11893                                 handle = mono_ldtoken_checked (image, n, &handle_class, generic_context, &cfg->error);
11894                                 CHECK_CFG_ERROR;
11895                         }
11896                         if (!handle)
11897                                 LOAD_ERROR;
11898                         mono_class_init (handle_class);
11899                         if (cfg->gshared) {
11900                                 if (mono_metadata_token_table (n) == MONO_TABLE_TYPEDEF ||
11901                                                 mono_metadata_token_table (n) == MONO_TABLE_TYPEREF) {
11902                                         /* This case handles ldtoken
11903                                            of an open type, like for
11904                                            typeof(Gen<>). */
11905                                         context_used = 0;
11906                                 } else if (handle_class == mono_defaults.typehandle_class) {
11907                                         context_used = mini_class_check_context_used (cfg, mono_class_from_mono_type (handle));
11908                                 } else if (handle_class == mono_defaults.fieldhandle_class)
11909                                         context_used = mini_class_check_context_used (cfg, ((MonoClassField*)handle)->parent);
11910                                 else if (handle_class == mono_defaults.methodhandle_class)
11911                                         context_used = mini_method_check_context_used (cfg, handle);
11912                                 else
11913                                         g_assert_not_reached ();
11914                         }
11915
11916                         if ((cfg->opt & MONO_OPT_SHARED) &&
11917                                         method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD &&
11918                                         method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED) {
11919                                 MonoInst *addr, *vtvar, *iargs [3];
11920                                 int method_context_used;
11921
11922                                 method_context_used = mini_method_check_context_used (cfg, method);
11923
11924                                 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL); 
11925
11926                                 EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
11927                                 EMIT_NEW_ICONST (cfg, iargs [1], n);
11928                                 if (method_context_used) {
11929                                         iargs [2] = emit_get_rgctx_method (cfg, method_context_used,
11930                                                 method, MONO_RGCTX_INFO_METHOD);
11931                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper_generic_shared, iargs);
11932                                 } else {
11933                                         EMIT_NEW_PCONST (cfg, iargs [2], generic_context);
11934                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper, iargs);
11935                                 }
11936                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
11937
11938                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
11939
11940                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
11941                         } else {
11942                                 if ((ip + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 5) && 
11943                                         ((ip [5] == CEE_CALL) || (ip [5] == CEE_CALLVIRT)) && 
11944                                         (cmethod = mini_get_method (cfg, method, read32 (ip + 6), NULL, generic_context)) &&
11945                                         (cmethod->klass == mono_defaults.systemtype_class) &&
11946                                         (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
11947                                         MonoClass *tclass = mono_class_from_mono_type (handle);
11948
11949                                         mono_class_init (tclass);
11950                                         if (context_used) {
11951                                                 ins = emit_get_rgctx_klass (cfg, context_used,
11952                                                         tclass, MONO_RGCTX_INFO_REFLECTION_TYPE);
11953                                         } else if (cfg->compile_aot) {
11954                                                 if (method->wrapper_type) {
11955                                                         mono_error_init (&error); //got to do it since there are multiple conditionals below
11956                                                         if (mono_class_get_checked (tclass->image, tclass->type_token, &error) == tclass && !generic_context) {
11957                                                                 /* Special case for static synchronized wrappers */
11958                                                                 EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, tclass->image, tclass->type_token, generic_context);
11959                                                         } else {
11960                                                                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
11961                                                                 /* FIXME: n is not a normal token */
11962                                                                 DISABLE_AOT (cfg);
11963                                                                 EMIT_NEW_PCONST (cfg, ins, NULL);
11964                                                         }
11965                                                 } else {
11966                                                         EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n, generic_context);
11967                                                 }
11968                                         } else {
11969                                                 EMIT_NEW_PCONST (cfg, ins, mono_type_get_object (cfg->domain, handle));
11970                                         }
11971                                         ins->type = STACK_OBJ;
11972                                         ins->klass = cmethod->klass;
11973                                         ip += 5;
11974                                 } else {
11975                                         MonoInst *addr, *vtvar;
11976
11977                                         vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
11978
11979                                         if (context_used) {
11980                                                 if (handle_class == mono_defaults.typehandle_class) {
11981                                                         ins = emit_get_rgctx_klass (cfg, context_used,
11982                                                                         mono_class_from_mono_type (handle),
11983                                                                         MONO_RGCTX_INFO_TYPE);
11984                                                 } else if (handle_class == mono_defaults.methodhandle_class) {
11985                                                         ins = emit_get_rgctx_method (cfg, context_used,
11986                                                                         handle, MONO_RGCTX_INFO_METHOD);
11987                                                 } else if (handle_class == mono_defaults.fieldhandle_class) {
11988                                                         ins = emit_get_rgctx_field (cfg, context_used,
11989                                                                         handle, MONO_RGCTX_INFO_CLASS_FIELD);
11990                                                 } else {
11991                                                         g_assert_not_reached ();
11992                                                 }
11993                                         } else if (cfg->compile_aot) {
11994                                                 EMIT_NEW_LDTOKENCONST (cfg, ins, image, n, generic_context);
11995                                         } else {
11996                                                 EMIT_NEW_PCONST (cfg, ins, handle);
11997                                         }
11998                                         EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
11999                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
12000                                         EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
12001                                 }
12002                         }
12003
12004                         *sp++ = ins;
12005                         ip += 5;
12006                         break;
12007                 }
12008                 case CEE_THROW:
12009                         CHECK_STACK (1);
12010                         MONO_INST_NEW (cfg, ins, OP_THROW);
12011                         --sp;
12012                         ins->sreg1 = sp [0]->dreg;
12013                         ip++;
12014                         cfg->cbb->out_of_line = TRUE;
12015                         MONO_ADD_INS (cfg->cbb, ins);
12016                         MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
12017                         MONO_ADD_INS (cfg->cbb, ins);
12018                         sp = stack_start;
12019                         
12020                         link_bblock (cfg, cfg->cbb, end_bblock);
12021                         start_new_bblock = 1;
12022                         /* This can complicate code generation for llvm since the return value might not be defined */
12023                         if (COMPILE_LLVM (cfg))
12024                                 INLINE_FAILURE ("throw");
12025                         break;
12026                 case CEE_ENDFINALLY:
12027                         /* mono_save_seq_point_info () depends on this */
12028                         if (sp != stack_start)
12029                                 emit_seq_point (cfg, method, ip, FALSE, FALSE);
12030                         MONO_INST_NEW (cfg, ins, OP_ENDFINALLY);
12031                         MONO_ADD_INS (cfg->cbb, ins);
12032                         ip++;
12033                         start_new_bblock = 1;
12034
12035                         /*
12036                          * Control will leave the method so empty the stack, otherwise
12037                          * the next basic block will start with a nonempty stack.
12038                          */
12039                         while (sp != stack_start) {
12040                                 sp--;
12041                         }
12042                         break;
12043                 case CEE_LEAVE:
12044                 case CEE_LEAVE_S: {
12045                         GList *handlers;
12046
12047                         if (*ip == CEE_LEAVE) {
12048                                 CHECK_OPSIZE (5);
12049                                 target = ip + 5 + (gint32)read32(ip + 1);
12050                         } else {
12051                                 CHECK_OPSIZE (2);
12052                                 target = ip + 2 + (signed char)(ip [1]);
12053                         }
12054
12055                         /* empty the stack */
12056                         while (sp != stack_start) {
12057                                 sp--;
12058                         }
12059
12060                         /* 
12061                          * If this leave statement is in a catch block, check for a
12062                          * pending exception, and rethrow it if necessary.
12063                          * We avoid doing this in runtime invoke wrappers, since those are called
12064                          * by native code which excepts the wrapper to catch all exceptions.
12065                          */
12066                         for (i = 0; i < header->num_clauses; ++i) {
12067                                 MonoExceptionClause *clause = &header->clauses [i];
12068
12069                                 /* 
12070                                  * Use <= in the final comparison to handle clauses with multiple
12071                                  * leave statements, like in bug #78024.
12072                                  * The ordering of the exception clauses guarantees that we find the
12073                                  * innermost clause.
12074                                  */
12075                                 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) {
12076                                         MonoInst *exc_ins;
12077                                         MonoBasicBlock *dont_throw;
12078
12079                                         /*
12080                                           MonoInst *load;
12081
12082                                           NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, clause->handler_offset)->inst_c0);
12083                                         */
12084
12085                                         exc_ins = mono_emit_jit_icall (cfg, mono_thread_get_undeniable_exception, NULL);
12086
12087                                         NEW_BBLOCK (cfg, dont_throw);
12088
12089                                         /*
12090                                          * Currently, we always rethrow the abort exception, despite the 
12091                                          * fact that this is not correct. See thread6.cs for an example. 
12092                                          * But propagating the abort exception is more important than 
12093                                          * getting the sematics right.
12094                                          */
12095                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, exc_ins->dreg, 0);
12096                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, dont_throw);
12097                                         MONO_EMIT_NEW_UNALU (cfg, OP_THROW, -1, exc_ins->dreg);
12098
12099                                         MONO_START_BB (cfg, dont_throw);
12100                                 }
12101                         }
12102
12103 #ifdef ENABLE_LLVM
12104                         cfg->cbb->try_end = (intptr_t)(ip - header->code);
12105 #endif
12106
12107                         if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
12108                                 GList *tmp;
12109                                 MonoExceptionClause *clause;
12110
12111                                 for (tmp = handlers; tmp; tmp = tmp->next) {
12112                                         clause = tmp->data;
12113                                         tblock = cfg->cil_offset_to_bb [clause->handler_offset];
12114                                         g_assert (tblock);
12115                                         link_bblock (cfg, cfg->cbb, tblock);
12116                                         MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
12117                                         ins->inst_target_bb = tblock;
12118                                         ins->inst_eh_block = clause;
12119                                         MONO_ADD_INS (cfg->cbb, ins);
12120                                         cfg->cbb->has_call_handler = 1;
12121                                         if (COMPILE_LLVM (cfg)) {
12122                                                 MonoBasicBlock *target_bb;
12123
12124                                                 /* 
12125                                                  * Link the finally bblock with the target, since it will
12126                                                  * conceptually branch there.
12127                                                  * FIXME: Have to link the bblock containing the endfinally.
12128                                                  */
12129                                                 GET_BBLOCK (cfg, target_bb, target);
12130                                                 link_bblock (cfg, tblock, target_bb);
12131                                         }
12132                                 }
12133                                 g_list_free (handlers);
12134                         } 
12135
12136                         MONO_INST_NEW (cfg, ins, OP_BR);
12137                         MONO_ADD_INS (cfg->cbb, ins);
12138                         GET_BBLOCK (cfg, tblock, target);
12139                         link_bblock (cfg, cfg->cbb, tblock);
12140                         ins->inst_target_bb = tblock;
12141
12142                         start_new_bblock = 1;
12143
12144                         if (*ip == CEE_LEAVE)
12145                                 ip += 5;
12146                         else
12147                                 ip += 2;
12148
12149                         break;
12150                 }
12151
12152                         /*
12153                          * Mono specific opcodes
12154                          */
12155                 case MONO_CUSTOM_PREFIX: {
12156
12157                         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
12158
12159                         CHECK_OPSIZE (2);
12160                         switch (ip [1]) {
12161                         case CEE_MONO_ICALL: {
12162                                 gpointer func;
12163                                 MonoJitICallInfo *info;
12164
12165                                 token = read32 (ip + 2);
12166                                 func = mono_method_get_wrapper_data (method, token);
12167                                 info = mono_find_jit_icall_by_addr (func);
12168                                 if (!info)
12169                                         g_error ("Could not find icall address in wrapper %s", mono_method_full_name (method, 1));
12170                                 g_assert (info);
12171
12172                                 CHECK_STACK (info->sig->param_count);
12173                                 sp -= info->sig->param_count;
12174
12175                                 ins = mono_emit_jit_icall (cfg, info->func, sp);
12176                                 if (!MONO_TYPE_IS_VOID (info->sig->ret))
12177                                         *sp++ = ins;
12178
12179                                 ip += 6;
12180                                 inline_costs += 10 * num_calls++;
12181
12182                                 break;
12183                         }
12184                         case CEE_MONO_LDPTR_CARD_TABLE:
12185                         case CEE_MONO_LDPTR_NURSERY_START:
12186                         case CEE_MONO_LDPTR_NURSERY_BITS:
12187                         case CEE_MONO_LDPTR_INT_REQ_FLAG: {
12188                                 CHECK_STACK_OVF (1);
12189
12190                                 switch (ip [1]) {
12191                                         case CEE_MONO_LDPTR_CARD_TABLE:
12192                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR, NULL);
12193                                                 break;
12194                                         case CEE_MONO_LDPTR_NURSERY_START:
12195                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_NURSERY_START, NULL);
12196                                                 break;
12197                                         case CEE_MONO_LDPTR_NURSERY_BITS:
12198                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_NURSERY_BITS, NULL);
12199                                                 break;
12200                                         case CEE_MONO_LDPTR_INT_REQ_FLAG:
12201                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG, NULL);
12202                                                 break;
12203                                 }
12204
12205                                 *sp++ = ins;
12206                                 ip += 2;
12207                                 inline_costs += 10 * num_calls++;
12208                                 break;
12209                         }
12210                         case CEE_MONO_LDPTR: {
12211                                 gpointer ptr;
12212
12213                                 CHECK_STACK_OVF (1);
12214                                 CHECK_OPSIZE (6);
12215                                 token = read32 (ip + 2);
12216
12217                                 ptr = mono_method_get_wrapper_data (method, token);
12218                                 EMIT_NEW_PCONST (cfg, ins, ptr);
12219                                 *sp++ = ins;
12220                                 ip += 6;
12221                                 inline_costs += 10 * num_calls++;
12222                                 /* Can't embed random pointers into AOT code */
12223                                 DISABLE_AOT (cfg);
12224                                 break;
12225                         }
12226                         case CEE_MONO_JIT_ICALL_ADDR: {
12227                                 MonoJitICallInfo *callinfo;
12228                                 gpointer ptr;
12229
12230                                 CHECK_STACK_OVF (1);
12231                                 CHECK_OPSIZE (6);
12232                                 token = read32 (ip + 2);
12233
12234                                 ptr = mono_method_get_wrapper_data (method, token);
12235                                 callinfo = mono_find_jit_icall_by_addr (ptr);
12236                                 g_assert (callinfo);
12237                                 EMIT_NEW_JIT_ICALL_ADDRCONST (cfg, ins, (char*)callinfo->name);
12238                                 *sp++ = ins;
12239                                 ip += 6;
12240                                 inline_costs += 10 * num_calls++;
12241                                 break;
12242                         }
12243                         case CEE_MONO_ICALL_ADDR: {
12244                                 MonoMethod *cmethod;
12245                                 gpointer ptr;
12246
12247                                 CHECK_STACK_OVF (1);
12248                                 CHECK_OPSIZE (6);
12249                                 token = read32 (ip + 2);
12250
12251                                 cmethod = mono_method_get_wrapper_data (method, token);
12252
12253                                 if (cfg->compile_aot) {
12254                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, cmethod);
12255                                 } else {
12256                                         ptr = mono_lookup_internal_call (cmethod);
12257                                         g_assert (ptr);
12258                                         EMIT_NEW_PCONST (cfg, ins, ptr);
12259                                 }
12260                                 *sp++ = ins;
12261                                 ip += 6;
12262                                 break;
12263                         }
12264                         case CEE_MONO_VTADDR: {
12265                                 MonoInst *src_var, *src;
12266
12267                                 CHECK_STACK (1);
12268                                 --sp;
12269
12270                                 // FIXME:
12271                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
12272                                 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
12273                                 *sp++ = src;
12274                                 ip += 2;
12275                                 break;
12276                         }
12277                         case CEE_MONO_NEWOBJ: {
12278                                 MonoInst *iargs [2];
12279
12280                                 CHECK_STACK_OVF (1);
12281                                 CHECK_OPSIZE (6);
12282                                 token = read32 (ip + 2);
12283                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12284                                 mono_class_init (klass);
12285                                 NEW_DOMAINCONST (cfg, iargs [0]);
12286                                 MONO_ADD_INS (cfg->cbb, iargs [0]);
12287                                 NEW_CLASSCONST (cfg, iargs [1], klass);
12288                                 MONO_ADD_INS (cfg->cbb, iargs [1]);
12289                                 *sp++ = mono_emit_jit_icall (cfg, mono_object_new, iargs);
12290                                 ip += 6;
12291                                 inline_costs += 10 * num_calls++;
12292                                 break;
12293                         }
12294                         case CEE_MONO_OBJADDR:
12295                                 CHECK_STACK (1);
12296                                 --sp;
12297                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
12298                                 ins->dreg = alloc_ireg_mp (cfg);
12299                                 ins->sreg1 = sp [0]->dreg;
12300                                 ins->type = STACK_MP;
12301                                 MONO_ADD_INS (cfg->cbb, ins);
12302                                 *sp++ = ins;
12303                                 ip += 2;
12304                                 break;
12305                         case CEE_MONO_LDNATIVEOBJ:
12306                                 /*
12307                                  * Similar to LDOBJ, but instead load the unmanaged 
12308                                  * representation of the vtype to the stack.
12309                                  */
12310                                 CHECK_STACK (1);
12311                                 CHECK_OPSIZE (6);
12312                                 --sp;
12313                                 token = read32 (ip + 2);
12314                                 klass = mono_method_get_wrapper_data (method, token);
12315                                 g_assert (klass->valuetype);
12316                                 mono_class_init (klass);
12317
12318                                 {
12319                                         MonoInst *src, *dest, *temp;
12320
12321                                         src = sp [0];
12322                                         temp = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
12323                                         temp->backend.is_pinvoke = 1;
12324                                         EMIT_NEW_TEMPLOADA (cfg, dest, temp->inst_c0);
12325                                         mini_emit_stobj (cfg, dest, src, klass, TRUE);
12326
12327                                         EMIT_NEW_TEMPLOAD (cfg, dest, temp->inst_c0);
12328                                         dest->type = STACK_VTYPE;
12329                                         dest->klass = klass;
12330
12331                                         *sp ++ = dest;
12332                                         ip += 6;
12333                                 }
12334                                 break;
12335                         case CEE_MONO_RETOBJ: {
12336                                 /*
12337                                  * Same as RET, but return the native representation of a vtype
12338                                  * to the caller.
12339                                  */
12340                                 g_assert (cfg->ret);
12341                                 g_assert (mono_method_signature (method)->pinvoke); 
12342                                 CHECK_STACK (1);
12343                                 --sp;
12344                                 
12345                                 CHECK_OPSIZE (6);
12346                                 token = read32 (ip + 2);    
12347                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12348
12349                                 if (!cfg->vret_addr) {
12350                                         g_assert (cfg->ret_var_is_local);
12351
12352                                         EMIT_NEW_VARLOADA (cfg, ins, cfg->ret, cfg->ret->inst_vtype);
12353                                 } else {
12354                                         EMIT_NEW_RETLOADA (cfg, ins);
12355                                 }
12356                                 mini_emit_stobj (cfg, ins, sp [0], klass, TRUE);
12357                                 
12358                                 if (sp != stack_start)
12359                                         UNVERIFIED;
12360                                 
12361                                 MONO_INST_NEW (cfg, ins, OP_BR);
12362                                 ins->inst_target_bb = end_bblock;
12363                                 MONO_ADD_INS (cfg->cbb, ins);
12364                                 link_bblock (cfg, cfg->cbb, end_bblock);
12365                                 start_new_bblock = 1;
12366                                 ip += 6;
12367                                 break;
12368                         }
12369                         case CEE_MONO_CISINST:
12370                         case CEE_MONO_CCASTCLASS: {
12371                                 int token;
12372                                 CHECK_STACK (1);
12373                                 --sp;
12374                                 CHECK_OPSIZE (6);
12375                                 token = read32 (ip + 2);
12376                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12377                                 if (ip [1] == CEE_MONO_CISINST)
12378                                         ins = handle_cisinst (cfg, klass, sp [0]);
12379                                 else
12380                                         ins = handle_ccastclass (cfg, klass, sp [0]);
12381                                 *sp++ = ins;
12382                                 ip += 6;
12383                                 break;
12384                         }
12385                         case CEE_MONO_SAVE_LMF:
12386                         case CEE_MONO_RESTORE_LMF:
12387                                 ip += 2;
12388                                 break;
12389                         case CEE_MONO_CLASSCONST:
12390                                 CHECK_STACK_OVF (1);
12391                                 CHECK_OPSIZE (6);
12392                                 token = read32 (ip + 2);
12393                                 EMIT_NEW_CLASSCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
12394                                 *sp++ = ins;
12395                                 ip += 6;
12396                                 inline_costs += 10 * num_calls++;
12397                                 break;
12398                         case CEE_MONO_NOT_TAKEN:
12399                                 cfg->cbb->out_of_line = TRUE;
12400                                 ip += 2;
12401                                 break;
12402                         case CEE_MONO_TLS: {
12403                                 int key;
12404
12405                                 CHECK_STACK_OVF (1);
12406                                 CHECK_OPSIZE (6);
12407                                 key = (gint32)read32 (ip + 2);
12408                                 g_assert (key < TLS_KEY_NUM);
12409
12410                                 ins = mono_create_tls_get (cfg, key);
12411                                 if (!ins) {
12412                                         if (cfg->compile_aot) {
12413                                                 DISABLE_AOT (cfg);
12414                                                 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
12415                                                 ins->dreg = alloc_preg (cfg);
12416                                                 ins->type = STACK_PTR;
12417                                         } else {
12418                                                 g_assert_not_reached ();
12419                                         }
12420                                 }
12421                                 ins->type = STACK_PTR;
12422                                 MONO_ADD_INS (cfg->cbb, ins);
12423                                 *sp++ = ins;
12424                                 ip += 6;
12425                                 break;
12426                         }
12427                         case CEE_MONO_DYN_CALL: {
12428                                 MonoCallInst *call;
12429
12430                                 /* It would be easier to call a trampoline, but that would put an
12431                                  * extra frame on the stack, confusing exception handling. So
12432                                  * implement it inline using an opcode for now.
12433                                  */
12434
12435                                 if (!cfg->dyn_call_var) {
12436                                         cfg->dyn_call_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12437                                         /* prevent it from being register allocated */
12438                                         cfg->dyn_call_var->flags |= MONO_INST_VOLATILE;
12439                                 }
12440
12441                                 /* Has to use a call inst since it local regalloc expects it */
12442                                 MONO_INST_NEW_CALL (cfg, call, OP_DYN_CALL);
12443                                 ins = (MonoInst*)call;
12444                                 sp -= 2;
12445                                 ins->sreg1 = sp [0]->dreg;
12446                                 ins->sreg2 = sp [1]->dreg;
12447                                 MONO_ADD_INS (cfg->cbb, ins);
12448
12449                                 cfg->param_area = MAX (cfg->param_area, cfg->backend->dyn_call_param_area);
12450
12451                                 ip += 2;
12452                                 inline_costs += 10 * num_calls++;
12453
12454                                 break;
12455                         }
12456                         case CEE_MONO_MEMORY_BARRIER: {
12457                                 CHECK_OPSIZE (6);
12458                                 emit_memory_barrier (cfg, (int)read32 (ip + 2));
12459                                 ip += 6;
12460                                 break;
12461                         }
12462                         case CEE_MONO_JIT_ATTACH: {
12463                                 MonoInst *args [16], *domain_ins;
12464                                 MonoInst *ad_ins, *jit_tls_ins;
12465                                 MonoBasicBlock *next_bb = NULL, *call_bb = NULL;
12466
12467                                 cfg->orig_domain_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12468
12469                                 EMIT_NEW_PCONST (cfg, ins, NULL);
12470                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12471
12472                                 ad_ins = mono_get_domain_intrinsic (cfg);
12473                                 jit_tls_ins = mono_get_jit_tls_intrinsic (cfg);
12474
12475                                 if (cfg->backend->have_tls_get && ad_ins && jit_tls_ins) {
12476                                         NEW_BBLOCK (cfg, next_bb);
12477                                         NEW_BBLOCK (cfg, call_bb);
12478
12479                                         if (cfg->compile_aot) {
12480                                                 /* AOT code is only used in the root domain */
12481                                                 EMIT_NEW_PCONST (cfg, domain_ins, NULL);
12482                                         } else {
12483                                                 EMIT_NEW_PCONST (cfg, domain_ins, cfg->domain);
12484                                         }
12485                                         MONO_ADD_INS (cfg->cbb, ad_ins);
12486                                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, ad_ins->dreg, domain_ins->dreg);
12487                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, call_bb);
12488
12489                                         MONO_ADD_INS (cfg->cbb, jit_tls_ins);
12490                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, jit_tls_ins->dreg, 0);
12491                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, call_bb);
12492
12493                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, next_bb);
12494                                         MONO_START_BB (cfg, call_bb);
12495                                 }
12496
12497                                 if (cfg->compile_aot) {
12498                                         /* AOT code is only used in the root domain */
12499                                         EMIT_NEW_PCONST (cfg, args [0], NULL);
12500                                 } else {
12501                                         EMIT_NEW_PCONST (cfg, args [0], cfg->domain);
12502                                 }
12503                                 ins = mono_emit_jit_icall (cfg, mono_jit_thread_attach, args);
12504                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12505
12506                                 if (next_bb)
12507                                         MONO_START_BB (cfg, next_bb);
12508                                 ip += 2;
12509                                 break;
12510                         }
12511                         case CEE_MONO_JIT_DETACH: {
12512                                 MonoInst *args [16];
12513
12514                                 /* Restore the original domain */
12515                                 dreg = alloc_ireg (cfg);
12516                                 EMIT_NEW_UNALU (cfg, args [0], OP_MOVE, dreg, cfg->orig_domain_var->dreg);
12517                                 mono_emit_jit_icall (cfg, mono_jit_set_domain, args);
12518                                 ip += 2;
12519                                 break;
12520                         }
12521                         default:
12522                                 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
12523                                 break;
12524                         }
12525                         break;
12526                 }
12527
12528                 case CEE_PREFIX1: {
12529                         CHECK_OPSIZE (2);
12530                         switch (ip [1]) {
12531                         case CEE_ARGLIST: {
12532                                 /* somewhat similar to LDTOKEN */
12533                                 MonoInst *addr, *vtvar;
12534                                 CHECK_STACK_OVF (1);
12535                                 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL); 
12536
12537                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
12538                                 EMIT_NEW_UNALU (cfg, ins, OP_ARGLIST, -1, addr->dreg);
12539
12540                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
12541                                 ins->type = STACK_VTYPE;
12542                                 ins->klass = mono_defaults.argumenthandle_class;
12543                                 *sp++ = ins;
12544                                 ip += 2;
12545                                 break;
12546                         }
12547                         case CEE_CEQ:
12548                         case CEE_CGT:
12549                         case CEE_CGT_UN:
12550                         case CEE_CLT:
12551                         case CEE_CLT_UN: {
12552                                 MonoInst *cmp, *arg1, *arg2;
12553
12554                                 CHECK_STACK (2);
12555                                 sp -= 2;
12556                                 arg1 = sp [0];
12557                                 arg2 = sp [1];
12558
12559                                 /*
12560                                  * The following transforms:
12561                                  *    CEE_CEQ    into OP_CEQ
12562                                  *    CEE_CGT    into OP_CGT
12563                                  *    CEE_CGT_UN into OP_CGT_UN
12564                                  *    CEE_CLT    into OP_CLT
12565                                  *    CEE_CLT_UN into OP_CLT_UN
12566                                  */
12567                                 MONO_INST_NEW (cfg, cmp, (OP_CEQ - CEE_CEQ) + ip [1]);
12568
12569                                 MONO_INST_NEW (cfg, ins, cmp->opcode);
12570                                 cmp->sreg1 = arg1->dreg;
12571                                 cmp->sreg2 = arg2->dreg;
12572                                 type_from_op (cfg, cmp, arg1, arg2);
12573                                 CHECK_TYPE (cmp);
12574                                 add_widen_op (cfg, cmp, &arg1, &arg2);
12575                                 if ((arg1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((arg1->type == STACK_PTR) || (arg1->type == STACK_OBJ) || (arg1->type == STACK_MP))))
12576                                         cmp->opcode = OP_LCOMPARE;
12577                                 else if (arg1->type == STACK_R4)
12578                                         cmp->opcode = OP_RCOMPARE;
12579                                 else if (arg1->type == STACK_R8)
12580                                         cmp->opcode = OP_FCOMPARE;
12581                                 else
12582                                         cmp->opcode = OP_ICOMPARE;
12583                                 MONO_ADD_INS (cfg->cbb, cmp);
12584                                 ins->type = STACK_I4;
12585                                 ins->dreg = alloc_dreg (cfg, ins->type);
12586                                 type_from_op (cfg, ins, arg1, arg2);
12587
12588                                 if (cmp->opcode == OP_FCOMPARE || cmp->opcode == OP_RCOMPARE) {
12589                                         /*
12590                                          * The backends expect the fceq opcodes to do the
12591                                          * comparison too.
12592                                          */
12593                                         ins->sreg1 = cmp->sreg1;
12594                                         ins->sreg2 = cmp->sreg2;
12595                                         NULLIFY_INS (cmp);
12596                                 }
12597                                 MONO_ADD_INS (cfg->cbb, ins);
12598                                 *sp++ = ins;
12599                                 ip += 2;
12600                                 break;
12601                         }
12602                         case CEE_LDFTN: {
12603                                 MonoInst *argconst;
12604                                 MonoMethod *cil_method;
12605
12606                                 CHECK_STACK_OVF (1);
12607                                 CHECK_OPSIZE (6);
12608                                 n = read32 (ip + 2);
12609                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
12610                                 if (!cmethod || mono_loader_get_last_error ())
12611                                         LOAD_ERROR;
12612                                 mono_class_init (cmethod->klass);
12613
12614                                 mono_save_token_info (cfg, image, n, cmethod);
12615
12616                                 context_used = mini_method_check_context_used (cfg, cmethod);
12617
12618                                 cil_method = cmethod;
12619                                 if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
12620                                         METHOD_ACCESS_FAILURE (method, cil_method);
12621
12622                                 if (mono_security_core_clr_enabled ())
12623                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
12624
12625                                 /* 
12626                                  * Optimize the common case of ldftn+delegate creation
12627                                  */
12628                                 if ((sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 6) && (ip [6] == CEE_NEWOBJ)) {
12629                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
12630                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
12631                                                 MonoInst *target_ins, *handle_ins;
12632                                                 MonoMethod *invoke;
12633                                                 int invoke_context_used;
12634
12635                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
12636                                                 if (!invoke || !mono_method_signature (invoke))
12637                                                         LOAD_ERROR;
12638
12639                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
12640
12641                                                 target_ins = sp [-1];
12642
12643                                                 if (mono_security_core_clr_enabled ())
12644                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
12645
12646                                                 if (!(cmethod->flags & METHOD_ATTRIBUTE_STATIC)) {
12647                                                         /*LAME IMPL: We must not add a null check for virtual invoke delegates.*/
12648                                                         if (mono_method_signature (invoke)->param_count == mono_method_signature (cmethod)->param_count) {
12649                                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, target_ins->dreg, 0);
12650                                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "ArgumentException");
12651                                                         }
12652                                                 }
12653
12654                                                 /* FIXME: SGEN support */
12655                                                 if (invoke_context_used == 0) {
12656                                                         ip += 6;
12657                                                         if (cfg->verbose_level > 3)
12658                                                                 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));
12659                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, FALSE))) {
12660                                                                 sp --;
12661                                                                 *sp = handle_ins;
12662                                                                 CHECK_CFG_EXCEPTION;
12663                                                                 ip += 5;
12664                                                                 sp ++;
12665                                                                 break;
12666                                                         }
12667                                                         ip -= 6;
12668                                                 }
12669                                         }
12670                                 }
12671
12672                                 argconst = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD);
12673                                 ins = mono_emit_jit_icall (cfg, mono_ldftn, &argconst);
12674                                 *sp++ = ins;
12675                                 
12676                                 ip += 6;
12677                                 inline_costs += 10 * num_calls++;
12678                                 break;
12679                         }
12680                         case CEE_LDVIRTFTN: {
12681                                 MonoInst *args [2];
12682
12683                                 CHECK_STACK (1);
12684                                 CHECK_OPSIZE (6);
12685                                 n = read32 (ip + 2);
12686                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
12687                                 if (!cmethod || mono_loader_get_last_error ())
12688                                         LOAD_ERROR;
12689                                 mono_class_init (cmethod->klass);
12690  
12691                                 context_used = mini_method_check_context_used (cfg, cmethod);
12692
12693                                 if (mono_security_core_clr_enabled ())
12694                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
12695
12696                                 /*
12697                                  * Optimize the common case of ldvirtftn+delegate creation
12698                                  */
12699                                 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)) {
12700                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
12701                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
12702                                                 MonoInst *target_ins, *handle_ins;
12703                                                 MonoMethod *invoke;
12704                                                 int invoke_context_used;
12705                                                 gboolean is_virtual = cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL;
12706
12707                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
12708                                                 if (!invoke || !mono_method_signature (invoke))
12709                                                         LOAD_ERROR;
12710
12711                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
12712
12713                                                 target_ins = sp [-1];
12714
12715                                                 if (mono_security_core_clr_enabled ())
12716                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
12717
12718                                                 /* FIXME: SGEN support */
12719                                                 if (invoke_context_used == 0 || cfg->llvm_only) {
12720                                                         ip += 6;
12721                                                         if (cfg->verbose_level > 3)
12722                                                                 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));
12723                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, is_virtual))) {
12724                                                                 sp -= 2;
12725                                                                 *sp = handle_ins;
12726                                                                 CHECK_CFG_EXCEPTION;
12727                                                                 ip += 5;
12728                                                                 sp ++;
12729                                                                 break;
12730                                                         }
12731                                                         ip -= 6;
12732                                                 }
12733                                         }
12734                                 }
12735
12736                                 --sp;
12737                                 args [0] = *sp;
12738
12739                                 args [1] = emit_get_rgctx_method (cfg, context_used,
12740                                                                                                   cmethod, MONO_RGCTX_INFO_METHOD);
12741
12742                                 if (context_used)
12743                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn_gshared, args);
12744                                 else
12745                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn, args);
12746
12747                                 ip += 6;
12748                                 inline_costs += 10 * num_calls++;
12749                                 break;
12750                         }
12751                         case CEE_LDARG:
12752                                 CHECK_STACK_OVF (1);
12753                                 CHECK_OPSIZE (4);
12754                                 n = read16 (ip + 2);
12755                                 CHECK_ARG (n);
12756                                 EMIT_NEW_ARGLOAD (cfg, ins, n);
12757                                 *sp++ = ins;
12758                                 ip += 4;
12759                                 break;
12760                         case CEE_LDARGA:
12761                                 CHECK_STACK_OVF (1);
12762                                 CHECK_OPSIZE (4);
12763                                 n = read16 (ip + 2);
12764                                 CHECK_ARG (n);
12765                                 NEW_ARGLOADA (cfg, ins, n);
12766                                 MONO_ADD_INS (cfg->cbb, ins);
12767                                 *sp++ = ins;
12768                                 ip += 4;
12769                                 break;
12770                         case CEE_STARG:
12771                                 CHECK_STACK (1);
12772                                 --sp;
12773                                 CHECK_OPSIZE (4);
12774                                 n = read16 (ip + 2);
12775                                 CHECK_ARG (n);
12776                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
12777                                         UNVERIFIED;
12778                                 EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
12779                                 ip += 4;
12780                                 break;
12781                         case CEE_LDLOC:
12782                                 CHECK_STACK_OVF (1);
12783                                 CHECK_OPSIZE (4);
12784                                 n = read16 (ip + 2);
12785                                 CHECK_LOCAL (n);
12786                                 EMIT_NEW_LOCLOAD (cfg, ins, n);
12787                                 *sp++ = ins;
12788                                 ip += 4;
12789                                 break;
12790                         case CEE_LDLOCA: {
12791                                 unsigned char *tmp_ip;
12792                                 CHECK_STACK_OVF (1);
12793                                 CHECK_OPSIZE (4);
12794                                 n = read16 (ip + 2);
12795                                 CHECK_LOCAL (n);
12796
12797                                 if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 2))) {
12798                                         ip = tmp_ip;
12799                                         inline_costs += 1;
12800                                         break;
12801                                 }                       
12802                                 
12803                                 EMIT_NEW_LOCLOADA (cfg, ins, n);
12804                                 *sp++ = ins;
12805                                 ip += 4;
12806                                 break;
12807                         }
12808                         case CEE_STLOC:
12809                                 CHECK_STACK (1);
12810                                 --sp;
12811                                 CHECK_OPSIZE (4);
12812                                 n = read16 (ip + 2);
12813                                 CHECK_LOCAL (n);
12814                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
12815                                         UNVERIFIED;
12816                                 emit_stloc_ir (cfg, sp, header, n);
12817                                 ip += 4;
12818                                 inline_costs += 1;
12819                                 break;
12820                         case CEE_LOCALLOC:
12821                                 CHECK_STACK (1);
12822                                 --sp;
12823                                 if (sp != stack_start) 
12824                                         UNVERIFIED;
12825                                 if (cfg->method != method) 
12826                                         /* 
12827                                          * Inlining this into a loop in a parent could lead to 
12828                                          * stack overflows which is different behavior than the
12829                                          * non-inlined case, thus disable inlining in this case.
12830                                          */
12831                                         INLINE_FAILURE("localloc");
12832
12833                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
12834                                 ins->dreg = alloc_preg (cfg);
12835                                 ins->sreg1 = sp [0]->dreg;
12836                                 ins->type = STACK_PTR;
12837                                 MONO_ADD_INS (cfg->cbb, ins);
12838
12839                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12840                                 if (init_locals)
12841                                         ins->flags |= MONO_INST_INIT;
12842
12843                                 *sp++ = ins;
12844                                 ip += 2;
12845                                 break;
12846                         case CEE_ENDFILTER: {
12847                                 MonoExceptionClause *clause, *nearest;
12848                                 int cc;
12849
12850                                 CHECK_STACK (1);
12851                                 --sp;
12852                                 if ((sp != stack_start) || (sp [0]->type != STACK_I4)) 
12853                                         UNVERIFIED;
12854                                 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
12855                                 ins->sreg1 = (*sp)->dreg;
12856                                 MONO_ADD_INS (cfg->cbb, ins);
12857                                 start_new_bblock = 1;
12858                                 ip += 2;
12859
12860                                 nearest = NULL;
12861                                 for (cc = 0; cc < header->num_clauses; ++cc) {
12862                                         clause = &header->clauses [cc];
12863                                         if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
12864                                                 ((ip - header->code) > clause->data.filter_offset && (ip - header->code) <= clause->handler_offset) &&
12865                                             (!nearest || (clause->data.filter_offset < nearest->data.filter_offset)))
12866                                                 nearest = clause;
12867                                 }
12868                                 g_assert (nearest);
12869                                 if ((ip - header->code) != nearest->handler_offset)
12870                                         UNVERIFIED;
12871
12872                                 break;
12873                         }
12874                         case CEE_UNALIGNED_:
12875                                 ins_flag |= MONO_INST_UNALIGNED;
12876                                 /* FIXME: record alignment? we can assume 1 for now */
12877                                 CHECK_OPSIZE (3);
12878                                 ip += 3;
12879                                 break;
12880                         case CEE_VOLATILE_:
12881                                 ins_flag |= MONO_INST_VOLATILE;
12882                                 ip += 2;
12883                                 break;
12884                         case CEE_TAIL_:
12885                                 ins_flag   |= MONO_INST_TAILCALL;
12886                                 cfg->flags |= MONO_CFG_HAS_TAIL;
12887                                 /* Can't inline tail calls at this time */
12888                                 inline_costs += 100000;
12889                                 ip += 2;
12890                                 break;
12891                         case CEE_INITOBJ:
12892                                 CHECK_STACK (1);
12893                                 --sp;
12894                                 CHECK_OPSIZE (6);
12895                                 token = read32 (ip + 2);
12896                                 klass = mini_get_class (method, token, generic_context);
12897                                 CHECK_TYPELOAD (klass);
12898                                 if (generic_class_is_reference_type (cfg, klass))
12899                                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, sp [0]->dreg, 0, 0);
12900                                 else
12901                                         mini_emit_initobj (cfg, *sp, NULL, klass);
12902                                 ip += 6;
12903                                 inline_costs += 1;
12904                                 break;
12905                         case CEE_CONSTRAINED_:
12906                                 CHECK_OPSIZE (6);
12907                                 token = read32 (ip + 2);
12908                                 constrained_class = mini_get_class (method, token, generic_context);
12909                                 CHECK_TYPELOAD (constrained_class);
12910                                 ip += 6;
12911                                 break;
12912                         case CEE_CPBLK:
12913                         case CEE_INITBLK: {
12914                                 MonoInst *iargs [3];
12915                                 CHECK_STACK (3);
12916                                 sp -= 3;
12917
12918                                 /* Skip optimized paths for volatile operations. */
12919                                 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)) {
12920                                         mini_emit_memcpy (cfg, sp [0]->dreg, 0, sp [1]->dreg, 0, sp [2]->inst_c0, 0);
12921                                 } 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)) {
12922                                         /* emit_memset only works when val == 0 */
12923                                         mini_emit_memset (cfg, sp [0]->dreg, 0, sp [2]->inst_c0, sp [1]->inst_c0, 0);
12924                                 } else {
12925                                         MonoInst *call;
12926                                         iargs [0] = sp [0];
12927                                         iargs [1] = sp [1];
12928                                         iargs [2] = sp [2];
12929                                         if (ip [1] == CEE_CPBLK) {
12930                                                 /*
12931                                                  * FIXME: It's unclear whether we should be emitting both the acquire
12932                                                  * and release barriers for cpblk. It is technically both a load and
12933                                                  * store operation, so it seems like that's the sensible thing to do.
12934                                                  *
12935                                                  * FIXME: We emit full barriers on both sides of the operation for
12936                                                  * simplicity. We should have a separate atomic memcpy method instead.
12937                                                  */
12938                                                 MonoMethod *memcpy_method = get_memcpy_method ();
12939
12940                                                 if (ins_flag & MONO_INST_VOLATILE)
12941                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
12942
12943                                                 call = mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
12944                                                 call->flags |= ins_flag;
12945
12946                                                 if (ins_flag & MONO_INST_VOLATILE)
12947                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
12948                                         } else {
12949                                                 MonoMethod *memset_method = get_memset_method ();
12950                                                 if (ins_flag & MONO_INST_VOLATILE) {
12951                                                         /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
12952                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
12953                                                 }
12954                                                 call = mono_emit_method_call (cfg, memset_method, iargs, NULL);
12955                                                 call->flags |= ins_flag;
12956                                         }
12957                                 }
12958                                 ip += 2;
12959                                 ins_flag = 0;
12960                                 inline_costs += 1;
12961                                 break;
12962                         }
12963                         case CEE_NO_:
12964                                 CHECK_OPSIZE (3);
12965                                 if (ip [2] & 0x1)
12966                                         ins_flag |= MONO_INST_NOTYPECHECK;
12967                                 if (ip [2] & 0x2)
12968                                         ins_flag |= MONO_INST_NORANGECHECK;
12969                                 /* we ignore the no-nullcheck for now since we
12970                                  * really do it explicitly only when doing callvirt->call
12971                                  */
12972                                 ip += 3;
12973                                 break;
12974                         case CEE_RETHROW: {
12975                                 MonoInst *load;
12976                                 int handler_offset = -1;
12977
12978                                 for (i = 0; i < header->num_clauses; ++i) {
12979                                         MonoExceptionClause *clause = &header->clauses [i];
12980                                         if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
12981                                                 handler_offset = clause->handler_offset;
12982                                                 break;
12983                                         }
12984                                 }
12985
12986                                 cfg->cbb->flags |= BB_EXCEPTION_UNSAFE;
12987
12988                                 if (handler_offset == -1)
12989                                         UNVERIFIED;
12990
12991                                 EMIT_NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
12992                                 MONO_INST_NEW (cfg, ins, OP_RETHROW);
12993                                 ins->sreg1 = load->dreg;
12994                                 MONO_ADD_INS (cfg->cbb, ins);
12995
12996                                 MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
12997                                 MONO_ADD_INS (cfg->cbb, ins);
12998
12999                                 sp = stack_start;
13000                                 link_bblock (cfg, cfg->cbb, end_bblock);
13001                                 start_new_bblock = 1;
13002                                 ip += 2;
13003                                 break;
13004                         }
13005                         case CEE_SIZEOF: {
13006                                 guint32 val;
13007                                 int ialign;
13008
13009                                 CHECK_STACK_OVF (1);
13010                                 CHECK_OPSIZE (6);
13011                                 token = read32 (ip + 2);
13012                                 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC && !image_is_dynamic (method->klass->image) && !generic_context) {
13013                                         MonoType *type = mono_type_create_from_typespec_checked (image, token, &cfg->error);
13014                                         CHECK_CFG_ERROR;
13015
13016                                         val = mono_type_size (type, &ialign);
13017                                 } else {
13018                                         MonoClass *klass = mini_get_class (method, token, generic_context);
13019                                         CHECK_TYPELOAD (klass);
13020
13021                                         val = mono_type_size (&klass->byval_arg, &ialign);
13022
13023                                         if (mini_is_gsharedvt_klass (klass))
13024                                                 GSHAREDVT_FAILURE (*ip);
13025                                 }
13026                                 EMIT_NEW_ICONST (cfg, ins, val);
13027                                 *sp++= ins;
13028                                 ip += 6;
13029                                 break;
13030                         }
13031                         case CEE_REFANYTYPE: {
13032                                 MonoInst *src_var, *src;
13033
13034                                 GSHAREDVT_FAILURE (*ip);
13035
13036                                 CHECK_STACK (1);
13037                                 --sp;
13038
13039                                 // FIXME:
13040                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
13041                                 if (!src_var)
13042                                         src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
13043                                 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
13044                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &mono_defaults.typehandle_class->byval_arg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type));
13045                                 *sp++ = ins;
13046                                 ip += 2;
13047                                 break;
13048                         }
13049                         case CEE_READONLY_:
13050                                 readonly = TRUE;
13051                                 ip += 2;
13052                                 break;
13053
13054                         case CEE_UNUSED56:
13055                         case CEE_UNUSED57:
13056                         case CEE_UNUSED70:
13057                         case CEE_UNUSED:
13058                         case CEE_UNUSED99:
13059                                 UNVERIFIED;
13060                                 
13061                         default:
13062                                 g_warning ("opcode 0xfe 0x%02x not handled", ip [1]);
13063                                 UNVERIFIED;
13064                         }
13065                         break;
13066                 }
13067                 case CEE_UNUSED58:
13068                 case CEE_UNUSED1:
13069                         UNVERIFIED;
13070
13071                 default:
13072                         g_warning ("opcode 0x%02x not handled", *ip);
13073                         UNVERIFIED;
13074                 }
13075         }
13076         if (start_new_bblock != 1)
13077                 UNVERIFIED;
13078
13079         cfg->cbb->cil_length = ip - cfg->cbb->cil_code;
13080         if (cfg->cbb->next_bb) {
13081                 /* This could already be set because of inlining, #693905 */
13082                 MonoBasicBlock *bb = cfg->cbb;
13083
13084                 while (bb->next_bb)
13085                         bb = bb->next_bb;
13086                 bb->next_bb = end_bblock;
13087         } else {
13088                 cfg->cbb->next_bb = end_bblock;
13089         }
13090
13091         if (cfg->method == method && cfg->domainvar) {
13092                 MonoInst *store;
13093                 MonoInst *get_domain;
13094
13095                 cfg->cbb = init_localsbb;
13096
13097                 if ((get_domain = mono_get_domain_intrinsic (cfg))) {
13098                         MONO_ADD_INS (cfg->cbb, get_domain);
13099                 } else {
13100                         get_domain = mono_emit_jit_icall (cfg, mono_domain_get, NULL);
13101                 }
13102                 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, get_domain);
13103                 MONO_ADD_INS (cfg->cbb, store);
13104         }
13105
13106 #if defined(TARGET_POWERPC) || defined(TARGET_X86)
13107         if (cfg->compile_aot)
13108                 /* FIXME: The plt slots require a GOT var even if the method doesn't use it */
13109                 mono_get_got_var (cfg);
13110 #endif
13111
13112         if (cfg->method == method && cfg->got_var)
13113                 mono_emit_load_got_addr (cfg);
13114
13115         if (init_localsbb) {
13116                 cfg->cbb = init_localsbb;
13117                 cfg->ip = NULL;
13118                 for (i = 0; i < header->num_locals; ++i) {
13119                         emit_init_local (cfg, i, header->locals [i], init_locals);
13120                 }
13121         }
13122
13123         if (cfg->init_ref_vars && cfg->method == method) {
13124                 /* Emit initialization for ref vars */
13125                 // FIXME: Avoid duplication initialization for IL locals.
13126                 for (i = 0; i < cfg->num_varinfo; ++i) {
13127                         MonoInst *ins = cfg->varinfo [i];
13128
13129                         if (ins->opcode == OP_LOCAL && ins->type == STACK_OBJ)
13130                                 MONO_EMIT_NEW_PCONST (cfg, ins->dreg, NULL);
13131                 }
13132         }
13133
13134         if (cfg->lmf_var && cfg->method == method && !cfg->llvm_only) {
13135                 cfg->cbb = init_localsbb;
13136                 emit_push_lmf (cfg);
13137         }
13138
13139         cfg->cbb = init_localsbb;
13140         emit_instrumentation_call (cfg, mono_profiler_method_enter);
13141
13142         if (seq_points) {
13143                 MonoBasicBlock *bb;
13144
13145                 /*
13146                  * Make seq points at backward branch targets interruptable.
13147                  */
13148                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
13149                         if (bb->code && bb->in_count > 1 && bb->code->opcode == OP_SEQ_POINT)
13150                                 bb->code->flags |= MONO_INST_SINGLE_STEP_LOC;
13151         }
13152
13153         /* Add a sequence point for method entry/exit events */
13154         if (seq_points && cfg->gen_sdb_seq_points) {
13155                 NEW_SEQ_POINT (cfg, ins, METHOD_ENTRY_IL_OFFSET, FALSE);
13156                 MONO_ADD_INS (init_localsbb, ins);
13157                 NEW_SEQ_POINT (cfg, ins, METHOD_EXIT_IL_OFFSET, FALSE);
13158                 MONO_ADD_INS (cfg->bb_exit, ins);
13159         }
13160
13161         /*
13162          * Add seq points for IL offsets which have line number info, but wasn't generated a seq point during JITting because
13163          * the code they refer to was dead (#11880).
13164          */
13165         if (sym_seq_points) {
13166                 for (i = 0; i < header->code_size; ++i) {
13167                         if (mono_bitset_test_fast (seq_point_locs, i) && !mono_bitset_test_fast (seq_point_set_locs, i)) {
13168                                 MonoInst *ins;
13169
13170                                 NEW_SEQ_POINT (cfg, ins, i, FALSE);
13171                                 mono_add_seq_point (cfg, NULL, ins, SEQ_POINT_NATIVE_OFFSET_DEAD_CODE);
13172                         }
13173                 }
13174         }
13175
13176         cfg->ip = NULL;
13177
13178         if (cfg->method == method) {
13179                 MonoBasicBlock *bb;
13180                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13181                         bb->region = mono_find_block_region (cfg, bb->real_offset);
13182                         if (cfg->spvars)
13183                                 mono_create_spvar_for_region (cfg, bb->region);
13184                         if (cfg->verbose_level > 2)
13185                                 printf ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
13186                 }
13187         }
13188
13189         if (inline_costs < 0) {
13190                 char *mname;
13191
13192                 /* Method is too large */
13193                 mname = mono_method_full_name (method, TRUE);
13194                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
13195                 cfg->exception_message = g_strdup_printf ("Method %s is too complex.", mname);
13196                 g_free (mname);
13197         }
13198
13199         if ((cfg->verbose_level > 2) && (cfg->method == method)) 
13200                 mono_print_code (cfg, "AFTER METHOD-TO-IR");
13201
13202         goto cleanup;
13203
13204 mono_error_exit:
13205         g_assert (!mono_error_ok (&cfg->error));
13206         goto cleanup;
13207  
13208  exception_exit:
13209         g_assert (cfg->exception_type != MONO_EXCEPTION_NONE);
13210         goto cleanup;
13211
13212  unverified:
13213         set_exception_type_from_invalid_il (cfg, method, ip);
13214         goto cleanup;
13215
13216  cleanup:
13217         g_slist_free (class_inits);
13218         mono_basic_block_free (original_bb);
13219         cfg->dont_inline = g_list_remove (cfg->dont_inline, method);
13220         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
13221         if (cfg->exception_type)
13222                 return -1;
13223         else
13224                 return inline_costs;
13225 }
13226
13227 static int
13228 store_membase_reg_to_store_membase_imm (int opcode)
13229 {
13230         switch (opcode) {
13231         case OP_STORE_MEMBASE_REG:
13232                 return OP_STORE_MEMBASE_IMM;
13233         case OP_STOREI1_MEMBASE_REG:
13234                 return OP_STOREI1_MEMBASE_IMM;
13235         case OP_STOREI2_MEMBASE_REG:
13236                 return OP_STOREI2_MEMBASE_IMM;
13237         case OP_STOREI4_MEMBASE_REG:
13238                 return OP_STOREI4_MEMBASE_IMM;
13239         case OP_STOREI8_MEMBASE_REG:
13240                 return OP_STOREI8_MEMBASE_IMM;
13241         default:
13242                 g_assert_not_reached ();
13243         }
13244
13245         return -1;
13246 }               
13247
13248 int
13249 mono_op_to_op_imm (int opcode)
13250 {
13251         switch (opcode) {
13252         case OP_IADD:
13253                 return OP_IADD_IMM;
13254         case OP_ISUB:
13255                 return OP_ISUB_IMM;
13256         case OP_IDIV:
13257                 return OP_IDIV_IMM;
13258         case OP_IDIV_UN:
13259                 return OP_IDIV_UN_IMM;
13260         case OP_IREM:
13261                 return OP_IREM_IMM;
13262         case OP_IREM_UN:
13263                 return OP_IREM_UN_IMM;
13264         case OP_IMUL:
13265                 return OP_IMUL_IMM;
13266         case OP_IAND:
13267                 return OP_IAND_IMM;
13268         case OP_IOR:
13269                 return OP_IOR_IMM;
13270         case OP_IXOR:
13271                 return OP_IXOR_IMM;
13272         case OP_ISHL:
13273                 return OP_ISHL_IMM;
13274         case OP_ISHR:
13275                 return OP_ISHR_IMM;
13276         case OP_ISHR_UN:
13277                 return OP_ISHR_UN_IMM;
13278
13279         case OP_LADD:
13280                 return OP_LADD_IMM;
13281         case OP_LSUB:
13282                 return OP_LSUB_IMM;
13283         case OP_LAND:
13284                 return OP_LAND_IMM;
13285         case OP_LOR:
13286                 return OP_LOR_IMM;
13287         case OP_LXOR:
13288                 return OP_LXOR_IMM;
13289         case OP_LSHL:
13290                 return OP_LSHL_IMM;
13291         case OP_LSHR:
13292                 return OP_LSHR_IMM;
13293         case OP_LSHR_UN:
13294                 return OP_LSHR_UN_IMM;
13295 #if SIZEOF_REGISTER == 8
13296         case OP_LREM:
13297                 return OP_LREM_IMM;
13298 #endif
13299
13300         case OP_COMPARE:
13301                 return OP_COMPARE_IMM;
13302         case OP_ICOMPARE:
13303                 return OP_ICOMPARE_IMM;
13304         case OP_LCOMPARE:
13305                 return OP_LCOMPARE_IMM;
13306
13307         case OP_STORE_MEMBASE_REG:
13308                 return OP_STORE_MEMBASE_IMM;
13309         case OP_STOREI1_MEMBASE_REG:
13310                 return OP_STOREI1_MEMBASE_IMM;
13311         case OP_STOREI2_MEMBASE_REG:
13312                 return OP_STOREI2_MEMBASE_IMM;
13313         case OP_STOREI4_MEMBASE_REG:
13314                 return OP_STOREI4_MEMBASE_IMM;
13315
13316 #if defined(TARGET_X86) || defined (TARGET_AMD64)
13317         case OP_X86_PUSH:
13318                 return OP_X86_PUSH_IMM;
13319         case OP_X86_COMPARE_MEMBASE_REG:
13320                 return OP_X86_COMPARE_MEMBASE_IMM;
13321 #endif
13322 #if defined(TARGET_AMD64)
13323         case OP_AMD64_ICOMPARE_MEMBASE_REG:
13324                 return OP_AMD64_ICOMPARE_MEMBASE_IMM;
13325 #endif
13326         case OP_VOIDCALL_REG:
13327                 return OP_VOIDCALL;
13328         case OP_CALL_REG:
13329                 return OP_CALL;
13330         case OP_LCALL_REG:
13331                 return OP_LCALL;
13332         case OP_FCALL_REG:
13333                 return OP_FCALL;
13334         case OP_LOCALLOC:
13335                 return OP_LOCALLOC_IMM;
13336         }
13337
13338         return -1;
13339 }
13340
13341 static int
13342 ldind_to_load_membase (int opcode)
13343 {
13344         switch (opcode) {
13345         case CEE_LDIND_I1:
13346                 return OP_LOADI1_MEMBASE;
13347         case CEE_LDIND_U1:
13348                 return OP_LOADU1_MEMBASE;
13349         case CEE_LDIND_I2:
13350                 return OP_LOADI2_MEMBASE;
13351         case CEE_LDIND_U2:
13352                 return OP_LOADU2_MEMBASE;
13353         case CEE_LDIND_I4:
13354                 return OP_LOADI4_MEMBASE;
13355         case CEE_LDIND_U4:
13356                 return OP_LOADU4_MEMBASE;
13357         case CEE_LDIND_I:
13358                 return OP_LOAD_MEMBASE;
13359         case CEE_LDIND_REF:
13360                 return OP_LOAD_MEMBASE;
13361         case CEE_LDIND_I8:
13362                 return OP_LOADI8_MEMBASE;
13363         case CEE_LDIND_R4:
13364                 return OP_LOADR4_MEMBASE;
13365         case CEE_LDIND_R8:
13366                 return OP_LOADR8_MEMBASE;
13367         default:
13368                 g_assert_not_reached ();
13369         }
13370
13371         return -1;
13372 }
13373
13374 static int
13375 stind_to_store_membase (int opcode)
13376 {
13377         switch (opcode) {
13378         case CEE_STIND_I1:
13379                 return OP_STOREI1_MEMBASE_REG;
13380         case CEE_STIND_I2:
13381                 return OP_STOREI2_MEMBASE_REG;
13382         case CEE_STIND_I4:
13383                 return OP_STOREI4_MEMBASE_REG;
13384         case CEE_STIND_I:
13385         case CEE_STIND_REF:
13386                 return OP_STORE_MEMBASE_REG;
13387         case CEE_STIND_I8:
13388                 return OP_STOREI8_MEMBASE_REG;
13389         case CEE_STIND_R4:
13390                 return OP_STORER4_MEMBASE_REG;
13391         case CEE_STIND_R8:
13392                 return OP_STORER8_MEMBASE_REG;
13393         default:
13394                 g_assert_not_reached ();
13395         }
13396
13397         return -1;
13398 }
13399
13400 int
13401 mono_load_membase_to_load_mem (int opcode)
13402 {
13403         // FIXME: Add a MONO_ARCH_HAVE_LOAD_MEM macro
13404 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13405         switch (opcode) {
13406         case OP_LOAD_MEMBASE:
13407                 return OP_LOAD_MEM;
13408         case OP_LOADU1_MEMBASE:
13409                 return OP_LOADU1_MEM;
13410         case OP_LOADU2_MEMBASE:
13411                 return OP_LOADU2_MEM;
13412         case OP_LOADI4_MEMBASE:
13413                 return OP_LOADI4_MEM;
13414         case OP_LOADU4_MEMBASE:
13415                 return OP_LOADU4_MEM;
13416 #if SIZEOF_REGISTER == 8
13417         case OP_LOADI8_MEMBASE:
13418                 return OP_LOADI8_MEM;
13419 #endif
13420         }
13421 #endif
13422
13423         return -1;
13424 }
13425
13426 static inline int
13427 op_to_op_dest_membase (int store_opcode, int opcode)
13428 {
13429 #if defined(TARGET_X86)
13430         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG)))
13431                 return -1;
13432
13433         switch (opcode) {
13434         case OP_IADD:
13435                 return OP_X86_ADD_MEMBASE_REG;
13436         case OP_ISUB:
13437                 return OP_X86_SUB_MEMBASE_REG;
13438         case OP_IAND:
13439                 return OP_X86_AND_MEMBASE_REG;
13440         case OP_IOR:
13441                 return OP_X86_OR_MEMBASE_REG;
13442         case OP_IXOR:
13443                 return OP_X86_XOR_MEMBASE_REG;
13444         case OP_ADD_IMM:
13445         case OP_IADD_IMM:
13446                 return OP_X86_ADD_MEMBASE_IMM;
13447         case OP_SUB_IMM:
13448         case OP_ISUB_IMM:
13449                 return OP_X86_SUB_MEMBASE_IMM;
13450         case OP_AND_IMM:
13451         case OP_IAND_IMM:
13452                 return OP_X86_AND_MEMBASE_IMM;
13453         case OP_OR_IMM:
13454         case OP_IOR_IMM:
13455                 return OP_X86_OR_MEMBASE_IMM;
13456         case OP_XOR_IMM:
13457         case OP_IXOR_IMM:
13458                 return OP_X86_XOR_MEMBASE_IMM;
13459         case OP_MOVE:
13460                 return OP_NOP;
13461         }
13462 #endif
13463
13464 #if defined(TARGET_AMD64)
13465         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG) || (store_opcode == OP_STOREI8_MEMBASE_REG)))
13466                 return -1;
13467
13468         switch (opcode) {
13469         case OP_IADD:
13470                 return OP_X86_ADD_MEMBASE_REG;
13471         case OP_ISUB:
13472                 return OP_X86_SUB_MEMBASE_REG;
13473         case OP_IAND:
13474                 return OP_X86_AND_MEMBASE_REG;
13475         case OP_IOR:
13476                 return OP_X86_OR_MEMBASE_REG;
13477         case OP_IXOR:
13478                 return OP_X86_XOR_MEMBASE_REG;
13479         case OP_IADD_IMM:
13480                 return OP_X86_ADD_MEMBASE_IMM;
13481         case OP_ISUB_IMM:
13482                 return OP_X86_SUB_MEMBASE_IMM;
13483         case OP_IAND_IMM:
13484                 return OP_X86_AND_MEMBASE_IMM;
13485         case OP_IOR_IMM:
13486                 return OP_X86_OR_MEMBASE_IMM;
13487         case OP_IXOR_IMM:
13488                 return OP_X86_XOR_MEMBASE_IMM;
13489         case OP_LADD:
13490                 return OP_AMD64_ADD_MEMBASE_REG;
13491         case OP_LSUB:
13492                 return OP_AMD64_SUB_MEMBASE_REG;
13493         case OP_LAND:
13494                 return OP_AMD64_AND_MEMBASE_REG;
13495         case OP_LOR:
13496                 return OP_AMD64_OR_MEMBASE_REG;
13497         case OP_LXOR:
13498                 return OP_AMD64_XOR_MEMBASE_REG;
13499         case OP_ADD_IMM:
13500         case OP_LADD_IMM:
13501                 return OP_AMD64_ADD_MEMBASE_IMM;
13502         case OP_SUB_IMM:
13503         case OP_LSUB_IMM:
13504                 return OP_AMD64_SUB_MEMBASE_IMM;
13505         case OP_AND_IMM:
13506         case OP_LAND_IMM:
13507                 return OP_AMD64_AND_MEMBASE_IMM;
13508         case OP_OR_IMM:
13509         case OP_LOR_IMM:
13510                 return OP_AMD64_OR_MEMBASE_IMM;
13511         case OP_XOR_IMM:
13512         case OP_LXOR_IMM:
13513                 return OP_AMD64_XOR_MEMBASE_IMM;
13514         case OP_MOVE:
13515                 return OP_NOP;
13516         }
13517 #endif
13518
13519         return -1;
13520 }
13521
13522 static inline int
13523 op_to_op_store_membase (int store_opcode, int opcode)
13524 {
13525 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13526         switch (opcode) {
13527         case OP_ICEQ:
13528                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13529                         return OP_X86_SETEQ_MEMBASE;
13530         case OP_CNE:
13531                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13532                         return OP_X86_SETNE_MEMBASE;
13533         }
13534 #endif
13535
13536         return -1;
13537 }
13538
13539 static inline int
13540 op_to_op_src1_membase (MonoCompile *cfg, int load_opcode, int opcode)
13541 {
13542 #ifdef TARGET_X86
13543         /* FIXME: This has sign extension issues */
13544         /*
13545         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
13546                 return OP_X86_COMPARE_MEMBASE8_IMM;
13547         */
13548
13549         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
13550                 return -1;
13551
13552         switch (opcode) {
13553         case OP_X86_PUSH:
13554                 return OP_X86_PUSH_MEMBASE;
13555         case OP_COMPARE_IMM:
13556         case OP_ICOMPARE_IMM:
13557                 return OP_X86_COMPARE_MEMBASE_IMM;
13558         case OP_COMPARE:
13559         case OP_ICOMPARE:
13560                 return OP_X86_COMPARE_MEMBASE_REG;
13561         }
13562 #endif
13563
13564 #ifdef TARGET_AMD64
13565         /* FIXME: This has sign extension issues */
13566         /*
13567         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
13568                 return OP_X86_COMPARE_MEMBASE8_IMM;
13569         */
13570
13571         switch (opcode) {
13572         case OP_X86_PUSH:
13573                 if ((load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32) || (load_opcode == OP_LOADI8_MEMBASE))
13574                         return OP_X86_PUSH_MEMBASE;
13575                 break;
13576                 /* FIXME: This only works for 32 bit immediates
13577         case OP_COMPARE_IMM:
13578         case OP_LCOMPARE_IMM:
13579                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
13580                         return OP_AMD64_COMPARE_MEMBASE_IMM;
13581                 */
13582         case OP_ICOMPARE_IMM:
13583                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
13584                         return OP_AMD64_ICOMPARE_MEMBASE_IMM;
13585                 break;
13586         case OP_COMPARE:
13587         case OP_LCOMPARE:
13588                 if (cfg->backend->ilp32 && load_opcode == OP_LOAD_MEMBASE)
13589                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
13590                 if ((load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32) || (load_opcode == OP_LOADI8_MEMBASE))
13591                         return OP_AMD64_COMPARE_MEMBASE_REG;
13592                 break;
13593         case OP_ICOMPARE:
13594                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
13595                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
13596                 break;
13597         }
13598 #endif
13599
13600         return -1;
13601 }
13602
13603 static inline int
13604 op_to_op_src2_membase (MonoCompile *cfg, int load_opcode, int opcode)
13605 {
13606 #ifdef TARGET_X86
13607         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
13608                 return -1;
13609         
13610         switch (opcode) {
13611         case OP_COMPARE:
13612         case OP_ICOMPARE:
13613                 return OP_X86_COMPARE_REG_MEMBASE;
13614         case OP_IADD:
13615                 return OP_X86_ADD_REG_MEMBASE;
13616         case OP_ISUB:
13617                 return OP_X86_SUB_REG_MEMBASE;
13618         case OP_IAND:
13619                 return OP_X86_AND_REG_MEMBASE;
13620         case OP_IOR:
13621                 return OP_X86_OR_REG_MEMBASE;
13622         case OP_IXOR:
13623                 return OP_X86_XOR_REG_MEMBASE;
13624         }
13625 #endif
13626
13627 #ifdef TARGET_AMD64
13628         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE && cfg->backend->ilp32)) {
13629                 switch (opcode) {
13630                 case OP_ICOMPARE:
13631                         return OP_AMD64_ICOMPARE_REG_MEMBASE;
13632                 case OP_IADD:
13633                         return OP_X86_ADD_REG_MEMBASE;
13634                 case OP_ISUB:
13635                         return OP_X86_SUB_REG_MEMBASE;
13636                 case OP_IAND:
13637                         return OP_X86_AND_REG_MEMBASE;
13638                 case OP_IOR:
13639                         return OP_X86_OR_REG_MEMBASE;
13640                 case OP_IXOR:
13641                         return OP_X86_XOR_REG_MEMBASE;
13642                 }
13643         } else if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32)) {
13644                 switch (opcode) {
13645                 case OP_COMPARE:
13646                 case OP_LCOMPARE:
13647                         return OP_AMD64_COMPARE_REG_MEMBASE;
13648                 case OP_LADD:
13649                         return OP_AMD64_ADD_REG_MEMBASE;
13650                 case OP_LSUB:
13651                         return OP_AMD64_SUB_REG_MEMBASE;
13652                 case OP_LAND:
13653                         return OP_AMD64_AND_REG_MEMBASE;
13654                 case OP_LOR:
13655                         return OP_AMD64_OR_REG_MEMBASE;
13656                 case OP_LXOR:
13657                         return OP_AMD64_XOR_REG_MEMBASE;
13658                 }
13659         }
13660 #endif
13661
13662         return -1;
13663 }
13664
13665 int
13666 mono_op_to_op_imm_noemul (int opcode)
13667 {
13668         switch (opcode) {
13669 #if SIZEOF_REGISTER == 4 && !defined(MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS)
13670         case OP_LSHR:
13671         case OP_LSHL:
13672         case OP_LSHR_UN:
13673                 return -1;
13674 #endif
13675 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
13676         case OP_IDIV:
13677         case OP_IDIV_UN:
13678         case OP_IREM:
13679         case OP_IREM_UN:
13680                 return -1;
13681 #endif
13682 #if defined(MONO_ARCH_EMULATE_MUL_DIV)
13683         case OP_IMUL:
13684                 return -1;
13685 #endif
13686         default:
13687                 return mono_op_to_op_imm (opcode);
13688         }
13689 }
13690
13691 /**
13692  * mono_handle_global_vregs:
13693  *
13694  *   Make vregs used in more than one bblock 'global', i.e. allocate a variable
13695  * for them.
13696  */
13697 void
13698 mono_handle_global_vregs (MonoCompile *cfg)
13699 {
13700         gint32 *vreg_to_bb;
13701         MonoBasicBlock *bb;
13702         int i, pos;
13703
13704         vreg_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (gint32*) * cfg->next_vreg + 1);
13705
13706 #ifdef MONO_ARCH_SIMD_INTRINSICS
13707         if (cfg->uses_simd_intrinsics)
13708                 mono_simd_simplify_indirection (cfg);
13709 #endif
13710
13711         /* Find local vregs used in more than one bb */
13712         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13713                 MonoInst *ins = bb->code;       
13714                 int block_num = bb->block_num;
13715
13716                 if (cfg->verbose_level > 2)
13717                         printf ("\nHANDLE-GLOBAL-VREGS BLOCK %d:\n", bb->block_num);
13718
13719                 cfg->cbb = bb;
13720                 for (; ins; ins = ins->next) {
13721                         const char *spec = INS_INFO (ins->opcode);
13722                         int regtype = 0, regindex;
13723                         gint32 prev_bb;
13724
13725                         if (G_UNLIKELY (cfg->verbose_level > 2))
13726                                 mono_print_ins (ins);
13727
13728                         g_assert (ins->opcode >= MONO_CEE_LAST);
13729
13730                         for (regindex = 0; regindex < 4; regindex ++) {
13731                                 int vreg = 0;
13732
13733                                 if (regindex == 0) {
13734                                         regtype = spec [MONO_INST_DEST];
13735                                         if (regtype == ' ')
13736                                                 continue;
13737                                         vreg = ins->dreg;
13738                                 } else if (regindex == 1) {
13739                                         regtype = spec [MONO_INST_SRC1];
13740                                         if (regtype == ' ')
13741                                                 continue;
13742                                         vreg = ins->sreg1;
13743                                 } else if (regindex == 2) {
13744                                         regtype = spec [MONO_INST_SRC2];
13745                                         if (regtype == ' ')
13746                                                 continue;
13747                                         vreg = ins->sreg2;
13748                                 } else if (regindex == 3) {
13749                                         regtype = spec [MONO_INST_SRC3];
13750                                         if (regtype == ' ')
13751                                                 continue;
13752                                         vreg = ins->sreg3;
13753                                 }
13754
13755 #if SIZEOF_REGISTER == 4
13756                                 /* In the LLVM case, the long opcodes are not decomposed */
13757                                 if (regtype == 'l' && !COMPILE_LLVM (cfg)) {
13758                                         /*
13759                                          * Since some instructions reference the original long vreg,
13760                                          * and some reference the two component vregs, it is quite hard
13761                                          * to determine when it needs to be global. So be conservative.
13762                                          */
13763                                         if (!get_vreg_to_inst (cfg, vreg)) {
13764                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
13765
13766                                                 if (cfg->verbose_level > 2)
13767                                                         printf ("LONG VREG R%d made global.\n", vreg);
13768                                         }
13769
13770                                         /*
13771                                          * Make the component vregs volatile since the optimizations can
13772                                          * get confused otherwise.
13773                                          */
13774                                         get_vreg_to_inst (cfg, vreg + 1)->flags |= MONO_INST_VOLATILE;
13775                                         get_vreg_to_inst (cfg, vreg + 2)->flags |= MONO_INST_VOLATILE;
13776                                 }
13777 #endif
13778
13779                                 g_assert (vreg != -1);
13780
13781                                 prev_bb = vreg_to_bb [vreg];
13782                                 if (prev_bb == 0) {
13783                                         /* 0 is a valid block num */
13784                                         vreg_to_bb [vreg] = block_num + 1;
13785                                 } else if ((prev_bb != block_num + 1) && (prev_bb != -1)) {
13786                                         if (((regtype == 'i' && (vreg < MONO_MAX_IREGS))) || (regtype == 'f' && (vreg < MONO_MAX_FREGS)))
13787                                                 continue;
13788
13789                                         if (!get_vreg_to_inst (cfg, vreg)) {
13790                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
13791                                                         printf ("VREG R%d used in BB%d and BB%d made global.\n", vreg, vreg_to_bb [vreg], block_num);
13792
13793                                                 switch (regtype) {
13794                                                 case 'i':
13795                                                         if (vreg_is_ref (cfg, vreg))
13796                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL, vreg);
13797                                                         else
13798                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL, vreg);
13799                                                         break;
13800                                                 case 'l':
13801                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
13802                                                         break;
13803                                                 case 'f':
13804                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL, vreg);
13805                                                         break;
13806                                                 case 'v':
13807                                                         mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, vreg);
13808                                                         break;
13809                                                 default:
13810                                                         g_assert_not_reached ();
13811                                                 }
13812                                         }
13813
13814                                         /* Flag as having been used in more than one bb */
13815                                         vreg_to_bb [vreg] = -1;
13816                                 }
13817                         }
13818                 }
13819         }
13820
13821         /* If a variable is used in only one bblock, convert it into a local vreg */
13822         for (i = 0; i < cfg->num_varinfo; i++) {
13823                 MonoInst *var = cfg->varinfo [i];
13824                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
13825
13826                 switch (var->type) {
13827                 case STACK_I4:
13828                 case STACK_OBJ:
13829                 case STACK_PTR:
13830                 case STACK_MP:
13831                 case STACK_VTYPE:
13832 #if SIZEOF_REGISTER == 8
13833                 case STACK_I8:
13834 #endif
13835 #if !defined(TARGET_X86)
13836                 /* Enabling this screws up the fp stack on x86 */
13837                 case STACK_R8:
13838 #endif
13839                         if (mono_arch_is_soft_float ())
13840                                 break;
13841
13842                         /* Arguments are implicitly global */
13843                         /* Putting R4 vars into registers doesn't work currently */
13844                         /* The gsharedvt vars are implicitly referenced by ldaddr opcodes, but those opcodes are only generated later */
13845                         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) {
13846                                 /* 
13847                                  * Make that the variable's liveness interval doesn't contain a call, since
13848                                  * that would cause the lvreg to be spilled, making the whole optimization
13849                                  * useless.
13850                                  */
13851                                 /* This is too slow for JIT compilation */
13852 #if 0
13853                                 if (cfg->compile_aot && vreg_to_bb [var->dreg]) {
13854                                         MonoInst *ins;
13855                                         int def_index, call_index, ins_index;
13856                                         gboolean spilled = FALSE;
13857
13858                                         def_index = -1;
13859                                         call_index = -1;
13860                                         ins_index = 0;
13861                                         for (ins = vreg_to_bb [var->dreg]->code; ins; ins = ins->next) {
13862                                                 const char *spec = INS_INFO (ins->opcode);
13863
13864                                                 if ((spec [MONO_INST_DEST] != ' ') && (ins->dreg == var->dreg))
13865                                                         def_index = ins_index;
13866
13867                                                 if (((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg)) ||
13868                                                         ((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg))) {
13869                                                         if (call_index > def_index) {
13870                                                                 spilled = TRUE;
13871                                                                 break;
13872                                                         }
13873                                                 }
13874
13875                                                 if (MONO_IS_CALL (ins))
13876                                                         call_index = ins_index;
13877
13878                                                 ins_index ++;
13879                                         }
13880
13881                                         if (spilled)
13882                                                 break;
13883                                 }
13884 #endif
13885
13886                                 if (G_UNLIKELY (cfg->verbose_level > 2))
13887                                         printf ("CONVERTED R%d(%d) TO VREG.\n", var->dreg, vmv->idx);
13888                                 var->flags |= MONO_INST_IS_DEAD;
13889                                 cfg->vreg_to_inst [var->dreg] = NULL;
13890                         }
13891                         break;
13892                 }
13893         }
13894
13895         /* 
13896          * Compress the varinfo and vars tables so the liveness computation is faster and
13897          * takes up less space.
13898          */
13899         pos = 0;
13900         for (i = 0; i < cfg->num_varinfo; ++i) {
13901                 MonoInst *var = cfg->varinfo [i];
13902                 if (pos < i && cfg->locals_start == i)
13903                         cfg->locals_start = pos;
13904                 if (!(var->flags & MONO_INST_IS_DEAD)) {
13905                         if (pos < i) {
13906                                 cfg->varinfo [pos] = cfg->varinfo [i];
13907                                 cfg->varinfo [pos]->inst_c0 = pos;
13908                                 memcpy (&cfg->vars [pos], &cfg->vars [i], sizeof (MonoMethodVar));
13909                                 cfg->vars [pos].idx = pos;
13910 #if SIZEOF_REGISTER == 4
13911                                 if (cfg->varinfo [pos]->type == STACK_I8) {
13912                                         /* Modify the two component vars too */
13913                                         MonoInst *var1;
13914
13915                                         var1 = get_vreg_to_inst (cfg, cfg->varinfo [pos]->dreg + 1);
13916                                         var1->inst_c0 = pos;
13917                                         var1 = get_vreg_to_inst (cfg, cfg->varinfo [pos]->dreg + 2);
13918                                         var1->inst_c0 = pos;
13919                                 }
13920 #endif
13921                         }
13922                         pos ++;
13923                 }
13924         }
13925         cfg->num_varinfo = pos;
13926         if (cfg->locals_start > cfg->num_varinfo)
13927                 cfg->locals_start = cfg->num_varinfo;
13928 }
13929
13930 /**
13931  * mono_spill_global_vars:
13932  *
13933  *   Generate spill code for variables which are not allocated to registers, 
13934  * and replace vregs with their allocated hregs. *need_local_opts is set to TRUE if
13935  * code is generated which could be optimized by the local optimization passes.
13936  */
13937 void
13938 mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
13939 {
13940         MonoBasicBlock *bb;
13941         char spec2 [16];
13942         int orig_next_vreg;
13943         guint32 *vreg_to_lvreg;
13944         guint32 *lvregs;
13945         guint32 i, lvregs_len;
13946         gboolean dest_has_lvreg = FALSE;
13947         guint32 stacktypes [128];
13948         MonoInst **live_range_start, **live_range_end;
13949         MonoBasicBlock **live_range_start_bb, **live_range_end_bb;
13950         int *gsharedvt_vreg_to_idx = NULL;
13951
13952         *need_local_opts = FALSE;
13953
13954         memset (spec2, 0, sizeof (spec2));
13955
13956         /* FIXME: Move this function to mini.c */
13957         stacktypes ['i'] = STACK_PTR;
13958         stacktypes ['l'] = STACK_I8;
13959         stacktypes ['f'] = STACK_R8;
13960 #ifdef MONO_ARCH_SIMD_INTRINSICS
13961         stacktypes ['x'] = STACK_VTYPE;
13962 #endif
13963
13964 #if SIZEOF_REGISTER == 4
13965         /* Create MonoInsts for longs */
13966         for (i = 0; i < cfg->num_varinfo; i++) {
13967                 MonoInst *ins = cfg->varinfo [i];
13968
13969                 if ((ins->opcode != OP_REGVAR) && !(ins->flags & MONO_INST_IS_DEAD)) {
13970                         switch (ins->type) {
13971                         case STACK_R8:
13972                         case STACK_I8: {
13973                                 MonoInst *tree;
13974
13975                                 if (ins->type == STACK_R8 && !COMPILE_SOFT_FLOAT (cfg))
13976                                         break;
13977
13978                                 g_assert (ins->opcode == OP_REGOFFSET);
13979
13980                                 tree = get_vreg_to_inst (cfg, ins->dreg + 1);
13981                                 g_assert (tree);
13982                                 tree->opcode = OP_REGOFFSET;
13983                                 tree->inst_basereg = ins->inst_basereg;
13984                                 tree->inst_offset = ins->inst_offset + MINI_LS_WORD_OFFSET;
13985
13986                                 tree = get_vreg_to_inst (cfg, ins->dreg + 2);
13987                                 g_assert (tree);
13988                                 tree->opcode = OP_REGOFFSET;
13989                                 tree->inst_basereg = ins->inst_basereg;
13990                                 tree->inst_offset = ins->inst_offset + MINI_MS_WORD_OFFSET;
13991                                 break;
13992                         }
13993                         default:
13994                                 break;
13995                         }
13996                 }
13997         }
13998 #endif
13999
14000         if (cfg->compute_gc_maps) {
14001                 /* registers need liveness info even for !non refs */
14002                 for (i = 0; i < cfg->num_varinfo; i++) {
14003                         MonoInst *ins = cfg->varinfo [i];
14004
14005                         if (ins->opcode == OP_REGVAR)
14006                                 ins->flags |= MONO_INST_GC_TRACK;
14007                 }
14008         }
14009
14010         if (cfg->gsharedvt) {
14011                 gsharedvt_vreg_to_idx = mono_mempool_alloc0 (cfg->mempool, sizeof (int) * cfg->next_vreg);
14012
14013                 for (i = 0; i < cfg->num_varinfo; ++i) {
14014                         MonoInst *ins = cfg->varinfo [i];
14015                         int idx;
14016
14017                         if (mini_is_gsharedvt_variable_type (ins->inst_vtype)) {
14018                                 if (i >= cfg->locals_start) {
14019                                         /* Local */
14020                                         idx = get_gsharedvt_info_slot (cfg, ins->inst_vtype, MONO_RGCTX_INFO_LOCAL_OFFSET);
14021                                         gsharedvt_vreg_to_idx [ins->dreg] = idx + 1;
14022                                         ins->opcode = OP_GSHAREDVT_LOCAL;
14023                                         ins->inst_imm = idx;
14024                                 } else {
14025                                         /* Arg */
14026                                         gsharedvt_vreg_to_idx [ins->dreg] = -1;
14027                                         ins->opcode = OP_GSHAREDVT_ARG_REGOFFSET;
14028                                 }
14029                         }
14030                 }
14031         }
14032                 
14033         /* FIXME: widening and truncation */
14034
14035         /*
14036          * As an optimization, when a variable allocated to the stack is first loaded into 
14037          * an lvreg, we will remember the lvreg and use it the next time instead of loading
14038          * the variable again.
14039          */
14040         orig_next_vreg = cfg->next_vreg;
14041         vreg_to_lvreg = mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * cfg->next_vreg);
14042         lvregs = mono_mempool_alloc (cfg->mempool, sizeof (guint32) * 1024);
14043         lvregs_len = 0;
14044
14045         /* 
14046          * These arrays contain the first and last instructions accessing a given
14047          * variable.
14048          * Since we emit bblocks in the same order we process them here, and we
14049          * don't split live ranges, these will precisely describe the live range of
14050          * the variable, i.e. the instruction range where a valid value can be found
14051          * in the variables location.
14052          * The live range is computed using the liveness info computed by the liveness pass.
14053          * We can't use vmv->range, since that is an abstract live range, and we need
14054          * one which is instruction precise.
14055          * FIXME: Variables used in out-of-line bblocks have a hole in their live range.
14056          */
14057         /* FIXME: Only do this if debugging info is requested */
14058         live_range_start = g_new0 (MonoInst*, cfg->next_vreg);
14059         live_range_end = g_new0 (MonoInst*, cfg->next_vreg);
14060         live_range_start_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
14061         live_range_end_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
14062         
14063         /* Add spill loads/stores */
14064         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
14065                 MonoInst *ins;
14066
14067                 if (cfg->verbose_level > 2)
14068                         printf ("\nSPILL BLOCK %d:\n", bb->block_num);
14069
14070                 /* Clear vreg_to_lvreg array */
14071                 for (i = 0; i < lvregs_len; i++)
14072                         vreg_to_lvreg [lvregs [i]] = 0;
14073                 lvregs_len = 0;
14074
14075                 cfg->cbb = bb;
14076                 MONO_BB_FOR_EACH_INS (bb, ins) {
14077                         const char *spec = INS_INFO (ins->opcode);
14078                         int regtype, srcindex, sreg, tmp_reg, prev_dreg, num_sregs;
14079                         gboolean store, no_lvreg;
14080                         int sregs [MONO_MAX_SRC_REGS];
14081
14082                         if (G_UNLIKELY (cfg->verbose_level > 2))
14083                                 mono_print_ins (ins);
14084
14085                         if (ins->opcode == OP_NOP)
14086                                 continue;
14087
14088                         /* 
14089                          * We handle LDADDR here as well, since it can only be decomposed
14090                          * when variable addresses are known.
14091                          */
14092                         if (ins->opcode == OP_LDADDR) {
14093                                 MonoInst *var = ins->inst_p0;
14094
14095                                 if (var->opcode == OP_VTARG_ADDR) {
14096                                         /* Happens on SPARC/S390 where vtypes are passed by reference */
14097                                         MonoInst *vtaddr = var->inst_left;
14098                                         if (vtaddr->opcode == OP_REGVAR) {
14099                                                 ins->opcode = OP_MOVE;
14100                                                 ins->sreg1 = vtaddr->dreg;
14101                                         }
14102                                         else if (var->inst_left->opcode == OP_REGOFFSET) {
14103                                                 ins->opcode = OP_LOAD_MEMBASE;
14104                                                 ins->inst_basereg = vtaddr->inst_basereg;
14105                                                 ins->inst_offset = vtaddr->inst_offset;
14106                                         } else
14107                                                 NOT_IMPLEMENTED;
14108                                 } else if (cfg->gsharedvt && gsharedvt_vreg_to_idx [var->dreg] < 0) {
14109                                         /* gsharedvt arg passed by ref */
14110                                         g_assert (var->opcode == OP_GSHAREDVT_ARG_REGOFFSET);
14111
14112                                         ins->opcode = OP_LOAD_MEMBASE;
14113                                         ins->inst_basereg = var->inst_basereg;
14114                                         ins->inst_offset = var->inst_offset;
14115                                 } else if (cfg->gsharedvt && gsharedvt_vreg_to_idx [var->dreg]) {
14116                                         MonoInst *load, *load2, *load3;
14117                                         int idx = gsharedvt_vreg_to_idx [var->dreg] - 1;
14118                                         int reg1, reg2, reg3;
14119                                         MonoInst *info_var = cfg->gsharedvt_info_var;
14120                                         MonoInst *locals_var = cfg->gsharedvt_locals_var;
14121
14122                                         /*
14123                                          * gsharedvt local.
14124                                          * Compute the address of the local as gsharedvt_locals_var + gsharedvt_info_var->locals_offsets [idx].
14125                                          */
14126
14127                                         g_assert (var->opcode == OP_GSHAREDVT_LOCAL);
14128
14129                                         g_assert (info_var);
14130                                         g_assert (locals_var);
14131
14132                                         /* Mark the instruction used to compute the locals var as used */
14133                                         cfg->gsharedvt_locals_var_ins = NULL;
14134
14135                                         /* Load the offset */
14136                                         if (info_var->opcode == OP_REGOFFSET) {
14137                                                 reg1 = alloc_ireg (cfg);
14138                                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, reg1, info_var->inst_basereg, info_var->inst_offset);
14139                                         } else if (info_var->opcode == OP_REGVAR) {
14140                                                 load = NULL;
14141                                                 reg1 = info_var->dreg;
14142                                         } else {
14143                                                 g_assert_not_reached ();
14144                                         }
14145                                         reg2 = alloc_ireg (cfg);
14146                                         NEW_LOAD_MEMBASE (cfg, load2, OP_LOADI4_MEMBASE, reg2, reg1, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
14147                                         /* Load the locals area address */
14148                                         reg3 = alloc_ireg (cfg);
14149                                         if (locals_var->opcode == OP_REGOFFSET) {
14150                                                 NEW_LOAD_MEMBASE (cfg, load3, OP_LOAD_MEMBASE, reg3, locals_var->inst_basereg, locals_var->inst_offset);
14151                                         } else if (locals_var->opcode == OP_REGVAR) {
14152                                                 NEW_UNALU (cfg, load3, OP_MOVE, reg3, locals_var->dreg);
14153                                         } else {
14154                                                 g_assert_not_reached ();
14155                                         }
14156                                         /* Compute the address */
14157                                         ins->opcode = OP_PADD;
14158                                         ins->sreg1 = reg3;
14159                                         ins->sreg2 = reg2;
14160
14161                                         mono_bblock_insert_before_ins (bb, ins, load3);
14162                                         mono_bblock_insert_before_ins (bb, load3, load2);
14163                                         if (load)
14164                                                 mono_bblock_insert_before_ins (bb, load2, load);
14165                                 } else {
14166                                         g_assert (var->opcode == OP_REGOFFSET);
14167
14168                                         ins->opcode = OP_ADD_IMM;
14169                                         ins->sreg1 = var->inst_basereg;
14170                                         ins->inst_imm = var->inst_offset;
14171                                 }
14172
14173                                 *need_local_opts = TRUE;
14174                                 spec = INS_INFO (ins->opcode);
14175                         }
14176
14177                         if (ins->opcode < MONO_CEE_LAST) {
14178                                 mono_print_ins (ins);
14179                                 g_assert_not_reached ();
14180                         }
14181
14182                         /*
14183                          * Store opcodes have destbasereg in the dreg, but in reality, it is an
14184                          * src register.
14185                          * FIXME:
14186                          */
14187                         if (MONO_IS_STORE_MEMBASE (ins)) {
14188                                 tmp_reg = ins->dreg;
14189                                 ins->dreg = ins->sreg2;
14190                                 ins->sreg2 = tmp_reg;
14191                                 store = TRUE;
14192
14193                                 spec2 [MONO_INST_DEST] = ' ';
14194                                 spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14195                                 spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14196                                 spec2 [MONO_INST_SRC3] = ' ';
14197                                 spec = spec2;
14198                         } else if (MONO_IS_STORE_MEMINDEX (ins))
14199                                 g_assert_not_reached ();
14200                         else
14201                                 store = FALSE;
14202                         no_lvreg = FALSE;
14203
14204                         if (G_UNLIKELY (cfg->verbose_level > 2)) {
14205                                 printf ("\t %.3s %d", spec, ins->dreg);
14206                                 num_sregs = mono_inst_get_src_registers (ins, sregs);
14207                                 for (srcindex = 0; srcindex < num_sregs; ++srcindex)
14208                                         printf (" %d", sregs [srcindex]);
14209                                 printf ("\n");
14210                         }
14211
14212                         /***************/
14213                         /*    DREG     */
14214                         /***************/
14215                         regtype = spec [MONO_INST_DEST];
14216                         g_assert (((ins->dreg == -1) && (regtype == ' ')) || ((ins->dreg != -1) && (regtype != ' ')));
14217                         prev_dreg = -1;
14218
14219                         if ((ins->dreg != -1) && get_vreg_to_inst (cfg, ins->dreg)) {
14220                                 MonoInst *var = get_vreg_to_inst (cfg, ins->dreg);
14221                                 MonoInst *store_ins;
14222                                 int store_opcode;
14223                                 MonoInst *def_ins = ins;
14224                                 int dreg = ins->dreg; /* The original vreg */
14225
14226                                 store_opcode = mono_type_to_store_membase (cfg, var->inst_vtype);
14227
14228                                 if (var->opcode == OP_REGVAR) {
14229                                         ins->dreg = var->dreg;
14230                                 } 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)) {
14231                                         /* 
14232                                          * Instead of emitting a load+store, use a _membase opcode.
14233                                          */
14234                                         g_assert (var->opcode == OP_REGOFFSET);
14235                                         if (ins->opcode == OP_MOVE) {
14236                                                 NULLIFY_INS (ins);
14237                                                 def_ins = NULL;
14238                                         } else {
14239                                                 ins->opcode = op_to_op_dest_membase (store_opcode, ins->opcode);
14240                                                 ins->inst_basereg = var->inst_basereg;
14241                                                 ins->inst_offset = var->inst_offset;
14242                                                 ins->dreg = -1;
14243                                         }
14244                                         spec = INS_INFO (ins->opcode);
14245                                 } else {
14246                                         guint32 lvreg;
14247
14248                                         g_assert (var->opcode == OP_REGOFFSET);
14249
14250                                         prev_dreg = ins->dreg;
14251
14252                                         /* Invalidate any previous lvreg for this vreg */
14253                                         vreg_to_lvreg [ins->dreg] = 0;
14254
14255                                         lvreg = 0;
14256
14257                                         if (COMPILE_SOFT_FLOAT (cfg) && store_opcode == OP_STORER8_MEMBASE_REG) {
14258                                                 regtype = 'l';
14259                                                 store_opcode = OP_STOREI8_MEMBASE_REG;
14260                                         }
14261
14262                                         ins->dreg = alloc_dreg (cfg, stacktypes [regtype]);
14263
14264 #if SIZEOF_REGISTER != 8
14265                                         if (regtype == 'l') {
14266                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET, ins->dreg + 1);
14267                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14268                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET, ins->dreg + 2);
14269                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14270                                                 def_ins = store_ins;
14271                                         }
14272                                         else
14273 #endif
14274                                         {
14275                                                 g_assert (store_opcode != OP_STOREV_MEMBASE);
14276
14277                                                 /* Try to fuse the store into the instruction itself */
14278                                                 /* FIXME: Add more instructions */
14279                                                 if (!lvreg && ((ins->opcode == OP_ICONST) || ((ins->opcode == OP_I8CONST) && (ins->inst_c0 == 0)))) {
14280                                                         ins->opcode = store_membase_reg_to_store_membase_imm (store_opcode);
14281                                                         ins->inst_imm = ins->inst_c0;
14282                                                         ins->inst_destbasereg = var->inst_basereg;
14283                                                         ins->inst_offset = var->inst_offset;
14284                                                         spec = INS_INFO (ins->opcode);
14285                                                 } else if (!lvreg && ((ins->opcode == OP_MOVE) || (ins->opcode == OP_FMOVE) || (ins->opcode == OP_LMOVE) || (ins->opcode == OP_RMOVE))) {
14286                                                         ins->opcode = store_opcode;
14287                                                         ins->inst_destbasereg = var->inst_basereg;
14288                                                         ins->inst_offset = var->inst_offset;
14289
14290                                                         no_lvreg = TRUE;
14291
14292                                                         tmp_reg = ins->dreg;
14293                                                         ins->dreg = ins->sreg2;
14294                                                         ins->sreg2 = tmp_reg;
14295                                                         store = TRUE;
14296
14297                                                         spec2 [MONO_INST_DEST] = ' ';
14298                                                         spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14299                                                         spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14300                                                         spec2 [MONO_INST_SRC3] = ' ';
14301                                                         spec = spec2;
14302                                                 } else if (!lvreg && (op_to_op_store_membase (store_opcode, ins->opcode) != -1)) {
14303                                                         // FIXME: The backends expect the base reg to be in inst_basereg
14304                                                         ins->opcode = op_to_op_store_membase (store_opcode, ins->opcode);
14305                                                         ins->dreg = -1;
14306                                                         ins->inst_basereg = var->inst_basereg;
14307                                                         ins->inst_offset = var->inst_offset;
14308                                                         spec = INS_INFO (ins->opcode);
14309                                                 } else {
14310                                                         /* printf ("INS: "); mono_print_ins (ins); */
14311                                                         /* Create a store instruction */
14312                                                         NEW_STORE_MEMBASE (cfg, store_ins, store_opcode, var->inst_basereg, var->inst_offset, ins->dreg);
14313
14314                                                         /* Insert it after the instruction */
14315                                                         mono_bblock_insert_after_ins (bb, ins, store_ins);
14316
14317                                                         def_ins = store_ins;
14318
14319                                                         /* 
14320                                                          * We can't assign ins->dreg to var->dreg here, since the
14321                                                          * sregs could use it. So set a flag, and do it after
14322                                                          * the sregs.
14323                                                          */
14324                                                         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)))
14325                                                                 dest_has_lvreg = TRUE;
14326                                                 }
14327                                         }
14328                                 }
14329
14330                                 if (def_ins && !live_range_start [dreg]) {
14331                                         live_range_start [dreg] = def_ins;
14332                                         live_range_start_bb [dreg] = bb;
14333                                 }
14334
14335                                 if (cfg->compute_gc_maps && def_ins && (var->flags & MONO_INST_GC_TRACK)) {
14336                                         MonoInst *tmp;
14337
14338                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
14339                                         tmp->inst_c1 = dreg;
14340                                         mono_bblock_insert_after_ins (bb, def_ins, tmp);
14341                                 }
14342                         }
14343
14344                         /************/
14345                         /*  SREGS   */
14346                         /************/
14347                         num_sregs = mono_inst_get_src_registers (ins, sregs);
14348                         for (srcindex = 0; srcindex < 3; ++srcindex) {
14349                                 regtype = spec [MONO_INST_SRC1 + srcindex];
14350                                 sreg = sregs [srcindex];
14351
14352                                 g_assert (((sreg == -1) && (regtype == ' ')) || ((sreg != -1) && (regtype != ' ')));
14353                                 if ((sreg != -1) && get_vreg_to_inst (cfg, sreg)) {
14354                                         MonoInst *var = get_vreg_to_inst (cfg, sreg);
14355                                         MonoInst *use_ins = ins;
14356                                         MonoInst *load_ins;
14357                                         guint32 load_opcode;
14358
14359                                         if (var->opcode == OP_REGVAR) {
14360                                                 sregs [srcindex] = var->dreg;
14361                                                 //mono_inst_set_src_registers (ins, sregs);
14362                                                 live_range_end [sreg] = use_ins;
14363                                                 live_range_end_bb [sreg] = bb;
14364
14365                                                 if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14366                                                         MonoInst *tmp;
14367
14368                                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14369                                                         /* var->dreg is a hreg */
14370                                                         tmp->inst_c1 = sreg;
14371                                                         mono_bblock_insert_after_ins (bb, ins, tmp);
14372                                                 }
14373
14374                                                 continue;
14375                                         }
14376
14377                                         g_assert (var->opcode == OP_REGOFFSET);
14378                                                 
14379                                         load_opcode = mono_type_to_load_membase (cfg, var->inst_vtype);
14380
14381                                         g_assert (load_opcode != OP_LOADV_MEMBASE);
14382
14383                                         if (vreg_to_lvreg [sreg]) {
14384                                                 g_assert (vreg_to_lvreg [sreg] != -1);
14385
14386                                                 /* The variable is already loaded to an lvreg */
14387                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
14388                                                         printf ("\t\tUse lvreg R%d for R%d.\n", vreg_to_lvreg [sreg], sreg);
14389                                                 sregs [srcindex] = vreg_to_lvreg [sreg];
14390                                                 //mono_inst_set_src_registers (ins, sregs);
14391                                                 continue;
14392                                         }
14393
14394                                         /* Try to fuse the load into the instruction */
14395                                         if ((srcindex == 0) && (op_to_op_src1_membase (cfg, load_opcode, ins->opcode) != -1)) {
14396                                                 ins->opcode = op_to_op_src1_membase (cfg, load_opcode, ins->opcode);
14397                                                 sregs [0] = var->inst_basereg;
14398                                                 //mono_inst_set_src_registers (ins, sregs);
14399                                                 ins->inst_offset = var->inst_offset;
14400                                         } else if ((srcindex == 1) && (op_to_op_src2_membase (cfg, load_opcode, ins->opcode) != -1)) {
14401                                                 ins->opcode = op_to_op_src2_membase (cfg, load_opcode, ins->opcode);
14402                                                 sregs [1] = var->inst_basereg;
14403                                                 //mono_inst_set_src_registers (ins, sregs);
14404                                                 ins->inst_offset = var->inst_offset;
14405                                         } else {
14406                                                 if (MONO_IS_REAL_MOVE (ins)) {
14407                                                         ins->opcode = OP_NOP;
14408                                                         sreg = ins->dreg;
14409                                                 } else {
14410                                                         //printf ("%d ", srcindex); mono_print_ins (ins);
14411
14412                                                         sreg = alloc_dreg (cfg, stacktypes [regtype]);
14413
14414                                                         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) {
14415                                                                 if (var->dreg == prev_dreg) {
14416                                                                         /*
14417                                                                          * sreg refers to the value loaded by the load
14418                                                                          * emitted below, but we need to use ins->dreg
14419                                                                          * since it refers to the store emitted earlier.
14420                                                                          */
14421                                                                         sreg = ins->dreg;
14422                                                                 }
14423                                                                 g_assert (sreg != -1);
14424                                                                 vreg_to_lvreg [var->dreg] = sreg;
14425                                                                 g_assert (lvregs_len < 1024);
14426                                                                 lvregs [lvregs_len ++] = var->dreg;
14427                                                         }
14428                                                 }
14429
14430                                                 sregs [srcindex] = sreg;
14431                                                 //mono_inst_set_src_registers (ins, sregs);
14432
14433 #if SIZEOF_REGISTER != 8
14434                                                 if (regtype == 'l') {
14435                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 2, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET);
14436                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14437                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 1, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET);
14438                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14439                                                         use_ins = load_ins;
14440                                                 }
14441                                                 else
14442 #endif
14443                                                 {
14444 #if SIZEOF_REGISTER == 4
14445                                                         g_assert (load_opcode != OP_LOADI8_MEMBASE);
14446 #endif
14447                                                         NEW_LOAD_MEMBASE (cfg, load_ins, load_opcode, sreg, var->inst_basereg, var->inst_offset);
14448                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14449                                                         use_ins = load_ins;
14450                                                 }
14451                                         }
14452
14453                                         if (var->dreg < orig_next_vreg) {
14454                                                 live_range_end [var->dreg] = use_ins;
14455                                                 live_range_end_bb [var->dreg] = bb;
14456                                         }
14457
14458                                         if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14459                                                 MonoInst *tmp;
14460
14461                                                 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14462                                                 tmp->inst_c1 = var->dreg;
14463                                                 mono_bblock_insert_after_ins (bb, ins, tmp);
14464                                         }
14465                                 }
14466                         }
14467                         mono_inst_set_src_registers (ins, sregs);
14468
14469                         if (dest_has_lvreg) {
14470                                 g_assert (ins->dreg != -1);
14471                                 vreg_to_lvreg [prev_dreg] = ins->dreg;
14472                                 g_assert (lvregs_len < 1024);
14473                                 lvregs [lvregs_len ++] = prev_dreg;
14474                                 dest_has_lvreg = FALSE;
14475                         }
14476
14477                         if (store) {
14478                                 tmp_reg = ins->dreg;
14479                                 ins->dreg = ins->sreg2;
14480                                 ins->sreg2 = tmp_reg;
14481                         }
14482
14483                         if (MONO_IS_CALL (ins)) {
14484                                 /* Clear vreg_to_lvreg array */
14485                                 for (i = 0; i < lvregs_len; i++)
14486                                         vreg_to_lvreg [lvregs [i]] = 0;
14487                                 lvregs_len = 0;
14488                         } else if (ins->opcode == OP_NOP) {
14489                                 ins->dreg = -1;
14490                                 MONO_INST_NULLIFY_SREGS (ins);
14491                         }
14492
14493                         if (cfg->verbose_level > 2)
14494                                 mono_print_ins_index (1, ins);
14495                 }
14496
14497                 /* Extend the live range based on the liveness info */
14498                 if (cfg->compute_precise_live_ranges && bb->live_out_set && bb->code) {
14499                         for (i = 0; i < cfg->num_varinfo; i ++) {
14500                                 MonoMethodVar *vi = MONO_VARINFO (cfg, i);
14501
14502                                 if (vreg_is_volatile (cfg, vi->vreg))
14503                                         /* The liveness info is incomplete */
14504                                         continue;
14505
14506                                 if (mono_bitset_test_fast (bb->live_in_set, i) && !live_range_start [vi->vreg]) {
14507                                         /* Live from at least the first ins of this bb */
14508                                         live_range_start [vi->vreg] = bb->code;
14509                                         live_range_start_bb [vi->vreg] = bb;
14510                                 }
14511
14512                                 if (mono_bitset_test_fast (bb->live_out_set, i)) {
14513                                         /* Live at least until the last ins of this bb */
14514                                         live_range_end [vi->vreg] = bb->last_ins;
14515                                         live_range_end_bb [vi->vreg] = bb;
14516                                 }
14517                         }
14518                 }
14519         }
14520         
14521         /*
14522          * Emit LIVERANGE_START/LIVERANGE_END opcodes, the backend will implement them
14523          * by storing the current native offset into MonoMethodVar->live_range_start/end.
14524          */
14525         if (cfg->backend->have_liverange_ops && cfg->compute_precise_live_ranges && cfg->comp_done & MONO_COMP_LIVENESS) {
14526                 for (i = 0; i < cfg->num_varinfo; ++i) {
14527                         int vreg = MONO_VARINFO (cfg, i)->vreg;
14528                         MonoInst *ins;
14529
14530                         if (live_range_start [vreg]) {
14531                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_START);
14532                                 ins->inst_c0 = i;
14533                                 ins->inst_c1 = vreg;
14534                                 mono_bblock_insert_after_ins (live_range_start_bb [vreg], live_range_start [vreg], ins);
14535                         }
14536                         if (live_range_end [vreg]) {
14537                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_END);
14538                                 ins->inst_c0 = i;
14539                                 ins->inst_c1 = vreg;
14540                                 if (live_range_end [vreg] == live_range_end_bb [vreg]->last_ins)
14541                                         mono_add_ins_to_end (live_range_end_bb [vreg], ins);
14542                                 else
14543                                         mono_bblock_insert_after_ins (live_range_end_bb [vreg], live_range_end [vreg], ins);
14544                         }
14545                 }
14546         }
14547
14548         if (cfg->gsharedvt_locals_var_ins) {
14549                 /* Nullify if unused */
14550                 cfg->gsharedvt_locals_var_ins->opcode = OP_PCONST;
14551                 cfg->gsharedvt_locals_var_ins->inst_imm = 0;
14552         }
14553
14554         g_free (live_range_start);
14555         g_free (live_range_end);
14556         g_free (live_range_start_bb);
14557         g_free (live_range_end_bb);
14558 }
14559
14560 /**
14561  * FIXME:
14562  * - use 'iadd' instead of 'int_add'
14563  * - handling ovf opcodes: decompose in method_to_ir.
14564  * - unify iregs/fregs
14565  *   -> partly done, the missing parts are:
14566  *   - a more complete unification would involve unifying the hregs as well, so
14567  *     code wouldn't need if (fp) all over the place. but that would mean the hregs
14568  *     would no longer map to the machine hregs, so the code generators would need to
14569  *     be modified. Also, on ia64 for example, niregs + nfregs > 256 -> bitmasks
14570  *     wouldn't work any more. Duplicating the code in mono_local_regalloc () into
14571  *     fp/non-fp branches speeds it up by about 15%.
14572  * - use sext/zext opcodes instead of shifts
14573  * - add OP_ICALL
14574  * - get rid of TEMPLOADs if possible and use vregs instead
14575  * - clean up usage of OP_P/OP_ opcodes
14576  * - cleanup usage of DUMMY_USE
14577  * - cleanup the setting of ins->type for MonoInst's which are pushed on the 
14578  *   stack
14579  * - set the stack type and allocate a dreg in the EMIT_NEW macros
14580  * - get rid of all the <foo>2 stuff when the new JIT is ready.
14581  * - make sure handle_stack_args () is called before the branch is emitted
14582  * - when the new IR is done, get rid of all unused stuff
14583  * - COMPARE/BEQ as separate instructions or unify them ?
14584  *   - keeping them separate allows specialized compare instructions like
14585  *     compare_imm, compare_membase
14586  *   - most back ends unify fp compare+branch, fp compare+ceq
14587  * - integrate mono_save_args into inline_method
14588  * - get rid of the empty bblocks created by MONO_EMIT_NEW_BRACH_BLOCK2
14589  * - handle long shift opts on 32 bit platforms somehow: they require 
14590  *   3 sregs (2 for arg1 and 1 for arg2)
14591  * - make byref a 'normal' type.
14592  * - use vregs for bb->out_stacks if possible, handle_global_vreg will make them a
14593  *   variable if needed.
14594  * - do not start a new IL level bblock when cfg->cbb is changed by a function call
14595  *   like inline_method.
14596  * - remove inlining restrictions
14597  * - fix LNEG and enable cfold of INEG
14598  * - generalize x86 optimizations like ldelema as a peephole optimization
14599  * - add store_mem_imm for amd64
14600  * - optimize the loading of the interruption flag in the managed->native wrappers
14601  * - avoid special handling of OP_NOP in passes
14602  * - move code inserting instructions into one function/macro.
14603  * - try a coalescing phase after liveness analysis
14604  * - add float -> vreg conversion + local optimizations on !x86
14605  * - figure out how to handle decomposed branches during optimizations, ie.
14606  *   compare+branch, op_jump_table+op_br etc.
14607  * - promote RuntimeXHandles to vregs
14608  * - vtype cleanups:
14609  *   - add a NEW_VARLOADA_VREG macro
14610  * - the vtype optimizations are blocked by the LDADDR opcodes generated for 
14611  *   accessing vtype fields.
14612  * - get rid of I8CONST on 64 bit platforms
14613  * - dealing with the increase in code size due to branches created during opcode
14614  *   decomposition:
14615  *   - use extended basic blocks
14616  *     - all parts of the JIT
14617  *     - handle_global_vregs () && local regalloc
14618  *   - avoid introducing global vregs during decomposition, like 'vtable' in isinst
14619  * - sources of increase in code size:
14620  *   - vtypes
14621  *   - long compares
14622  *   - isinst and castclass
14623  *   - lvregs not allocated to global registers even if used multiple times
14624  * - call cctors outside the JIT, to make -v output more readable and JIT timings more
14625  *   meaningful.
14626  * - check for fp stack leakage in other opcodes too. (-> 'exceptions' optimization)
14627  * - add all micro optimizations from the old JIT
14628  * - put tree optimizations into the deadce pass
14629  * - decompose op_start_handler/op_endfilter/op_endfinally earlier using an arch
14630  *   specific function.
14631  * - unify the float comparison opcodes with the other comparison opcodes, i.e.
14632  *   fcompare + branchCC.
14633  * - create a helper function for allocating a stack slot, taking into account 
14634  *   MONO_CFG_HAS_SPILLUP.
14635  * - merge r68207.
14636  * - merge the ia64 switch changes.
14637  * - optimize mono_regstate2_alloc_int/float.
14638  * - fix the pessimistic handling of variables accessed in exception handler blocks.
14639  * - need to write a tree optimization pass, but the creation of trees is difficult, i.e.
14640  *   parts of the tree could be separated by other instructions, killing the tree
14641  *   arguments, or stores killing loads etc. Also, should we fold loads into other
14642  *   instructions if the result of the load is used multiple times ?
14643  * - make the REM_IMM optimization in mini-x86.c arch-independent.
14644  * - LAST MERGE: 108395.
14645  * - when returning vtypes in registers, generate IR and append it to the end of the
14646  *   last bb instead of doing it in the epilog.
14647  * - change the store opcodes so they use sreg1 instead of dreg to store the base register.
14648  */
14649
14650 /*
14651
14652 NOTES
14653 -----
14654
14655 - When to decompose opcodes:
14656   - earlier: this makes some optimizations hard to implement, since the low level IR
14657   no longer contains the neccessary information. But it is easier to do.
14658   - later: harder to implement, enables more optimizations.
14659 - Branches inside bblocks:
14660   - created when decomposing complex opcodes. 
14661     - branches to another bblock: harmless, but not tracked by the branch 
14662       optimizations, so need to branch to a label at the start of the bblock.
14663     - branches to inside the same bblock: very problematic, trips up the local
14664       reg allocator. Can be fixed by spitting the current bblock, but that is a
14665       complex operation, since some local vregs can become global vregs etc.
14666 - Local/global vregs:
14667   - local vregs: temporary vregs used inside one bblock. Assigned to hregs by the
14668     local register allocator.
14669   - global vregs: used in more than one bblock. Have an associated MonoMethodVar
14670     structure, created by mono_create_var (). Assigned to hregs or the stack by
14671     the global register allocator.
14672 - When to do optimizations like alu->alu_imm:
14673   - earlier -> saves work later on since the IR will be smaller/simpler
14674   - later -> can work on more instructions
14675 - Handling of valuetypes:
14676   - When a vtype is pushed on the stack, a new temporary is created, an 
14677     instruction computing its address (LDADDR) is emitted and pushed on
14678     the stack. Need to optimize cases when the vtype is used immediately as in
14679     argument passing, stloc etc.
14680 - Instead of the to_end stuff in the old JIT, simply call the function handling
14681   the values on the stack before emitting the last instruction of the bb.
14682 */
14683
14684 #endif /* DISABLE_JIT */