26536d45eff761c95cdb856c2b39fea390e401b1
[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         if (mini_is_gsharedvt_variable_type (fsig->ret))
5758                 return NULL;
5759
5760         //Valuetypes that are semantically equivalent or numbers than can be widened to
5761         if (is_unsafe_mov_compatible (cfg, param_klass, return_klass))
5762                 return args [0];
5763
5764         //Arrays of valuetypes that are semantically equivalent
5765         if (param_klass->rank == 1 && return_klass->rank == 1 && is_unsafe_mov_compatible (cfg, param_klass->element_class, return_klass->element_class))
5766                 return args [0];
5767
5768         return NULL;
5769 }
5770
5771 static MonoInst*
5772 mini_emit_inst_for_ctor (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5773 {
5774 #ifdef MONO_ARCH_SIMD_INTRINSICS
5775         MonoInst *ins = NULL;
5776
5777         if (cfg->opt & MONO_OPT_SIMD) {
5778                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
5779                 if (ins)
5780                         return ins;
5781         }
5782 #endif
5783
5784         return mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
5785 }
5786
5787 static MonoInst*
5788 emit_memory_barrier (MonoCompile *cfg, int kind)
5789 {
5790         MonoInst *ins = NULL;
5791         MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
5792         MONO_ADD_INS (cfg->cbb, ins);
5793         ins->backend.memory_barrier_kind = kind;
5794
5795         return ins;
5796 }
5797
5798 static MonoInst*
5799 llvm_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5800 {
5801         MonoInst *ins = NULL;
5802         int opcode = 0;
5803
5804         /* The LLVM backend supports these intrinsics */
5805         if (cmethod->klass == mono_defaults.math_class) {
5806                 if (strcmp (cmethod->name, "Sin") == 0) {
5807                         opcode = OP_SIN;
5808                 } else if (strcmp (cmethod->name, "Cos") == 0) {
5809                         opcode = OP_COS;
5810                 } else if (strcmp (cmethod->name, "Sqrt") == 0) {
5811                         opcode = OP_SQRT;
5812                 } else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8) {
5813                         opcode = OP_ABS;
5814                 }
5815
5816                 if (opcode && fsig->param_count == 1) {
5817                         MONO_INST_NEW (cfg, ins, opcode);
5818                         ins->type = STACK_R8;
5819                         ins->dreg = mono_alloc_freg (cfg);
5820                         ins->sreg1 = args [0]->dreg;
5821                         MONO_ADD_INS (cfg->cbb, ins);
5822                 }
5823
5824                 opcode = 0;
5825                 if (cfg->opt & MONO_OPT_CMOV) {
5826                         if (strcmp (cmethod->name, "Min") == 0) {
5827                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5828                                         opcode = OP_IMIN;
5829                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5830                                         opcode = OP_IMIN_UN;
5831                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5832                                         opcode = OP_LMIN;
5833                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5834                                         opcode = OP_LMIN_UN;
5835                         } else if (strcmp (cmethod->name, "Max") == 0) {
5836                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5837                                         opcode = OP_IMAX;
5838                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5839                                         opcode = OP_IMAX_UN;
5840                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5841                                         opcode = OP_LMAX;
5842                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5843                                         opcode = OP_LMAX_UN;
5844                         }
5845                 }
5846
5847                 if (opcode && fsig->param_count == 2) {
5848                         MONO_INST_NEW (cfg, ins, opcode);
5849                         ins->type = fsig->params [0]->type == MONO_TYPE_I4 ? STACK_I4 : STACK_I8;
5850                         ins->dreg = mono_alloc_ireg (cfg);
5851                         ins->sreg1 = args [0]->dreg;
5852                         ins->sreg2 = args [1]->dreg;
5853                         MONO_ADD_INS (cfg->cbb, ins);
5854                 }
5855         }
5856
5857         return ins;
5858 }
5859
5860 static MonoInst*
5861 mini_emit_inst_for_sharable_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5862 {
5863         if (cmethod->klass == mono_defaults.array_class) {
5864                 if (strcmp (cmethod->name, "UnsafeStore") == 0)
5865                         return emit_array_unsafe_access (cfg, fsig, args, TRUE);
5866                 else if (strcmp (cmethod->name, "UnsafeLoad") == 0)
5867                         return emit_array_unsafe_access (cfg, fsig, args, FALSE);
5868                 else if (strcmp (cmethod->name, "UnsafeMov") == 0)
5869                         return emit_array_unsafe_mov (cfg, fsig, args);
5870         }
5871
5872         return NULL;
5873 }
5874
5875 static MonoInst*
5876 mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5877 {
5878         MonoInst *ins = NULL;
5879
5880         static MonoClass *runtime_helpers_class = NULL;
5881         if (! runtime_helpers_class)
5882                 runtime_helpers_class = mono_class_from_name (mono_defaults.corlib,
5883                         "System.Runtime.CompilerServices", "RuntimeHelpers");
5884
5885         if (cmethod->klass == mono_defaults.string_class) {
5886                 if (strcmp (cmethod->name, "get_Chars") == 0 && fsig->param_count + fsig->hasthis == 2) {
5887                         int dreg = alloc_ireg (cfg);
5888                         int index_reg = alloc_preg (cfg);
5889                         int add_reg = alloc_preg (cfg);
5890
5891 #if SIZEOF_REGISTER == 8
5892                         /* The array reg is 64 bits but the index reg is only 32 */
5893                         MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index_reg, args [1]->dreg);
5894 #else
5895                         index_reg = args [1]->dreg;
5896 #endif  
5897                         MONO_EMIT_BOUNDS_CHECK (cfg, args [0]->dreg, MonoString, length, index_reg);
5898
5899 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5900                         EMIT_NEW_X86_LEA (cfg, ins, args [0]->dreg, index_reg, 1, MONO_STRUCT_OFFSET (MonoString, chars));
5901                         add_reg = ins->dreg;
5902                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5903                                                                    add_reg, 0);
5904 #else
5905                         int mult_reg = alloc_preg (cfg);
5906                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, index_reg, 1);
5907                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
5908                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5909                                                                    add_reg, MONO_STRUCT_OFFSET (MonoString, chars));
5910 #endif
5911                         type_from_op (cfg, ins, NULL, NULL);
5912                         return ins;
5913                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count + fsig->hasthis == 1) {
5914                         int dreg = alloc_ireg (cfg);
5915                         /* Decompose later to allow more optimizations */
5916                         EMIT_NEW_UNALU (cfg, ins, OP_STRLEN, dreg, args [0]->dreg);
5917                         ins->type = STACK_I4;
5918                         ins->flags |= MONO_INST_FAULT;
5919                         cfg->cbb->has_array_access = TRUE;
5920                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
5921
5922                         return ins;
5923                 } else 
5924                         return NULL;
5925         } else if (cmethod->klass == mono_defaults.object_class) {
5926
5927                 if (strcmp (cmethod->name, "GetType") == 0 && fsig->param_count + fsig->hasthis == 1) {
5928                         int dreg = alloc_ireg_ref (cfg);
5929                         int vt_reg = alloc_preg (cfg);
5930                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vt_reg, args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
5931                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, vt_reg, MONO_STRUCT_OFFSET (MonoVTable, type));
5932                         type_from_op (cfg, ins, NULL, NULL);
5933
5934                         return ins;
5935                 } else if (!cfg->backend->emulate_mul_div && strcmp (cmethod->name, "InternalGetHashCode") == 0 && fsig->param_count == 1 && !mono_gc_is_moving ()) {
5936                         int dreg = alloc_ireg (cfg);
5937                         int t1 = alloc_ireg (cfg);
5938         
5939                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, t1, args [0]->dreg, 3);
5940                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_MUL_IMM, dreg, t1, 2654435761u);
5941                         ins->type = STACK_I4;
5942
5943                         return ins;
5944                 } else if (strcmp (cmethod->name, ".ctor") == 0 && fsig->param_count == 0) {
5945                         MONO_INST_NEW (cfg, ins, OP_NOP);
5946                         MONO_ADD_INS (cfg->cbb, ins);
5947                         return ins;
5948                 } else
5949                         return NULL;
5950         } else if (cmethod->klass == mono_defaults.array_class) {
5951                 if (strcmp (cmethod->name, "GetGenericValueImpl") == 0 && fsig->param_count + fsig->hasthis == 3 && !cfg->gsharedvt)
5952                         return emit_array_generic_access (cfg, fsig, args, FALSE);
5953                 else if (strcmp (cmethod->name, "SetGenericValueImpl") == 0 && fsig->param_count + fsig->hasthis == 3 && !cfg->gsharedvt)
5954                         return emit_array_generic_access (cfg, fsig, args, TRUE);
5955
5956 #ifndef MONO_BIG_ARRAYS
5957                 /*
5958                  * This is an inline version of GetLength/GetLowerBound(0) used frequently in
5959                  * Array methods.
5960                  */
5961                 else if (((strcmp (cmethod->name, "GetLength") == 0 && fsig->param_count + fsig->hasthis == 2) ||
5962                          (strcmp (cmethod->name, "GetLowerBound") == 0 && fsig->param_count + fsig->hasthis == 2)) &&
5963                          args [1]->opcode == OP_ICONST && args [1]->inst_c0 == 0) {
5964                         int dreg = alloc_ireg (cfg);
5965                         int bounds_reg = alloc_ireg_mp (cfg);
5966                         MonoBasicBlock *end_bb, *szarray_bb;
5967                         gboolean get_length = strcmp (cmethod->name, "GetLength") == 0;
5968
5969                         NEW_BBLOCK (cfg, end_bb);
5970                         NEW_BBLOCK (cfg, szarray_bb);
5971
5972                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOAD_MEMBASE, bounds_reg,
5973                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
5974                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
5975                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, szarray_bb);
5976                         /* Non-szarray case */
5977                         if (get_length)
5978                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5979                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5980                         else
5981                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5982                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5983                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
5984                         MONO_START_BB (cfg, szarray_bb);
5985                         /* Szarray case */
5986                         if (get_length)
5987                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5988                                                                            args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
5989                         else
5990                                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
5991                         MONO_START_BB (cfg, end_bb);
5992
5993                         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, dreg, dreg);
5994                         ins->type = STACK_I4;
5995                         
5996                         return ins;
5997                 }
5998 #endif
5999
6000                 if (cmethod->name [0] != 'g')
6001                         return NULL;
6002
6003                 if (strcmp (cmethod->name, "get_Rank") == 0 && fsig->param_count + fsig->hasthis == 1) {
6004                         int dreg = alloc_ireg (cfg);
6005                         int vtable_reg = alloc_preg (cfg);
6006                         MONO_EMIT_NEW_LOAD_MEMBASE_OP_FAULT (cfg, OP_LOAD_MEMBASE, vtable_reg, 
6007                                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
6008                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU1_MEMBASE, dreg,
6009                                                                    vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
6010                         type_from_op (cfg, ins, NULL, NULL);
6011
6012                         return ins;
6013                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count + fsig->hasthis == 1) {
6014                         int dreg = alloc_ireg (cfg);
6015
6016                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOADI4_MEMBASE, dreg, 
6017                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
6018                         type_from_op (cfg, ins, NULL, NULL);
6019
6020                         return ins;
6021                 } else
6022                         return NULL;
6023         } else if (cmethod->klass == runtime_helpers_class) {
6024
6025                 if (strcmp (cmethod->name, "get_OffsetToStringData") == 0 && fsig->param_count == 0) {
6026                         EMIT_NEW_ICONST (cfg, ins, MONO_STRUCT_OFFSET (MonoString, chars));
6027                         return ins;
6028                 } else
6029                         return NULL;
6030         } else if (cmethod->klass == mono_defaults.thread_class) {
6031                 if (strcmp (cmethod->name, "SpinWait_nop") == 0 && fsig->param_count == 0) {
6032                         MONO_INST_NEW (cfg, ins, OP_RELAXED_NOP);
6033                         MONO_ADD_INS (cfg->cbb, ins);
6034                         return ins;
6035                 } else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0) {
6036                         return emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6037                 } else if (!strcmp (cmethod->name, "VolatileRead") && fsig->param_count == 1) {
6038                         guint32 opcode = 0;
6039                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6040
6041                         if (fsig->params [0]->type == MONO_TYPE_I1)
6042                                 opcode = OP_LOADI1_MEMBASE;
6043                         else if (fsig->params [0]->type == MONO_TYPE_U1)
6044                                 opcode = OP_LOADU1_MEMBASE;
6045                         else if (fsig->params [0]->type == MONO_TYPE_I2)
6046                                 opcode = OP_LOADI2_MEMBASE;
6047                         else if (fsig->params [0]->type == MONO_TYPE_U2)
6048                                 opcode = OP_LOADU2_MEMBASE;
6049                         else if (fsig->params [0]->type == MONO_TYPE_I4)
6050                                 opcode = OP_LOADI4_MEMBASE;
6051                         else if (fsig->params [0]->type == MONO_TYPE_U4)
6052                                 opcode = OP_LOADU4_MEMBASE;
6053                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
6054                                 opcode = OP_LOADI8_MEMBASE;
6055                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6056                                 opcode = OP_LOADR4_MEMBASE;
6057                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6058                                 opcode = OP_LOADR8_MEMBASE;
6059                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
6060                                 opcode = OP_LOAD_MEMBASE;
6061
6062                         if (opcode) {
6063                                 MONO_INST_NEW (cfg, ins, opcode);
6064                                 ins->inst_basereg = args [0]->dreg;
6065                                 ins->inst_offset = 0;
6066                                 MONO_ADD_INS (cfg->cbb, ins);
6067
6068                                 switch (fsig->params [0]->type) {
6069                                 case MONO_TYPE_I1:
6070                                 case MONO_TYPE_U1:
6071                                 case MONO_TYPE_I2:
6072                                 case MONO_TYPE_U2:
6073                                 case MONO_TYPE_I4:
6074                                 case MONO_TYPE_U4:
6075                                         ins->dreg = mono_alloc_ireg (cfg);
6076                                         ins->type = STACK_I4;
6077                                         break;
6078                                 case MONO_TYPE_I8:
6079                                 case MONO_TYPE_U8:
6080                                         ins->dreg = mono_alloc_lreg (cfg);
6081                                         ins->type = STACK_I8;
6082                                         break;
6083                                 case MONO_TYPE_I:
6084                                 case MONO_TYPE_U:
6085                                         ins->dreg = mono_alloc_ireg (cfg);
6086 #if SIZEOF_REGISTER == 8
6087                                         ins->type = STACK_I8;
6088 #else
6089                                         ins->type = STACK_I4;
6090 #endif
6091                                         break;
6092                                 case MONO_TYPE_R4:
6093                                 case MONO_TYPE_R8:
6094                                         ins->dreg = mono_alloc_freg (cfg);
6095                                         ins->type = STACK_R8;
6096                                         break;
6097                                 default:
6098                                         g_assert (mini_type_is_reference (fsig->params [0]));
6099                                         ins->dreg = mono_alloc_ireg_ref (cfg);
6100                                         ins->type = STACK_OBJ;
6101                                         break;
6102                                 }
6103
6104                                 if (opcode == OP_LOADI8_MEMBASE)
6105                                         ins = mono_decompose_opcode (cfg, ins);
6106
6107                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
6108
6109                                 return ins;
6110                         }
6111                 } else if (!strcmp (cmethod->name, "VolatileWrite") && fsig->param_count == 2) {
6112                         guint32 opcode = 0;
6113                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6114
6115                         if (fsig->params [0]->type == MONO_TYPE_I1 || fsig->params [0]->type == MONO_TYPE_U1)
6116                                 opcode = OP_STOREI1_MEMBASE_REG;
6117                         else if (fsig->params [0]->type == MONO_TYPE_I2 || fsig->params [0]->type == MONO_TYPE_U2)
6118                                 opcode = OP_STOREI2_MEMBASE_REG;
6119                         else if (fsig->params [0]->type == MONO_TYPE_I4 || fsig->params [0]->type == MONO_TYPE_U4)
6120                                 opcode = OP_STOREI4_MEMBASE_REG;
6121                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
6122                                 opcode = OP_STOREI8_MEMBASE_REG;
6123                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6124                                 opcode = OP_STORER4_MEMBASE_REG;
6125                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6126                                 opcode = OP_STORER8_MEMBASE_REG;
6127                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
6128                                 opcode = OP_STORE_MEMBASE_REG;
6129
6130                         if (opcode) {
6131                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
6132
6133                                 MONO_INST_NEW (cfg, ins, opcode);
6134                                 ins->sreg1 = args [1]->dreg;
6135                                 ins->inst_destbasereg = args [0]->dreg;
6136                                 ins->inst_offset = 0;
6137                                 MONO_ADD_INS (cfg->cbb, ins);
6138
6139                                 if (opcode == OP_STOREI8_MEMBASE_REG)
6140                                         ins = mono_decompose_opcode (cfg, ins);
6141
6142                                 return ins;
6143                         }
6144                 }
6145         } else if (cmethod->klass->image == mono_defaults.corlib &&
6146                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
6147                            (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
6148                 ins = NULL;
6149
6150 #if SIZEOF_REGISTER == 8
6151                 if (!cfg->llvm_only && strcmp (cmethod->name, "Read") == 0 && fsig->param_count == 1 && (fsig->params [0]->type == MONO_TYPE_I8)) {
6152                         if (!cfg->llvm_only && mono_arch_opcode_supported (OP_ATOMIC_LOAD_I8)) {
6153                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_LOAD_I8);
6154                                 ins->dreg = mono_alloc_preg (cfg);
6155                                 ins->sreg1 = args [0]->dreg;
6156                                 ins->type = STACK_I8;
6157                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_SEQ;
6158                                 MONO_ADD_INS (cfg->cbb, ins);
6159                         } else {
6160                                 MonoInst *load_ins;
6161
6162                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6163
6164                                 /* 64 bit reads are already atomic */
6165                                 MONO_INST_NEW (cfg, load_ins, OP_LOADI8_MEMBASE);
6166                                 load_ins->dreg = mono_alloc_preg (cfg);
6167                                 load_ins->inst_basereg = args [0]->dreg;
6168                                 load_ins->inst_offset = 0;
6169                                 load_ins->type = STACK_I8;
6170                                 MONO_ADD_INS (cfg->cbb, load_ins);
6171
6172                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6173
6174                                 ins = load_ins;
6175                         }
6176                 }
6177 #endif
6178
6179                 if (strcmp (cmethod->name, "Increment") == 0 && fsig->param_count == 1) {
6180                         MonoInst *ins_iconst;
6181                         guint32 opcode = 0;
6182
6183                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6184                                 opcode = OP_ATOMIC_ADD_I4;
6185                                 cfg->has_atomic_add_i4 = TRUE;
6186                         }
6187 #if SIZEOF_REGISTER == 8
6188                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6189                                 opcode = OP_ATOMIC_ADD_I8;
6190 #endif
6191                         if (opcode) {
6192                                 if (!mono_arch_opcode_supported (opcode))
6193                                         return NULL;
6194                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
6195                                 ins_iconst->inst_c0 = 1;
6196                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
6197                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
6198
6199                                 MONO_INST_NEW (cfg, ins, opcode);
6200                                 ins->dreg = mono_alloc_ireg (cfg);
6201                                 ins->inst_basereg = args [0]->dreg;
6202                                 ins->inst_offset = 0;
6203                                 ins->sreg2 = ins_iconst->dreg;
6204                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6205                                 MONO_ADD_INS (cfg->cbb, ins);
6206                         }
6207                 } else if (strcmp (cmethod->name, "Decrement") == 0 && fsig->param_count == 1) {
6208                         MonoInst *ins_iconst;
6209                         guint32 opcode = 0;
6210
6211                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6212                                 opcode = OP_ATOMIC_ADD_I4;
6213                                 cfg->has_atomic_add_i4 = TRUE;
6214                         }
6215 #if SIZEOF_REGISTER == 8
6216                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6217                                 opcode = OP_ATOMIC_ADD_I8;
6218 #endif
6219                         if (opcode) {
6220                                 if (!mono_arch_opcode_supported (opcode))
6221                                         return NULL;
6222                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
6223                                 ins_iconst->inst_c0 = -1;
6224                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
6225                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
6226
6227                                 MONO_INST_NEW (cfg, ins, opcode);
6228                                 ins->dreg = mono_alloc_ireg (cfg);
6229                                 ins->inst_basereg = args [0]->dreg;
6230                                 ins->inst_offset = 0;
6231                                 ins->sreg2 = ins_iconst->dreg;
6232                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6233                                 MONO_ADD_INS (cfg->cbb, ins);
6234                         }
6235                 } else if (strcmp (cmethod->name, "Add") == 0 && fsig->param_count == 2) {
6236                         guint32 opcode = 0;
6237
6238                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6239                                 opcode = OP_ATOMIC_ADD_I4;
6240                                 cfg->has_atomic_add_i4 = TRUE;
6241                         }
6242 #if SIZEOF_REGISTER == 8
6243                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6244                                 opcode = OP_ATOMIC_ADD_I8;
6245 #endif
6246                         if (opcode) {
6247                                 if (!mono_arch_opcode_supported (opcode))
6248                                         return NULL;
6249                                 MONO_INST_NEW (cfg, ins, opcode);
6250                                 ins->dreg = mono_alloc_ireg (cfg);
6251                                 ins->inst_basereg = args [0]->dreg;
6252                                 ins->inst_offset = 0;
6253                                 ins->sreg2 = args [1]->dreg;
6254                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6255                                 MONO_ADD_INS (cfg->cbb, ins);
6256                         }
6257                 }
6258                 else if (strcmp (cmethod->name, "Exchange") == 0 && fsig->param_count == 2) {
6259                         MonoInst *f2i = NULL, *i2f;
6260                         guint32 opcode, f2i_opcode, i2f_opcode;
6261                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6262                         gboolean is_float = fsig->params [0]->type == MONO_TYPE_R4 || fsig->params [0]->type == MONO_TYPE_R8;
6263
6264                         if (fsig->params [0]->type == MONO_TYPE_I4 ||
6265                             fsig->params [0]->type == MONO_TYPE_R4) {
6266                                 opcode = OP_ATOMIC_EXCHANGE_I4;
6267                                 f2i_opcode = OP_MOVE_F_TO_I4;
6268                                 i2f_opcode = OP_MOVE_I4_TO_F;
6269                                 cfg->has_atomic_exchange_i4 = TRUE;
6270                         }
6271 #if SIZEOF_REGISTER == 8
6272                         else if (is_ref ||
6273                                  fsig->params [0]->type == MONO_TYPE_I8 ||
6274                                  fsig->params [0]->type == MONO_TYPE_R8 ||
6275                                  fsig->params [0]->type == MONO_TYPE_I) {
6276                                 opcode = OP_ATOMIC_EXCHANGE_I8;
6277                                 f2i_opcode = OP_MOVE_F_TO_I8;
6278                                 i2f_opcode = OP_MOVE_I8_TO_F;
6279                         }
6280 #else
6281                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I) {
6282                                 opcode = OP_ATOMIC_EXCHANGE_I4;
6283                                 cfg->has_atomic_exchange_i4 = TRUE;
6284                         }
6285 #endif
6286                         else
6287                                 return NULL;
6288
6289                         if (!mono_arch_opcode_supported (opcode))
6290                                 return NULL;
6291
6292                         if (is_float) {
6293                                 /* TODO: Decompose these opcodes instead of bailing here. */
6294                                 if (COMPILE_SOFT_FLOAT (cfg))
6295                                         return NULL;
6296
6297                                 MONO_INST_NEW (cfg, f2i, f2i_opcode);
6298                                 f2i->dreg = mono_alloc_ireg (cfg);
6299                                 f2i->sreg1 = args [1]->dreg;
6300                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6301                                         f2i->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6302                                 MONO_ADD_INS (cfg->cbb, f2i);
6303                         }
6304
6305                         MONO_INST_NEW (cfg, ins, opcode);
6306                         ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : mono_alloc_ireg (cfg);
6307                         ins->inst_basereg = args [0]->dreg;
6308                         ins->inst_offset = 0;
6309                         ins->sreg2 = is_float ? f2i->dreg : args [1]->dreg;
6310                         MONO_ADD_INS (cfg->cbb, ins);
6311
6312                         switch (fsig->params [0]->type) {
6313                         case MONO_TYPE_I4:
6314                                 ins->type = STACK_I4;
6315                                 break;
6316                         case MONO_TYPE_I8:
6317                                 ins->type = STACK_I8;
6318                                 break;
6319                         case MONO_TYPE_I:
6320 #if SIZEOF_REGISTER == 8
6321                                 ins->type = STACK_I8;
6322 #else
6323                                 ins->type = STACK_I4;
6324 #endif
6325                                 break;
6326                         case MONO_TYPE_R4:
6327                         case MONO_TYPE_R8:
6328                                 ins->type = STACK_R8;
6329                                 break;
6330                         default:
6331                                 g_assert (mini_type_is_reference (fsig->params [0]));
6332                                 ins->type = STACK_OBJ;
6333                                 break;
6334                         }
6335
6336                         if (is_float) {
6337                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
6338                                 i2f->dreg = mono_alloc_freg (cfg);
6339                                 i2f->sreg1 = ins->dreg;
6340                                 i2f->type = STACK_R8;
6341                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
6342                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6343                                 MONO_ADD_INS (cfg->cbb, i2f);
6344
6345                                 ins = i2f;
6346                         }
6347
6348                         if (cfg->gen_write_barriers && is_ref)
6349                                 emit_write_barrier (cfg, args [0], args [1]);
6350                 }
6351                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 3) {
6352                         MonoInst *f2i_new = NULL, *f2i_cmp = NULL, *i2f;
6353                         guint32 opcode, f2i_opcode, i2f_opcode;
6354                         gboolean is_ref = mini_type_is_reference (fsig->params [1]);
6355                         gboolean is_float = fsig->params [1]->type == MONO_TYPE_R4 || fsig->params [1]->type == MONO_TYPE_R8;
6356
6357                         if (fsig->params [1]->type == MONO_TYPE_I4 ||
6358                             fsig->params [1]->type == MONO_TYPE_R4) {
6359                                 opcode = OP_ATOMIC_CAS_I4;
6360                                 f2i_opcode = OP_MOVE_F_TO_I4;
6361                                 i2f_opcode = OP_MOVE_I4_TO_F;
6362                                 cfg->has_atomic_cas_i4 = TRUE;
6363                         }
6364 #if SIZEOF_REGISTER == 8
6365                         else if (is_ref ||
6366                                  fsig->params [1]->type == MONO_TYPE_I8 ||
6367                                  fsig->params [1]->type == MONO_TYPE_R8 ||
6368                                  fsig->params [1]->type == MONO_TYPE_I) {
6369                                 opcode = OP_ATOMIC_CAS_I8;
6370                                 f2i_opcode = OP_MOVE_F_TO_I8;
6371                                 i2f_opcode = OP_MOVE_I8_TO_F;
6372                         }
6373 #else
6374                         else if (is_ref || fsig->params [1]->type == MONO_TYPE_I) {
6375                                 opcode = OP_ATOMIC_CAS_I4;
6376                                 cfg->has_atomic_cas_i4 = TRUE;
6377                         }
6378 #endif
6379                         else
6380                                 return NULL;
6381
6382                         if (!mono_arch_opcode_supported (opcode))
6383                                 return NULL;
6384
6385                         if (is_float) {
6386                                 /* TODO: Decompose these opcodes instead of bailing here. */
6387                                 if (COMPILE_SOFT_FLOAT (cfg))
6388                                         return NULL;
6389
6390                                 MONO_INST_NEW (cfg, f2i_new, f2i_opcode);
6391                                 f2i_new->dreg = mono_alloc_ireg (cfg);
6392                                 f2i_new->sreg1 = args [1]->dreg;
6393                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6394                                         f2i_new->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6395                                 MONO_ADD_INS (cfg->cbb, f2i_new);
6396
6397                                 MONO_INST_NEW (cfg, f2i_cmp, f2i_opcode);
6398                                 f2i_cmp->dreg = mono_alloc_ireg (cfg);
6399                                 f2i_cmp->sreg1 = args [2]->dreg;
6400                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6401                                         f2i_cmp->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6402                                 MONO_ADD_INS (cfg->cbb, f2i_cmp);
6403                         }
6404
6405                         MONO_INST_NEW (cfg, ins, opcode);
6406                         ins->dreg = is_ref ? alloc_ireg_ref (cfg) : alloc_ireg (cfg);
6407                         ins->sreg1 = args [0]->dreg;
6408                         ins->sreg2 = is_float ? f2i_new->dreg : args [1]->dreg;
6409                         ins->sreg3 = is_float ? f2i_cmp->dreg : args [2]->dreg;
6410                         MONO_ADD_INS (cfg->cbb, ins);
6411
6412                         switch (fsig->params [1]->type) {
6413                         case MONO_TYPE_I4:
6414                                 ins->type = STACK_I4;
6415                                 break;
6416                         case MONO_TYPE_I8:
6417                                 ins->type = STACK_I8;
6418                                 break;
6419                         case MONO_TYPE_I:
6420 #if SIZEOF_REGISTER == 8
6421                                 ins->type = STACK_I8;
6422 #else
6423                                 ins->type = STACK_I4;
6424 #endif
6425                                 break;
6426                         case MONO_TYPE_R4:
6427                                 ins->type = cfg->r4_stack_type;
6428                                 break;
6429                         case MONO_TYPE_R8:
6430                                 ins->type = STACK_R8;
6431                                 break;
6432                         default:
6433                                 g_assert (mini_type_is_reference (fsig->params [1]));
6434                                 ins->type = STACK_OBJ;
6435                                 break;
6436                         }
6437
6438                         if (is_float) {
6439                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
6440                                 i2f->dreg = mono_alloc_freg (cfg);
6441                                 i2f->sreg1 = ins->dreg;
6442                                 i2f->type = STACK_R8;
6443                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
6444                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6445                                 MONO_ADD_INS (cfg->cbb, i2f);
6446
6447                                 ins = i2f;
6448                         }
6449
6450                         if (cfg->gen_write_barriers && is_ref)
6451                                 emit_write_barrier (cfg, args [0], args [1]);
6452                 }
6453                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 4 &&
6454                          fsig->params [1]->type == MONO_TYPE_I4) {
6455                         MonoInst *cmp, *ceq;
6456
6457                         if (!mono_arch_opcode_supported (OP_ATOMIC_CAS_I4))
6458                                 return NULL;
6459
6460                         /* int32 r = CAS (location, value, comparand); */
6461                         MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I4);
6462                         ins->dreg = alloc_ireg (cfg);
6463                         ins->sreg1 = args [0]->dreg;
6464                         ins->sreg2 = args [1]->dreg;
6465                         ins->sreg3 = args [2]->dreg;
6466                         ins->type = STACK_I4;
6467                         MONO_ADD_INS (cfg->cbb, ins);
6468
6469                         /* bool result = r == comparand; */
6470                         MONO_INST_NEW (cfg, cmp, OP_ICOMPARE);
6471                         cmp->sreg1 = ins->dreg;
6472                         cmp->sreg2 = args [2]->dreg;
6473                         cmp->type = STACK_I4;
6474                         MONO_ADD_INS (cfg->cbb, cmp);
6475
6476                         MONO_INST_NEW (cfg, ceq, OP_ICEQ);
6477                         ceq->dreg = alloc_ireg (cfg);
6478                         ceq->type = STACK_I4;
6479                         MONO_ADD_INS (cfg->cbb, ceq);
6480
6481                         /* *success = result; */
6482                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, args [3]->dreg, 0, ceq->dreg);
6483
6484                         cfg->has_atomic_cas_i4 = TRUE;
6485                 }
6486                 else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0)
6487                         ins = emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6488
6489                 if (ins)
6490                         return ins;
6491         } else if (cmethod->klass->image == mono_defaults.corlib &&
6492                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
6493                            (strcmp (cmethod->klass->name, "Volatile") == 0)) {
6494                 ins = NULL;
6495
6496                 if (!cfg->llvm_only && !strcmp (cmethod->name, "Read") && fsig->param_count == 1) {
6497                         guint32 opcode = 0;
6498                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6499                         gboolean is_float = fsig->params [0]->type == MONO_TYPE_R4 || fsig->params [0]->type == MONO_TYPE_R8;
6500
6501                         if (fsig->params [0]->type == MONO_TYPE_I1)
6502                                 opcode = OP_ATOMIC_LOAD_I1;
6503                         else if (fsig->params [0]->type == MONO_TYPE_U1 || fsig->params [0]->type == MONO_TYPE_BOOLEAN)
6504                                 opcode = OP_ATOMIC_LOAD_U1;
6505                         else if (fsig->params [0]->type == MONO_TYPE_I2)
6506                                 opcode = OP_ATOMIC_LOAD_I2;
6507                         else if (fsig->params [0]->type == MONO_TYPE_U2)
6508                                 opcode = OP_ATOMIC_LOAD_U2;
6509                         else if (fsig->params [0]->type == MONO_TYPE_I4)
6510                                 opcode = OP_ATOMIC_LOAD_I4;
6511                         else if (fsig->params [0]->type == MONO_TYPE_U4)
6512                                 opcode = OP_ATOMIC_LOAD_U4;
6513                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6514                                 opcode = OP_ATOMIC_LOAD_R4;
6515                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6516                                 opcode = OP_ATOMIC_LOAD_R8;
6517 #if SIZEOF_REGISTER == 8
6518                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_I)
6519                                 opcode = OP_ATOMIC_LOAD_I8;
6520                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_U8 || fsig->params [0]->type == MONO_TYPE_U)
6521                                 opcode = OP_ATOMIC_LOAD_U8;
6522 #else
6523                         else if (fsig->params [0]->type == MONO_TYPE_I)
6524                                 opcode = OP_ATOMIC_LOAD_I4;
6525                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_U)
6526                                 opcode = OP_ATOMIC_LOAD_U4;
6527 #endif
6528
6529                         if (opcode) {
6530                                 if (!mono_arch_opcode_supported (opcode))
6531                                         return NULL;
6532
6533                                 MONO_INST_NEW (cfg, ins, opcode);
6534                                 ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : (is_float ? mono_alloc_freg (cfg) : mono_alloc_ireg (cfg));
6535                                 ins->sreg1 = args [0]->dreg;
6536                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_ACQ;
6537                                 MONO_ADD_INS (cfg->cbb, ins);
6538
6539                                 switch (fsig->params [0]->type) {
6540                                 case MONO_TYPE_BOOLEAN:
6541                                 case MONO_TYPE_I1:
6542                                 case MONO_TYPE_U1:
6543                                 case MONO_TYPE_I2:
6544                                 case MONO_TYPE_U2:
6545                                 case MONO_TYPE_I4:
6546                                 case MONO_TYPE_U4:
6547                                         ins->type = STACK_I4;
6548                                         break;
6549                                 case MONO_TYPE_I8:
6550                                 case MONO_TYPE_U8:
6551                                         ins->type = STACK_I8;
6552                                         break;
6553                                 case MONO_TYPE_I:
6554                                 case MONO_TYPE_U:
6555 #if SIZEOF_REGISTER == 8
6556                                         ins->type = STACK_I8;
6557 #else
6558                                         ins->type = STACK_I4;
6559 #endif
6560                                         break;
6561                                 case MONO_TYPE_R4:
6562                                         ins->type = cfg->r4_stack_type;
6563                                         break;
6564                                 case MONO_TYPE_R8:
6565                                         ins->type = STACK_R8;
6566                                         break;
6567                                 default:
6568                                         g_assert (mini_type_is_reference (fsig->params [0]));
6569                                         ins->type = STACK_OBJ;
6570                                         break;
6571                                 }
6572                         }
6573                 }
6574
6575                 if (!cfg->llvm_only && !strcmp (cmethod->name, "Write") && fsig->param_count == 2) {
6576                         guint32 opcode = 0;
6577                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6578
6579                         if (fsig->params [0]->type == MONO_TYPE_I1)
6580                                 opcode = OP_ATOMIC_STORE_I1;
6581                         else if (fsig->params [0]->type == MONO_TYPE_U1 || fsig->params [0]->type == MONO_TYPE_BOOLEAN)
6582                                 opcode = OP_ATOMIC_STORE_U1;
6583                         else if (fsig->params [0]->type == MONO_TYPE_I2)
6584                                 opcode = OP_ATOMIC_STORE_I2;
6585                         else if (fsig->params [0]->type == MONO_TYPE_U2)
6586                                 opcode = OP_ATOMIC_STORE_U2;
6587                         else if (fsig->params [0]->type == MONO_TYPE_I4)
6588                                 opcode = OP_ATOMIC_STORE_I4;
6589                         else if (fsig->params [0]->type == MONO_TYPE_U4)
6590                                 opcode = OP_ATOMIC_STORE_U4;
6591                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6592                                 opcode = OP_ATOMIC_STORE_R4;
6593                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6594                                 opcode = OP_ATOMIC_STORE_R8;
6595 #if SIZEOF_REGISTER == 8
6596                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_I)
6597                                 opcode = OP_ATOMIC_STORE_I8;
6598                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_U8 || fsig->params [0]->type == MONO_TYPE_U)
6599                                 opcode = OP_ATOMIC_STORE_U8;
6600 #else
6601                         else if (fsig->params [0]->type == MONO_TYPE_I)
6602                                 opcode = OP_ATOMIC_STORE_I4;
6603                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_U)
6604                                 opcode = OP_ATOMIC_STORE_U4;
6605 #endif
6606
6607                         if (opcode) {
6608                                 if (!mono_arch_opcode_supported (opcode))
6609                                         return NULL;
6610
6611                                 MONO_INST_NEW (cfg, ins, opcode);
6612                                 ins->dreg = args [0]->dreg;
6613                                 ins->sreg1 = args [1]->dreg;
6614                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_REL;
6615                                 MONO_ADD_INS (cfg->cbb, ins);
6616
6617                                 if (cfg->gen_write_barriers && is_ref)
6618                                         emit_write_barrier (cfg, args [0], args [1]);
6619                         }
6620                 }
6621
6622                 if (ins)
6623                         return ins;
6624         } else if (cmethod->klass->image == mono_defaults.corlib &&
6625                            (strcmp (cmethod->klass->name_space, "System.Diagnostics") == 0) &&
6626                            (strcmp (cmethod->klass->name, "Debugger") == 0)) {
6627                 if (!strcmp (cmethod->name, "Break") && fsig->param_count == 0) {
6628                         if (should_insert_brekpoint (cfg->method)) {
6629                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
6630                         } else {
6631                                 MONO_INST_NEW (cfg, ins, OP_NOP);
6632                                 MONO_ADD_INS (cfg->cbb, ins);
6633                         }
6634                         return ins;
6635                 }
6636         } else if (cmethod->klass->image == mono_defaults.corlib &&
6637                    (strcmp (cmethod->klass->name_space, "System") == 0) &&
6638                    (strcmp (cmethod->klass->name, "Environment") == 0)) {
6639                 if (!strcmp (cmethod->name, "get_IsRunningOnWindows") && fsig->param_count == 0) {
6640 #ifdef TARGET_WIN32
6641                         EMIT_NEW_ICONST (cfg, ins, 1);
6642 #else
6643                         EMIT_NEW_ICONST (cfg, ins, 0);
6644 #endif
6645                 }
6646         } else if (cmethod->klass->image == mono_defaults.corlib &&
6647                            (strcmp (cmethod->klass->name_space, "System.Reflection") == 0) &&
6648                            (strcmp (cmethod->klass->name, "Assembly") == 0)) {
6649                 if (cfg->llvm_only && !strcmp (cmethod->name, "GetExecutingAssembly")) {
6650                         /* No stack walks are current available, so implement this as an intrinsic */
6651                         MonoInst *assembly_ins;
6652
6653                         EMIT_NEW_AOTCONST (cfg, assembly_ins, MONO_PATCH_INFO_IMAGE, cfg->method->klass->image);
6654                         ins = mono_emit_jit_icall (cfg, mono_get_assembly_object, &assembly_ins);
6655                         return ins;
6656                 }
6657         } else if (cmethod->klass == mono_defaults.math_class) {
6658                 /* 
6659                  * There is general branchless code for Min/Max, but it does not work for 
6660                  * all inputs:
6661                  * http://everything2.com/?node_id=1051618
6662                  */
6663         } else if (((!strcmp (cmethod->klass->image->assembly->aname.name, "MonoMac") ||
6664                     !strcmp (cmethod->klass->image->assembly->aname.name, "monotouch")) &&
6665                                 !strcmp (cmethod->klass->name_space, "XamCore.ObjCRuntime") &&
6666                                 !strcmp (cmethod->klass->name, "Selector")) ||
6667                            (!strcmp (cmethod->klass->image->assembly->aname.name, "Xamarin.iOS") &&
6668                                 !strcmp (cmethod->klass->name_space, "ObjCRuntime") &&
6669                                 !strcmp (cmethod->klass->name, "Selector"))
6670                            ) {
6671                 if (cfg->backend->have_objc_get_selector &&
6672                         !strcmp (cmethod->name, "GetHandle") && fsig->param_count == 1 &&
6673                     (args [0]->opcode == OP_GOT_ENTRY || args [0]->opcode == OP_AOTCONST) &&
6674                     cfg->compile_aot) {
6675                         MonoInst *pi;
6676                         MonoJumpInfoToken *ji;
6677                         MonoString *s;
6678
6679                         cfg->disable_llvm = TRUE;
6680
6681                         if (args [0]->opcode == OP_GOT_ENTRY) {
6682                                 pi = args [0]->inst_p1;
6683                                 g_assert (pi->opcode == OP_PATCH_INFO);
6684                                 g_assert (GPOINTER_TO_INT (pi->inst_p1) == MONO_PATCH_INFO_LDSTR);
6685                                 ji = pi->inst_p0;
6686                         } else {
6687                                 g_assert (GPOINTER_TO_INT (args [0]->inst_p1) == MONO_PATCH_INFO_LDSTR);
6688                                 ji = args [0]->inst_p0;
6689                         }
6690
6691                         NULLIFY_INS (args [0]);
6692
6693                         // FIXME: Ugly
6694                         s = mono_ldstr (cfg->domain, ji->image, mono_metadata_token_index (ji->token));
6695                         MONO_INST_NEW (cfg, ins, OP_OBJC_GET_SELECTOR);
6696                         ins->dreg = mono_alloc_ireg (cfg);
6697                         // FIXME: Leaks
6698                         ins->inst_p0 = mono_string_to_utf8 (s);
6699                         MONO_ADD_INS (cfg->cbb, ins);
6700                         return ins;
6701                 }
6702         }
6703
6704 #ifdef MONO_ARCH_SIMD_INTRINSICS
6705         if (cfg->opt & MONO_OPT_SIMD) {
6706                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
6707                 if (ins)
6708                         return ins;
6709         }
6710 #endif
6711
6712         ins = mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
6713         if (ins)
6714                 return ins;
6715
6716         if (COMPILE_LLVM (cfg)) {
6717                 ins = llvm_emit_inst_for_method (cfg, cmethod, fsig, args);
6718                 if (ins)
6719                         return ins;
6720         }
6721
6722         return mono_arch_emit_inst_for_method (cfg, cmethod, fsig, args);
6723 }
6724
6725 /*
6726  * This entry point could be used later for arbitrary method
6727  * redirection.
6728  */
6729 inline static MonoInst*
6730 mini_redirect_call (MonoCompile *cfg, MonoMethod *method,  
6731                                         MonoMethodSignature *signature, MonoInst **args, MonoInst *this_ins)
6732 {
6733         if (method->klass == mono_defaults.string_class) {
6734                 /* managed string allocation support */
6735                 if (strcmp (method->name, "InternalAllocateStr") == 0 && !(mono_profiler_events & MONO_PROFILE_ALLOCATIONS) && !(cfg->opt & MONO_OPT_SHARED)) {
6736                         MonoInst *iargs [2];
6737                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
6738                         MonoMethod *managed_alloc = NULL;
6739
6740                         g_assert (vtable); /*Should not fail since it System.String*/
6741 #ifndef MONO_CROSS_COMPILE
6742                         managed_alloc = mono_gc_get_managed_allocator (method->klass, FALSE, FALSE);
6743 #endif
6744                         if (!managed_alloc)
6745                                 return NULL;
6746                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
6747                         iargs [1] = args [0];
6748                         return mono_emit_method_call (cfg, managed_alloc, iargs, this_ins);
6749                 }
6750         }
6751         return NULL;
6752 }
6753
6754 static void
6755 mono_save_args (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **sp)
6756 {
6757         MonoInst *store, *temp;
6758         int i;
6759
6760         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
6761                 MonoType *argtype = (sig->hasthis && (i == 0)) ? type_from_stack_type (*sp) : sig->params [i - sig->hasthis];
6762
6763                 /*
6764                  * FIXME: We should use *args++ = sp [0], but that would mean the arg
6765                  * would be different than the MonoInst's used to represent arguments, and
6766                  * the ldelema implementation can't deal with that.
6767                  * Solution: When ldelema is used on an inline argument, create a var for 
6768                  * it, emit ldelema on that var, and emit the saving code below in
6769                  * inline_method () if needed.
6770                  */
6771                 temp = mono_compile_create_var (cfg, argtype, OP_LOCAL);
6772                 cfg->args [i] = temp;
6773                 /* This uses cfg->args [i] which is set by the preceeding line */
6774                 EMIT_NEW_ARGSTORE (cfg, store, i, *sp);
6775                 store->cil_code = sp [0]->cil_code;
6776                 sp++;
6777         }
6778 }
6779
6780 #define MONO_INLINE_CALLED_LIMITED_METHODS 1
6781 #define MONO_INLINE_CALLER_LIMITED_METHODS 1
6782
6783 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
6784 static gboolean
6785 check_inline_called_method_name_limit (MonoMethod *called_method)
6786 {
6787         int strncmp_result;
6788         static const char *limit = NULL;
6789         
6790         if (limit == NULL) {
6791                 const char *limit_string = g_getenv ("MONO_INLINE_CALLED_METHOD_NAME_LIMIT");
6792
6793                 if (limit_string != NULL)
6794                         limit = limit_string;
6795                 else
6796                         limit = "";
6797         }
6798
6799         if (limit [0] != '\0') {
6800                 char *called_method_name = mono_method_full_name (called_method, TRUE);
6801
6802                 strncmp_result = strncmp (called_method_name, limit, strlen (limit));
6803                 g_free (called_method_name);
6804         
6805                 //return (strncmp_result <= 0);
6806                 return (strncmp_result == 0);
6807         } else {
6808                 return TRUE;
6809         }
6810 }
6811 #endif
6812
6813 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
6814 static gboolean
6815 check_inline_caller_method_name_limit (MonoMethod *caller_method)
6816 {
6817         int strncmp_result;
6818         static const char *limit = NULL;
6819         
6820         if (limit == NULL) {
6821                 const char *limit_string = g_getenv ("MONO_INLINE_CALLER_METHOD_NAME_LIMIT");
6822                 if (limit_string != NULL) {
6823                         limit = limit_string;
6824                 } else {
6825                         limit = "";
6826                 }
6827         }
6828
6829         if (limit [0] != '\0') {
6830                 char *caller_method_name = mono_method_full_name (caller_method, TRUE);
6831
6832                 strncmp_result = strncmp (caller_method_name, limit, strlen (limit));
6833                 g_free (caller_method_name);
6834         
6835                 //return (strncmp_result <= 0);
6836                 return (strncmp_result == 0);
6837         } else {
6838                 return TRUE;
6839         }
6840 }
6841 #endif
6842
6843 static void
6844 emit_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
6845 {
6846         static double r8_0 = 0.0;
6847         static float r4_0 = 0.0;
6848         MonoInst *ins;
6849         int t;
6850
6851         rtype = mini_get_underlying_type (rtype);
6852         t = rtype->type;
6853
6854         if (rtype->byref) {
6855                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
6856         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
6857                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
6858         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
6859                 MONO_EMIT_NEW_I8CONST (cfg, dreg, 0);
6860         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
6861                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
6862                 ins->type = STACK_R4;
6863                 ins->inst_p0 = (void*)&r4_0;
6864                 ins->dreg = dreg;
6865                 MONO_ADD_INS (cfg->cbb, ins);
6866         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
6867                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
6868                 ins->type = STACK_R8;
6869                 ins->inst_p0 = (void*)&r8_0;
6870                 ins->dreg = dreg;
6871                 MONO_ADD_INS (cfg->cbb, ins);
6872         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
6873                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
6874                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
6875         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (rtype)) {
6876                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
6877         } else {
6878                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
6879         }
6880 }
6881
6882 static void
6883 emit_dummy_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
6884 {
6885         int t;
6886
6887         rtype = mini_get_underlying_type (rtype);
6888         t = rtype->type;
6889
6890         if (rtype->byref) {
6891                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_PCONST);
6892         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
6893                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_ICONST);
6894         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
6895                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_I8CONST);
6896         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
6897                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R4CONST);
6898         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
6899                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R8CONST);
6900         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
6901                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
6902                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
6903         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (rtype)) {
6904                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
6905         } else {
6906                 emit_init_rvar (cfg, dreg, rtype);
6907         }
6908 }
6909
6910 /* If INIT is FALSE, emit dummy initialization statements to keep the IR valid */
6911 static void
6912 emit_init_local (MonoCompile *cfg, int local, MonoType *type, gboolean init)
6913 {
6914         MonoInst *var = cfg->locals [local];
6915         if (COMPILE_SOFT_FLOAT (cfg)) {
6916                 MonoInst *store;
6917                 int reg = alloc_dreg (cfg, var->type);
6918                 emit_init_rvar (cfg, reg, type);
6919                 EMIT_NEW_LOCSTORE (cfg, store, local, cfg->cbb->last_ins);
6920         } else {
6921                 if (init)
6922                         emit_init_rvar (cfg, var->dreg, type);
6923                 else
6924                         emit_dummy_init_rvar (cfg, var->dreg, type);
6925         }
6926 }
6927
6928 /*
6929  * inline_method:
6930  *
6931  *   Return the cost of inlining CMETHOD.
6932  */
6933 static int
6934 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
6935                            guchar *ip, guint real_offset, gboolean inline_always)
6936 {
6937         MonoInst *ins, *rvar = NULL;
6938         MonoMethodHeader *cheader;
6939         MonoBasicBlock *ebblock, *sbblock;
6940         int i, costs;
6941         MonoMethod *prev_inlined_method;
6942         MonoInst **prev_locals, **prev_args;
6943         MonoType **prev_arg_types;
6944         guint prev_real_offset;
6945         GHashTable *prev_cbb_hash;
6946         MonoBasicBlock **prev_cil_offset_to_bb;
6947         MonoBasicBlock *prev_cbb;
6948         unsigned char* prev_cil_start;
6949         guint32 prev_cil_offset_to_bb_len;
6950         MonoMethod *prev_current_method;
6951         MonoGenericContext *prev_generic_context;
6952         gboolean ret_var_set, prev_ret_var_set, prev_disable_inline, virtual = FALSE;
6953
6954         g_assert (cfg->exception_type == MONO_EXCEPTION_NONE);
6955
6956 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
6957         if ((! inline_always) && ! check_inline_called_method_name_limit (cmethod))
6958                 return 0;
6959 #endif
6960 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
6961         if ((! inline_always) && ! check_inline_caller_method_name_limit (cfg->method))
6962                 return 0;
6963 #endif
6964
6965         if (!fsig)
6966                 fsig = mono_method_signature (cmethod);
6967
6968         if (cfg->verbose_level > 2)
6969                 printf ("INLINE START %p %s -> %s\n", cmethod,  mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
6970
6971         if (!cmethod->inline_info) {
6972                 cfg->stat_inlineable_methods++;
6973                 cmethod->inline_info = 1;
6974         }
6975
6976         /* allocate local variables */
6977         cheader = mono_method_get_header (cmethod);
6978
6979         if (cheader == NULL || mono_loader_get_last_error ()) {
6980                 MonoLoaderError *error = mono_loader_get_last_error ();
6981
6982                 if (cheader)
6983                         mono_metadata_free_mh (cheader);
6984                 if (inline_always && error)
6985                         mono_cfg_set_exception (cfg, error->exception_type);
6986
6987                 mono_loader_clear_error ();
6988                 return 0;
6989         }
6990
6991         /*Must verify before creating locals as it can cause the JIT to assert.*/
6992         if (mono_compile_is_broken (cfg, cmethod, FALSE)) {
6993                 mono_metadata_free_mh (cheader);
6994                 return 0;
6995         }
6996
6997         /* allocate space to store the return value */
6998         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
6999                 rvar = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
7000         }
7001
7002         prev_locals = cfg->locals;
7003         cfg->locals = mono_mempool_alloc0 (cfg->mempool, cheader->num_locals * sizeof (MonoInst*));     
7004         for (i = 0; i < cheader->num_locals; ++i)
7005                 cfg->locals [i] = mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
7006
7007         /* allocate start and end blocks */
7008         /* This is needed so if the inline is aborted, we can clean up */
7009         NEW_BBLOCK (cfg, sbblock);
7010         sbblock->real_offset = real_offset;
7011
7012         NEW_BBLOCK (cfg, ebblock);
7013         ebblock->block_num = cfg->num_bblocks++;
7014         ebblock->real_offset = real_offset;
7015
7016         prev_args = cfg->args;
7017         prev_arg_types = cfg->arg_types;
7018         prev_inlined_method = cfg->inlined_method;
7019         cfg->inlined_method = cmethod;
7020         cfg->ret_var_set = FALSE;
7021         cfg->inline_depth ++;
7022         prev_real_offset = cfg->real_offset;
7023         prev_cbb_hash = cfg->cbb_hash;
7024         prev_cil_offset_to_bb = cfg->cil_offset_to_bb;
7025         prev_cil_offset_to_bb_len = cfg->cil_offset_to_bb_len;
7026         prev_cil_start = cfg->cil_start;
7027         prev_cbb = cfg->cbb;
7028         prev_current_method = cfg->current_method;
7029         prev_generic_context = cfg->generic_context;
7030         prev_ret_var_set = cfg->ret_var_set;
7031         prev_disable_inline = cfg->disable_inline;
7032
7033         if (ip && *ip == CEE_CALLVIRT && !(cmethod->flags & METHOD_ATTRIBUTE_STATIC))
7034                 virtual = TRUE;
7035
7036         costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, rvar, sp, real_offset, virtual);
7037
7038         ret_var_set = cfg->ret_var_set;
7039
7040         cfg->inlined_method = prev_inlined_method;
7041         cfg->real_offset = prev_real_offset;
7042         cfg->cbb_hash = prev_cbb_hash;
7043         cfg->cil_offset_to_bb = prev_cil_offset_to_bb;
7044         cfg->cil_offset_to_bb_len = prev_cil_offset_to_bb_len;
7045         cfg->cil_start = prev_cil_start;
7046         cfg->locals = prev_locals;
7047         cfg->args = prev_args;
7048         cfg->arg_types = prev_arg_types;
7049         cfg->current_method = prev_current_method;
7050         cfg->generic_context = prev_generic_context;
7051         cfg->ret_var_set = prev_ret_var_set;
7052         cfg->disable_inline = prev_disable_inline;
7053         cfg->inline_depth --;
7054
7055         if ((costs >= 0 && costs < 60) || inline_always || (costs >= 0 && (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))) {
7056                 if (cfg->verbose_level > 2)
7057                         printf ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
7058                 
7059                 cfg->stat_inlined_methods++;
7060
7061                 /* always add some code to avoid block split failures */
7062                 MONO_INST_NEW (cfg, ins, OP_NOP);
7063                 MONO_ADD_INS (prev_cbb, ins);
7064
7065                 prev_cbb->next_bb = sbblock;
7066                 link_bblock (cfg, prev_cbb, sbblock);
7067
7068                 /* 
7069                  * Get rid of the begin and end bblocks if possible to aid local
7070                  * optimizations.
7071                  */
7072                 mono_merge_basic_blocks (cfg, prev_cbb, sbblock);
7073
7074                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] != ebblock))
7075                         mono_merge_basic_blocks (cfg, prev_cbb, prev_cbb->out_bb [0]);
7076
7077                 if ((ebblock->in_count == 1) && ebblock->in_bb [0]->out_count == 1) {
7078                         MonoBasicBlock *prev = ebblock->in_bb [0];
7079                         mono_merge_basic_blocks (cfg, prev, ebblock);
7080                         cfg->cbb = prev;
7081                         if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] == prev)) {
7082                                 mono_merge_basic_blocks (cfg, prev_cbb, prev);
7083                                 cfg->cbb = prev_cbb;
7084                         }
7085                 } else {
7086                         /* 
7087                          * Its possible that the rvar is set in some prev bblock, but not in others.
7088                          * (#1835).
7089                          */
7090                         if (rvar) {
7091                                 MonoBasicBlock *bb;
7092
7093                                 for (i = 0; i < ebblock->in_count; ++i) {
7094                                         bb = ebblock->in_bb [i];
7095
7096                                         if (bb->last_ins && bb->last_ins->opcode == OP_NOT_REACHED) {
7097                                                 cfg->cbb = bb;
7098
7099                                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
7100                                         }
7101                                 }
7102                         }
7103
7104                         cfg->cbb = ebblock;
7105                 }
7106
7107                 if (rvar) {
7108                         /*
7109                          * If the inlined method contains only a throw, then the ret var is not 
7110                          * set, so set it to a dummy value.
7111                          */
7112                         if (!ret_var_set)
7113                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
7114
7115                         EMIT_NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
7116                         *sp++ = ins;
7117                 }
7118                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
7119                 return costs + 1;
7120         } else {
7121                 if (cfg->verbose_level > 2)
7122                         printf ("INLINE ABORTED %s (cost %d)\n", mono_method_full_name (cmethod, TRUE), costs);
7123                 cfg->exception_type = MONO_EXCEPTION_NONE;
7124                 mono_loader_clear_error ();
7125
7126                 /* This gets rid of the newly added bblocks */
7127                 cfg->cbb = prev_cbb;
7128         }
7129         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
7130         return 0;
7131 }
7132
7133 /*
7134  * Some of these comments may well be out-of-date.
7135  * Design decisions: we do a single pass over the IL code (and we do bblock 
7136  * splitting/merging in the few cases when it's required: a back jump to an IL
7137  * address that was not already seen as bblock starting point).
7138  * Code is validated as we go (full verification is still better left to metadata/verify.c).
7139  * Complex operations are decomposed in simpler ones right away. We need to let the 
7140  * arch-specific code peek and poke inside this process somehow (except when the 
7141  * optimizations can take advantage of the full semantic info of coarse opcodes).
7142  * All the opcodes of the form opcode.s are 'normalized' to opcode.
7143  * MonoInst->opcode initially is the IL opcode or some simplification of that 
7144  * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific 
7145  * opcode with value bigger than OP_LAST.
7146  * At this point the IR can be handed over to an interpreter, a dumb code generator
7147  * or to the optimizing code generator that will translate it to SSA form.
7148  *
7149  * Profiling directed optimizations.
7150  * We may compile by default with few or no optimizations and instrument the code
7151  * or the user may indicate what methods to optimize the most either in a config file
7152  * or through repeated runs where the compiler applies offline the optimizations to 
7153  * each method and then decides if it was worth it.
7154  */
7155
7156 #define CHECK_TYPE(ins) if (!(ins)->type) UNVERIFIED
7157 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) UNVERIFIED
7158 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) UNVERIFIED
7159 #define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) UNVERIFIED
7160 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
7161 #define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
7162 #define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
7163 #define CHECK_TYPELOAD(klass) if (!(klass) || (klass)->exception_type) TYPE_LOAD_ERROR ((klass))
7164
7165 /* offset from br.s -> br like opcodes */
7166 #define BIG_BRANCH_OFFSET 13
7167
7168 static gboolean
7169 ip_in_bb (MonoCompile *cfg, MonoBasicBlock *bb, const guint8* ip)
7170 {
7171         MonoBasicBlock *b = cfg->cil_offset_to_bb [ip - cfg->cil_start];
7172
7173         return b == NULL || b == bb;
7174 }
7175
7176 static int
7177 get_basic_blocks (MonoCompile *cfg, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
7178 {
7179         unsigned char *ip = start;
7180         unsigned char *target;
7181         int i;
7182         guint cli_addr;
7183         MonoBasicBlock *bblock;
7184         const MonoOpcode *opcode;
7185
7186         while (ip < end) {
7187                 cli_addr = ip - start;
7188                 i = mono_opcode_value ((const guint8 **)&ip, end);
7189                 if (i < 0)
7190                         UNVERIFIED;
7191                 opcode = &mono_opcodes [i];
7192                 switch (opcode->argument) {
7193                 case MonoInlineNone:
7194                         ip++; 
7195                         break;
7196                 case MonoInlineString:
7197                 case MonoInlineType:
7198                 case MonoInlineField:
7199                 case MonoInlineMethod:
7200                 case MonoInlineTok:
7201                 case MonoInlineSig:
7202                 case MonoShortInlineR:
7203                 case MonoInlineI:
7204                         ip += 5;
7205                         break;
7206                 case MonoInlineVar:
7207                         ip += 3;
7208                         break;
7209                 case MonoShortInlineVar:
7210                 case MonoShortInlineI:
7211                         ip += 2;
7212                         break;
7213                 case MonoShortInlineBrTarget:
7214                         target = start + cli_addr + 2 + (signed char)ip [1];
7215                         GET_BBLOCK (cfg, bblock, target);
7216                         ip += 2;
7217                         if (ip < end)
7218                                 GET_BBLOCK (cfg, bblock, ip);
7219                         break;
7220                 case MonoInlineBrTarget:
7221                         target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
7222                         GET_BBLOCK (cfg, bblock, target);
7223                         ip += 5;
7224                         if (ip < end)
7225                                 GET_BBLOCK (cfg, bblock, ip);
7226                         break;
7227                 case MonoInlineSwitch: {
7228                         guint32 n = read32 (ip + 1);
7229                         guint32 j;
7230                         ip += 5;
7231                         cli_addr += 5 + 4 * n;
7232                         target = start + cli_addr;
7233                         GET_BBLOCK (cfg, bblock, target);
7234                         
7235                         for (j = 0; j < n; ++j) {
7236                                 target = start + cli_addr + (gint32)read32 (ip);
7237                                 GET_BBLOCK (cfg, bblock, target);
7238                                 ip += 4;
7239                         }
7240                         break;
7241                 }
7242                 case MonoInlineR:
7243                 case MonoInlineI8:
7244                         ip += 9;
7245                         break;
7246                 default:
7247                         g_assert_not_reached ();
7248                 }
7249
7250                 if (i == CEE_THROW) {
7251                         unsigned char *bb_start = ip - 1;
7252                         
7253                         /* Find the start of the bblock containing the throw */
7254                         bblock = NULL;
7255                         while ((bb_start >= start) && !bblock) {
7256                                 bblock = cfg->cil_offset_to_bb [(bb_start) - start];
7257                                 bb_start --;
7258                         }
7259                         if (bblock)
7260                                 bblock->out_of_line = 1;
7261                 }
7262         }
7263         return 0;
7264 unverified:
7265 exception_exit:
7266         *pos = ip;
7267         return 1;
7268 }
7269
7270 static inline MonoMethod *
7271 mini_get_method_allow_open (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
7272 {
7273         MonoMethod *method;
7274
7275         if (m->wrapper_type != MONO_WRAPPER_NONE) {
7276                 method = mono_method_get_wrapper_data (m, token);
7277                 if (context) {
7278                         MonoError error;
7279                         method = mono_class_inflate_generic_method_checked (method, context, &error);
7280                         g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
7281                 }
7282         } else {
7283                 method = mono_get_method_full (m->klass->image, token, klass, context);
7284         }
7285
7286         return method;
7287 }
7288
7289 static inline MonoMethod *
7290 mini_get_method (MonoCompile *cfg, MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
7291 {
7292         MonoMethod *method = mini_get_method_allow_open (m, token, klass, context);
7293
7294         if (method && cfg && !cfg->gshared && mono_class_is_open_constructed_type (&method->klass->byval_arg))
7295                 return NULL;
7296
7297         return method;
7298 }
7299
7300 static inline MonoClass*
7301 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
7302 {
7303         MonoError error;
7304         MonoClass *klass;
7305
7306         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7307                 klass = mono_method_get_wrapper_data (method, token);
7308                 if (context)
7309                         klass = mono_class_inflate_generic_class (klass, context);
7310         } else {
7311                 klass = mono_class_get_and_inflate_typespec_checked (method->klass->image, token, context, &error);
7312                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
7313         }
7314         if (klass)
7315                 mono_class_init (klass);
7316         return klass;
7317 }
7318
7319 static inline MonoMethodSignature*
7320 mini_get_signature (MonoMethod *method, guint32 token, MonoGenericContext *context)
7321 {
7322         MonoMethodSignature *fsig;
7323
7324         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7325                 fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
7326         } else {
7327                 fsig = mono_metadata_parse_signature (method->klass->image, token);
7328         }
7329         if (context) {
7330                 MonoError error;
7331                 fsig = mono_inflate_generic_signature(fsig, context, &error);
7332                 // FIXME:
7333                 g_assert(mono_error_ok(&error));
7334         }
7335         return fsig;
7336 }
7337
7338 static MonoMethod*
7339 throw_exception (void)
7340 {
7341         static MonoMethod *method = NULL;
7342
7343         if (!method) {
7344                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
7345                 method = mono_class_get_method_from_name (secman->securitymanager, "ThrowException", 1);
7346         }
7347         g_assert (method);
7348         return method;
7349 }
7350
7351 static void
7352 emit_throw_exception (MonoCompile *cfg, MonoException *ex)
7353 {
7354         MonoMethod *thrower = throw_exception ();
7355         MonoInst *args [1];
7356
7357         EMIT_NEW_PCONST (cfg, args [0], ex);
7358         mono_emit_method_call (cfg, thrower, args, NULL);
7359 }
7360
7361 /*
7362  * Return the original method is a wrapper is specified. We can only access 
7363  * the custom attributes from the original method.
7364  */
7365 static MonoMethod*
7366 get_original_method (MonoMethod *method)
7367 {
7368         if (method->wrapper_type == MONO_WRAPPER_NONE)
7369                 return method;
7370
7371         /* native code (which is like Critical) can call any managed method XXX FIXME XXX to validate all usages */
7372         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)
7373                 return NULL;
7374
7375         /* in other cases we need to find the original method */
7376         return mono_marshal_method_from_wrapper (method);
7377 }
7378
7379 static void
7380 ensure_method_is_allowed_to_access_field (MonoCompile *cfg, MonoMethod *caller, MonoClassField *field)
7381 {
7382         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
7383         MonoException *ex = mono_security_core_clr_is_field_access_allowed (get_original_method (caller), field);
7384         if (ex)
7385                 emit_throw_exception (cfg, ex);
7386 }
7387
7388 static void
7389 ensure_method_is_allowed_to_call_method (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee)
7390 {
7391         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
7392         MonoException *ex = mono_security_core_clr_is_call_allowed (get_original_method (caller), callee);
7393         if (ex)
7394                 emit_throw_exception (cfg, ex);
7395 }
7396
7397 /*
7398  * Check that the IL instructions at ip are the array initialization
7399  * sequence and return the pointer to the data and the size.
7400  */
7401 static const char*
7402 initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, MonoClass *klass, guint32 len, int *out_size, guint32 *out_field_token)
7403 {
7404         /*
7405          * newarr[System.Int32]
7406          * dup
7407          * ldtoken field valuetype ...
7408          * call void class [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle)
7409          */
7410         if (ip [0] == CEE_DUP && ip [1] == CEE_LDTOKEN && ip [5] == 0x4 && ip [6] == CEE_CALL) {
7411                 MonoError error;
7412                 guint32 token = read32 (ip + 7);
7413                 guint32 field_token = read32 (ip + 2);
7414                 guint32 field_index = field_token & 0xffffff;
7415                 guint32 rva;
7416                 const char *data_ptr;
7417                 int size = 0;
7418                 MonoMethod *cmethod;
7419                 MonoClass *dummy_class;
7420                 MonoClassField *field = mono_field_from_token_checked (method->klass->image, field_token, &dummy_class, NULL, &error);
7421                 int dummy_align;
7422
7423                 if (!field) {
7424                         mono_error_cleanup (&error); /* FIXME don't swallow the error */
7425                         return NULL;
7426                 }
7427
7428                 *out_field_token = field_token;
7429
7430                 cmethod = mini_get_method (NULL, method, token, NULL, NULL);
7431                 if (!cmethod)
7432                         return NULL;
7433                 if (strcmp (cmethod->name, "InitializeArray") || strcmp (cmethod->klass->name, "RuntimeHelpers") || cmethod->klass->image != mono_defaults.corlib)
7434                         return NULL;
7435                 switch (mono_type_get_underlying_type (&klass->byval_arg)->type) {
7436                 case MONO_TYPE_BOOLEAN:
7437                 case MONO_TYPE_I1:
7438                 case MONO_TYPE_U1:
7439                         size = 1; break;
7440                 /* we need to swap on big endian, so punt. Should we handle R4 and R8 as well? */
7441 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
7442                 case MONO_TYPE_CHAR:
7443                 case MONO_TYPE_I2:
7444                 case MONO_TYPE_U2:
7445                         size = 2; break;
7446                 case MONO_TYPE_I4:
7447                 case MONO_TYPE_U4:
7448                 case MONO_TYPE_R4:
7449                         size = 4; break;
7450                 case MONO_TYPE_R8:
7451                 case MONO_TYPE_I8:
7452                 case MONO_TYPE_U8:
7453                         size = 8; break;
7454 #endif
7455                 default:
7456                         return NULL;
7457                 }
7458                 size *= len;
7459                 if (size > mono_type_size (field->type, &dummy_align))
7460                     return NULL;
7461                 *out_size = size;
7462                 /*g_print ("optimized in %s: size: %d, numelems: %d\n", method->name, size, newarr->inst_newa_len->inst_c0);*/
7463                 if (!image_is_dynamic (method->klass->image)) {
7464                         field_index = read32 (ip + 2) & 0xffffff;
7465                         mono_metadata_field_info (method->klass->image, field_index - 1, NULL, &rva, NULL);
7466                         data_ptr = mono_image_rva_map (method->klass->image, rva);
7467                         /*g_print ("field: 0x%08x, rva: %d, rva_ptr: %p\n", read32 (ip + 2), rva, data_ptr);*/
7468                         /* for aot code we do the lookup on load */
7469                         if (aot && data_ptr)
7470                                 return GUINT_TO_POINTER (rva);
7471                 } else {
7472                         /*FIXME is it possible to AOT a SRE assembly not meant to be saved? */ 
7473                         g_assert (!aot);
7474                         data_ptr = mono_field_get_data (field);
7475                 }
7476                 return data_ptr;
7477         }
7478         return NULL;
7479 }
7480
7481 static void
7482 set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsigned char *ip)
7483 {
7484         char *method_fname = mono_method_full_name (method, TRUE);
7485         char *method_code;
7486         MonoMethodHeader *header = mono_method_get_header (method);
7487
7488         if (header->code_size == 0)
7489                 method_code = g_strdup ("method body is empty.");
7490         else
7491                 method_code = mono_disasm_code_one (NULL, method, ip, NULL);
7492         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
7493         cfg->exception_message = g_strdup_printf ("Invalid IL code in %s: %s\n", method_fname, method_code);
7494         g_free (method_fname);
7495         g_free (method_code);
7496         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
7497 }
7498
7499 static void
7500 set_exception_object (MonoCompile *cfg, MonoException *exception)
7501 {
7502         mono_cfg_set_exception (cfg, MONO_EXCEPTION_OBJECT_SUPPLIED);
7503         MONO_GC_REGISTER_ROOT_SINGLE (cfg->exception_ptr, MONO_ROOT_SOURCE_JIT, "jit exception");
7504         cfg->exception_ptr = exception;
7505 }
7506
7507 static void
7508 emit_stloc_ir (MonoCompile *cfg, MonoInst **sp, MonoMethodHeader *header, int n)
7509 {
7510         MonoInst *ins;
7511         guint32 opcode = mono_type_to_regmove (cfg, header->locals [n]);
7512         if ((opcode == OP_MOVE) && cfg->cbb->last_ins == sp [0]  &&
7513                         ((sp [0]->opcode == OP_ICONST) || (sp [0]->opcode == OP_I8CONST))) {
7514                 /* Optimize reg-reg moves away */
7515                 /* 
7516                  * Can't optimize other opcodes, since sp[0] might point to
7517                  * the last ins of a decomposed opcode.
7518                  */
7519                 sp [0]->dreg = (cfg)->locals [n]->dreg;
7520         } else {
7521                 EMIT_NEW_LOCSTORE (cfg, ins, n, *sp);
7522         }
7523 }
7524
7525 /*
7526  * ldloca inhibits many optimizations so try to get rid of it in common
7527  * cases.
7528  */
7529 static inline unsigned char *
7530 emit_optimized_ldloca_ir (MonoCompile *cfg, unsigned char *ip, unsigned char *end, int size)
7531 {
7532         int local, token;
7533         MonoClass *klass;
7534         MonoType *type;
7535
7536         if (size == 1) {
7537                 local = ip [1];
7538                 ip += 2;
7539         } else {
7540                 local = read16 (ip + 2);
7541                 ip += 4;
7542         }
7543         
7544         if (ip + 6 < end && (ip [0] == CEE_PREFIX1) && (ip [1] == CEE_INITOBJ) && ip_in_bb (cfg, cfg->cbb, ip + 1)) {
7545                 /* From the INITOBJ case */
7546                 token = read32 (ip + 2);
7547                 klass = mini_get_class (cfg->current_method, token, cfg->generic_context);
7548                 CHECK_TYPELOAD (klass);
7549                 type = mini_get_underlying_type (&klass->byval_arg);
7550                 emit_init_local (cfg, local, type, TRUE);
7551                 return ip + 6;
7552         }
7553  exception_exit:
7554         return NULL;
7555 }
7556
7557 static gboolean
7558 is_exception_class (MonoClass *klass)
7559 {
7560         while (klass) {
7561                 if (klass == mono_defaults.exception_class)
7562                         return TRUE;
7563                 klass = klass->parent;
7564         }
7565         return FALSE;
7566 }
7567
7568 /*
7569  * is_jit_optimizer_disabled:
7570  *
7571  *   Determine whenever M's assembly has a DebuggableAttribute with the
7572  * IsJITOptimizerDisabled flag set.
7573  */
7574 static gboolean
7575 is_jit_optimizer_disabled (MonoMethod *m)
7576 {
7577         MonoAssembly *ass = m->klass->image->assembly;
7578         MonoCustomAttrInfo* attrs;
7579         static MonoClass *klass;
7580         int i;
7581         gboolean val = FALSE;
7582
7583         g_assert (ass);
7584         if (ass->jit_optimizer_disabled_inited)
7585                 return ass->jit_optimizer_disabled;
7586
7587         if (!klass)
7588                 klass = mono_class_from_name (mono_defaults.corlib, "System.Diagnostics", "DebuggableAttribute");
7589         if (!klass) {
7590                 /* Linked away */
7591                 ass->jit_optimizer_disabled = FALSE;
7592                 mono_memory_barrier ();
7593                 ass->jit_optimizer_disabled_inited = TRUE;
7594                 return FALSE;
7595         }
7596
7597         attrs = mono_custom_attrs_from_assembly (ass);
7598         if (attrs) {
7599                 for (i = 0; i < attrs->num_attrs; ++i) {
7600                         MonoCustomAttrEntry *attr = &attrs->attrs [i];
7601                         const gchar *p;
7602                         MonoMethodSignature *sig;
7603
7604                         if (!attr->ctor || attr->ctor->klass != klass)
7605                                 continue;
7606                         /* Decode the attribute. See reflection.c */
7607                         p = (const char*)attr->data;
7608                         g_assert (read16 (p) == 0x0001);
7609                         p += 2;
7610
7611                         // FIXME: Support named parameters
7612                         sig = mono_method_signature (attr->ctor);
7613                         if (sig->param_count != 2 || sig->params [0]->type != MONO_TYPE_BOOLEAN || sig->params [1]->type != MONO_TYPE_BOOLEAN)
7614                                 continue;
7615                         /* Two boolean arguments */
7616                         p ++;
7617                         val = *p;
7618                 }
7619                 mono_custom_attrs_free (attrs);
7620         }
7621
7622         ass->jit_optimizer_disabled = val;
7623         mono_memory_barrier ();
7624         ass->jit_optimizer_disabled_inited = TRUE;
7625
7626         return val;
7627 }
7628
7629 static gboolean
7630 is_supported_tail_call (MonoCompile *cfg, MonoMethod *method, MonoMethod *cmethod, MonoMethodSignature *fsig, int call_opcode)
7631 {
7632         gboolean supported_tail_call;
7633         int i;
7634
7635         supported_tail_call = mono_arch_tail_call_supported (cfg, mono_method_signature (method), mono_method_signature (cmethod));
7636
7637         for (i = 0; i < fsig->param_count; ++i) {
7638                 if (fsig->params [i]->byref || fsig->params [i]->type == MONO_TYPE_PTR || fsig->params [i]->type == MONO_TYPE_FNPTR)
7639                         /* These can point to the current method's stack */
7640                         supported_tail_call = FALSE;
7641         }
7642         if (fsig->hasthis && cmethod->klass->valuetype)
7643                 /* this might point to the current method's stack */
7644                 supported_tail_call = FALSE;
7645         if (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
7646                 supported_tail_call = FALSE;
7647         if (cfg->method->save_lmf)
7648                 supported_tail_call = FALSE;
7649         if (cmethod->wrapper_type && cmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD)
7650                 supported_tail_call = FALSE;
7651         if (call_opcode != CEE_CALL)
7652                 supported_tail_call = FALSE;
7653
7654         /* Debugging support */
7655 #if 0
7656         if (supported_tail_call) {
7657                 if (!mono_debug_count ())
7658                         supported_tail_call = FALSE;
7659         }
7660 #endif
7661
7662         return supported_tail_call;
7663 }
7664
7665 /*
7666  * handle_ctor_call:
7667  *
7668  *   Handle calls made to ctors from NEWOBJ opcodes.
7669  */
7670 static void
7671 handle_ctor_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used,
7672                                   MonoInst **sp, guint8 *ip, int *inline_costs)
7673 {
7674         MonoInst *vtable_arg = NULL, *callvirt_this_arg = NULL, *ins;
7675
7676         if (cmethod->klass->valuetype && mono_class_generic_sharing_enabled (cmethod->klass) &&
7677                                         mono_method_is_generic_sharable (cmethod, TRUE)) {
7678                 if (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst) {
7679                         mono_class_vtable (cfg->domain, cmethod->klass);
7680                         CHECK_TYPELOAD (cmethod->klass);
7681
7682                         vtable_arg = emit_get_rgctx_method (cfg, context_used,
7683                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
7684                 } else {
7685                         if (context_used) {
7686                                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
7687                                                                                                    cmethod->klass, MONO_RGCTX_INFO_VTABLE);
7688                         } else {
7689                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
7690
7691                                 CHECK_TYPELOAD (cmethod->klass);
7692                                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
7693                         }
7694                 }
7695         }
7696
7697         /* Avoid virtual calls to ctors if possible */
7698         if (mono_class_is_marshalbyref (cmethod->klass))
7699                 callvirt_this_arg = sp [0];
7700
7701         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_ctor (cfg, cmethod, fsig, sp))) {
7702                 g_assert (MONO_TYPE_IS_VOID (fsig->ret));
7703                 CHECK_CFG_EXCEPTION;
7704         } else if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used && !vtable_arg &&
7705                            mono_method_check_inlining (cfg, cmethod) &&
7706                            !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE)) {
7707                 int costs;
7708
7709                 if ((costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, FALSE))) {
7710                         cfg->real_offset += 5;
7711
7712                         *inline_costs += costs - 5;
7713                 } else {
7714                         INLINE_FAILURE ("inline failure");
7715                         // FIXME-VT: Clean this up
7716                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))
7717                                 GSHAREDVT_FAILURE(*ip);
7718                         mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, callvirt_this_arg, NULL, NULL);
7719                 }
7720         } else if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
7721                 MonoInst *addr;
7722
7723                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE);
7724                 mono_emit_calli (cfg, fsig, sp, addr, NULL, vtable_arg);
7725         } else if (context_used &&
7726                            ((!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
7727                                  !mono_class_generic_sharing_enabled (cmethod->klass)) || cfg->gsharedvt)) {
7728                 MonoInst *cmethod_addr;
7729
7730                 /* Generic calls made out of gsharedvt methods cannot be patched, so use an indirect call */
7731
7732                 cmethod_addr = emit_get_rgctx_method (cfg, context_used,
7733                                                                                           cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
7734
7735                 mono_emit_calli (cfg, fsig, sp, cmethod_addr, NULL, vtable_arg);
7736         } else {
7737                 INLINE_FAILURE ("ctor call");
7738                 ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp,
7739                                                                                   callvirt_this_arg, NULL, vtable_arg);
7740         }
7741  exception_exit:
7742         return;
7743 }
7744
7745 static void
7746 emit_setret (MonoCompile *cfg, MonoInst *val)
7747 {
7748         MonoType *ret_type = mini_get_underlying_type (mono_method_signature (cfg->method)->ret);
7749         MonoInst *ins;
7750
7751         if (mini_type_to_stind (cfg, ret_type) == CEE_STOBJ) {
7752                 MonoInst *ret_addr;
7753
7754                 if (!cfg->vret_addr) {
7755                         EMIT_NEW_VARSTORE (cfg, ins, cfg->ret, ret_type, val);
7756                 } else {
7757                         EMIT_NEW_RETLOADA (cfg, ret_addr);
7758
7759                         EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STOREV_MEMBASE, ret_addr->dreg, 0, val->dreg);
7760                         ins->klass = mono_class_from_mono_type (ret_type);
7761                 }
7762         } else {
7763 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
7764                 if (COMPILE_SOFT_FLOAT (cfg) && !ret_type->byref && ret_type->type == MONO_TYPE_R4) {
7765                         MonoInst *iargs [1];
7766                         MonoInst *conv;
7767
7768                         iargs [0] = val;
7769                         conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
7770                         mono_arch_emit_setret (cfg, cfg->method, conv);
7771                 } else {
7772                         mono_arch_emit_setret (cfg, cfg->method, val);
7773                 }
7774 #else
7775                 mono_arch_emit_setret (cfg, cfg->method, val);
7776 #endif
7777         }
7778 }
7779
7780 static MonoMethodSignature*
7781 sig_to_rgctx_sig (MonoMethodSignature *sig)
7782 {
7783         // FIXME: memory allocation
7784         MonoMethodSignature *res;
7785         int i;
7786
7787         res = g_malloc (MONO_SIZEOF_METHOD_SIGNATURE + (sig->param_count + 1) * sizeof (MonoType*));
7788         memcpy (res, sig, MONO_SIZEOF_METHOD_SIGNATURE);
7789         res->param_count = sig->param_count + 1;
7790         for (i = 0; i < sig->param_count; ++i)
7791                 res->params [i] = sig->params [i];
7792         res->params [sig->param_count] = &mono_defaults.int_class->byval_arg;
7793         return res;
7794 }
7795
7796 /*
7797  * mono_method_to_ir:
7798  *
7799  *   Translate the .net IL into linear IR.
7800  */
7801 int
7802 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
7803                    MonoInst *return_var, MonoInst **inline_args, 
7804                    guint inline_offset, gboolean is_virtual_call)
7805 {
7806         MonoError error;
7807         MonoInst *ins, **sp, **stack_start;
7808         MonoBasicBlock *tblock = NULL, *init_localsbb = NULL;
7809         MonoSimpleBasicBlock *bb = NULL, *original_bb = NULL;
7810         MonoMethod *cmethod, *method_definition;
7811         MonoInst **arg_array;
7812         MonoMethodHeader *header;
7813         MonoImage *image;
7814         guint32 token, ins_flag;
7815         MonoClass *klass;
7816         MonoClass *constrained_class = NULL;
7817         unsigned char *ip, *end, *target, *err_pos;
7818         MonoMethodSignature *sig;
7819         MonoGenericContext *generic_context = NULL;
7820         MonoGenericContainer *generic_container = NULL;
7821         MonoType **param_types;
7822         int i, n, start_new_bblock, dreg;
7823         int num_calls = 0, inline_costs = 0;
7824         int breakpoint_id = 0;
7825         guint num_args;
7826         GSList *class_inits = NULL;
7827         gboolean dont_verify, dont_verify_stloc, readonly = FALSE;
7828         int context_used;
7829         gboolean init_locals, seq_points, skip_dead_blocks;
7830         gboolean sym_seq_points = FALSE;
7831         MonoDebugMethodInfo *minfo;
7832         MonoBitSet *seq_point_locs = NULL;
7833         MonoBitSet *seq_point_set_locs = NULL;
7834
7835         cfg->disable_inline = is_jit_optimizer_disabled (method);
7836
7837         /* serialization and xdomain stuff may need access to private fields and methods */
7838         dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
7839         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE;
7840         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH;
7841         dont_verify |= method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; /* bug #77896 */
7842         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP;
7843         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP_INVOKE;
7844
7845         /* still some type unsafety issues in marshal wrappers... (unknown is PtrToStructure) */
7846         dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE;
7847         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_UNKNOWN;
7848         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED;
7849         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_STELEMREF;
7850
7851         image = method->klass->image;
7852         header = mono_method_get_header (method);
7853         if (!header) {
7854                 MonoLoaderError *error;
7855
7856                 if ((error = mono_loader_get_last_error ())) {
7857                         mono_cfg_set_exception (cfg, error->exception_type);
7858                 } else {
7859                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
7860                         cfg->exception_message = g_strdup_printf ("Missing or incorrect header for method %s", cfg->method->name);
7861                 }
7862                 goto exception_exit;
7863         }
7864         generic_container = mono_method_get_generic_container (method);
7865         sig = mono_method_signature (method);
7866         num_args = sig->hasthis + sig->param_count;
7867         ip = (unsigned char*)header->code;
7868         cfg->cil_start = ip;
7869         end = ip + header->code_size;
7870         cfg->stat_cil_code_size += header->code_size;
7871
7872         seq_points = cfg->gen_seq_points && cfg->method == method;
7873
7874         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
7875                 /* We could hit a seq point before attaching to the JIT (#8338) */
7876                 seq_points = FALSE;
7877         }
7878
7879         if (cfg->gen_sdb_seq_points && cfg->method == method) {
7880                 minfo = mono_debug_lookup_method (method);
7881                 if (minfo) {
7882                         MonoSymSeqPoint *sps;
7883                         int i, n_il_offsets;
7884
7885                         mono_debug_get_seq_points (minfo, NULL, NULL, NULL, &sps, &n_il_offsets);
7886                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
7887                         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);
7888                         sym_seq_points = TRUE;
7889                         for (i = 0; i < n_il_offsets; ++i) {
7890                                 if (sps [i].il_offset < header->code_size)
7891                                         mono_bitset_set_fast (seq_point_locs, sps [i].il_offset);
7892                         }
7893                         g_free (sps);
7894                 } else if (!method->wrapper_type && !method->dynamic && mono_debug_image_has_debug_info (method->klass->image)) {
7895                         /* Methods without line number info like auto-generated property accessors */
7896                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
7897                         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);
7898                         sym_seq_points = TRUE;
7899                 }
7900         }
7901
7902         /* 
7903          * Methods without init_locals set could cause asserts in various passes
7904          * (#497220). To work around this, we emit dummy initialization opcodes
7905          * (OP_DUMMY_ICONST etc.) which generate no code. These are only supported
7906          * on some platforms.
7907          */
7908         if ((cfg->opt & MONO_OPT_UNSAFE) && cfg->backend->have_dummy_init)
7909                 init_locals = header->init_locals;
7910         else
7911                 init_locals = TRUE;
7912
7913         method_definition = method;
7914         while (method_definition->is_inflated) {
7915                 MonoMethodInflated *imethod = (MonoMethodInflated *) method_definition;
7916                 method_definition = imethod->declaring;
7917         }
7918
7919         /* SkipVerification is not allowed if core-clr is enabled */
7920         if (!dont_verify && mini_assembly_can_skip_verification (cfg->domain, method)) {
7921                 dont_verify = TRUE;
7922                 dont_verify_stloc = TRUE;
7923         }
7924
7925         if (sig->is_inflated)
7926                 generic_context = mono_method_get_context (method);
7927         else if (generic_container)
7928                 generic_context = &generic_container->context;
7929         cfg->generic_context = generic_context;
7930
7931         if (!cfg->gshared)
7932                 g_assert (!sig->has_type_parameters);
7933
7934         if (sig->generic_param_count && method->wrapper_type == MONO_WRAPPER_NONE) {
7935                 g_assert (method->is_inflated);
7936                 g_assert (mono_method_get_context (method)->method_inst);
7937         }
7938         if (method->is_inflated && mono_method_get_context (method)->method_inst)
7939                 g_assert (sig->generic_param_count);
7940
7941         if (cfg->method == method) {
7942                 cfg->real_offset = 0;
7943         } else {
7944                 cfg->real_offset = inline_offset;
7945         }
7946
7947         cfg->cil_offset_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoBasicBlock*) * header->code_size);
7948         cfg->cil_offset_to_bb_len = header->code_size;
7949
7950         cfg->current_method = method;
7951
7952         if (cfg->verbose_level > 2)
7953                 printf ("method to IR %s\n", mono_method_full_name (method, TRUE));
7954
7955         param_types = mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * num_args);
7956         if (sig->hasthis)
7957                 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
7958         for (n = 0; n < sig->param_count; ++n)
7959                 param_types [n + sig->hasthis] = sig->params [n];
7960         cfg->arg_types = param_types;
7961
7962         cfg->dont_inline = g_list_prepend (cfg->dont_inline, method);
7963         if (cfg->method == method) {
7964
7965                 if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
7966                         cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
7967
7968                 /* ENTRY BLOCK */
7969                 NEW_BBLOCK (cfg, start_bblock);
7970                 cfg->bb_entry = start_bblock;
7971                 start_bblock->cil_code = NULL;
7972                 start_bblock->cil_length = 0;
7973
7974                 /* EXIT BLOCK */
7975                 NEW_BBLOCK (cfg, end_bblock);
7976                 cfg->bb_exit = end_bblock;
7977                 end_bblock->cil_code = NULL;
7978                 end_bblock->cil_length = 0;
7979                 end_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
7980                 g_assert (cfg->num_bblocks == 2);
7981
7982                 arg_array = cfg->args;
7983
7984                 if (header->num_clauses) {
7985                         cfg->spvars = g_hash_table_new (NULL, NULL);
7986                         cfg->exvars = g_hash_table_new (NULL, NULL);
7987                 }
7988                 /* handle exception clauses */
7989                 for (i = 0; i < header->num_clauses; ++i) {
7990                         MonoBasicBlock *try_bb;
7991                         MonoExceptionClause *clause = &header->clauses [i];
7992                         GET_BBLOCK (cfg, try_bb, ip + clause->try_offset);
7993
7994                         try_bb->real_offset = clause->try_offset;
7995                         try_bb->try_start = TRUE;
7996                         try_bb->region = ((i + 1) << 8) | clause->flags;
7997                         GET_BBLOCK (cfg, tblock, ip + clause->handler_offset);
7998                         tblock->real_offset = clause->handler_offset;
7999                         tblock->flags |= BB_EXCEPTION_HANDLER;
8000
8001                         /*
8002                          * Linking the try block with the EH block hinders inlining as we won't be able to 
8003                          * merge the bblocks from inlining and produce an artificial hole for no good reason.
8004                          */
8005                         if (COMPILE_LLVM (cfg))
8006                                 link_bblock (cfg, try_bb, tblock);
8007
8008                         if (*(ip + clause->handler_offset) == CEE_POP)
8009                                 tblock->flags |= BB_EXCEPTION_DEAD_OBJ;
8010
8011                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
8012                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER ||
8013                             clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
8014                                 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
8015                                 MONO_ADD_INS (tblock, ins);
8016
8017                                 if (seq_points && clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY && clause->flags != MONO_EXCEPTION_CLAUSE_FILTER) {
8018                                         /* finally clauses already have a seq point */
8019                                         /* seq points for filter clauses are emitted below */
8020                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
8021                                         MONO_ADD_INS (tblock, ins);
8022                                 }
8023
8024                                 /* todo: is a fault block unsafe to optimize? */
8025                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
8026                                         tblock->flags |= BB_EXCEPTION_UNSAFE;
8027                         }
8028
8029                         /*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);
8030                           while (p < end) {
8031                           printf ("%s", mono_disasm_code_one (NULL, method, p, &p));
8032                           }*/
8033                         /* catch and filter blocks get the exception object on the stack */
8034                         if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
8035                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
8036
8037                                 /* mostly like handle_stack_args (), but just sets the input args */
8038                                 /* printf ("handling clause at IL_%04x\n", clause->handler_offset); */
8039                                 tblock->in_scount = 1;
8040                                 tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
8041                                 tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
8042
8043                                 cfg->cbb = tblock;
8044
8045 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
8046                                 /* The EH code passes in the exception in a register to both JITted and LLVM compiled code */
8047                                 if (!cfg->compile_llvm) {
8048                                         MONO_INST_NEW (cfg, ins, OP_GET_EX_OBJ);
8049                                         ins->dreg = tblock->in_stack [0]->dreg;
8050                                         MONO_ADD_INS (tblock, ins);
8051                                 }
8052 #else
8053                                 MonoInst *dummy_use;
8054
8055                                 /* 
8056                                  * Add a dummy use for the exvar so its liveness info will be
8057                                  * correct.
8058                                  */
8059                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, tblock->in_stack [0]);
8060 #endif
8061
8062                                 if (seq_points && clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
8063                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
8064                                         MONO_ADD_INS (tblock, ins);
8065                                 }
8066                                 
8067                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
8068                                         GET_BBLOCK (cfg, tblock, ip + clause->data.filter_offset);
8069                                         tblock->flags |= BB_EXCEPTION_HANDLER;
8070                                         tblock->real_offset = clause->data.filter_offset;
8071                                         tblock->in_scount = 1;
8072                                         tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
8073                                         /* The filter block shares the exvar with the handler block */
8074                                         tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
8075                                         MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
8076                                         MONO_ADD_INS (tblock, ins);
8077                                 }
8078                         }
8079
8080                         if (clause->flags != MONO_EXCEPTION_CLAUSE_FILTER &&
8081                                         clause->data.catch_class &&
8082                                         cfg->gshared &&
8083                                         mono_class_check_context_used (clause->data.catch_class)) {
8084                                 /*
8085                                  * In shared generic code with catch
8086                                  * clauses containing type variables
8087                                  * the exception handling code has to
8088                                  * be able to get to the rgctx.
8089                                  * Therefore we have to make sure that
8090                                  * the vtable/mrgctx argument (for
8091                                  * static or generic methods) or the
8092                                  * "this" argument (for non-static
8093                                  * methods) are live.
8094                                  */
8095                                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
8096                                                 mini_method_get_context (method)->method_inst ||
8097                                                 method->klass->valuetype) {
8098                                         mono_get_vtable_var (cfg);
8099                                 } else {
8100                                         MonoInst *dummy_use;
8101
8102                                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, arg_array [0]);
8103                                 }
8104                         }
8105                 }
8106         } else {
8107                 arg_array = (MonoInst **) alloca (sizeof (MonoInst *) * num_args);
8108                 cfg->cbb = start_bblock;
8109                 cfg->args = arg_array;
8110                 mono_save_args (cfg, sig, inline_args);
8111         }
8112
8113         /* FIRST CODE BLOCK */
8114         NEW_BBLOCK (cfg, tblock);
8115         tblock->cil_code = ip;
8116         cfg->cbb = tblock;
8117         cfg->ip = ip;
8118
8119         ADD_BBLOCK (cfg, tblock);
8120
8121         if (cfg->method == method) {
8122                 breakpoint_id = mono_debugger_method_has_breakpoint (method);
8123                 if (breakpoint_id) {
8124                         MONO_INST_NEW (cfg, ins, OP_BREAK);
8125                         MONO_ADD_INS (cfg->cbb, ins);
8126                 }
8127         }
8128
8129         /* we use a separate basic block for the initialization code */
8130         NEW_BBLOCK (cfg, init_localsbb);
8131         cfg->bb_init = init_localsbb;
8132         init_localsbb->real_offset = cfg->real_offset;
8133         start_bblock->next_bb = init_localsbb;
8134         init_localsbb->next_bb = cfg->cbb;
8135         link_bblock (cfg, start_bblock, init_localsbb);
8136         link_bblock (cfg, init_localsbb, cfg->cbb);
8137                 
8138         cfg->cbb = init_localsbb;
8139
8140         if (cfg->gsharedvt && cfg->method == method) {
8141                 MonoGSharedVtMethodInfo *info;
8142                 MonoInst *var, *locals_var;
8143                 int dreg;
8144
8145                 info = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoGSharedVtMethodInfo));
8146                 info->method = cfg->method;
8147                 info->count_entries = 16;
8148                 info->entries = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
8149                 cfg->gsharedvt_info = info;
8150
8151                 var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8152                 /* prevent it from being register allocated */
8153                 //var->flags |= MONO_INST_VOLATILE;
8154                 cfg->gsharedvt_info_var = var;
8155
8156                 ins = emit_get_rgctx_gsharedvt_method (cfg, mini_method_check_context_used (cfg, method), method, info);
8157                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, var->dreg, ins->dreg);
8158
8159                 /* Allocate locals */
8160                 locals_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8161                 /* prevent it from being register allocated */
8162                 //locals_var->flags |= MONO_INST_VOLATILE;
8163                 cfg->gsharedvt_locals_var = locals_var;
8164
8165                 dreg = alloc_ireg (cfg);
8166                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, dreg, var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, locals_size));
8167
8168                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
8169                 ins->dreg = locals_var->dreg;
8170                 ins->sreg1 = dreg;
8171                 MONO_ADD_INS (cfg->cbb, ins);
8172                 cfg->gsharedvt_locals_var_ins = ins;
8173                 
8174                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
8175                 /*
8176                 if (init_locals)
8177                         ins->flags |= MONO_INST_INIT;
8178                 */
8179         }
8180
8181         if (mono_security_core_clr_enabled ()) {
8182                 /* check if this is native code, e.g. an icall or a p/invoke */
8183                 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
8184                         MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
8185                         if (wrapped) {
8186                                 gboolean pinvk = (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL);
8187                                 gboolean icall = (wrapped->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL);
8188
8189                                 /* if this ia a native call then it can only be JITted from platform code */
8190                                 if ((icall || pinvk) && method->klass && method->klass->image) {
8191                                         if (!mono_security_core_clr_is_platform_image (method->klass->image)) {
8192                                                 MonoException *ex = icall ? mono_get_exception_security () : 
8193                                                         mono_get_exception_method_access ();
8194                                                 emit_throw_exception (cfg, ex);
8195                                         }
8196                                 }
8197                         }
8198                 }
8199         }
8200
8201         CHECK_CFG_EXCEPTION;
8202
8203         if (header->code_size == 0)
8204                 UNVERIFIED;
8205
8206         if (get_basic_blocks (cfg, header, cfg->real_offset, ip, end, &err_pos)) {
8207                 ip = err_pos;
8208                 UNVERIFIED;
8209         }
8210
8211         if (cfg->method == method)
8212                 mono_debug_init_method (cfg, cfg->cbb, breakpoint_id);
8213
8214         for (n = 0; n < header->num_locals; ++n) {
8215                 if (header->locals [n]->type == MONO_TYPE_VOID && !header->locals [n]->byref)
8216                         UNVERIFIED;
8217         }
8218         class_inits = NULL;
8219
8220         /* We force the vtable variable here for all shared methods
8221            for the possibility that they might show up in a stack
8222            trace where their exact instantiation is needed. */
8223         if (cfg->gshared && method == cfg->method) {
8224                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
8225                                 mini_method_get_context (method)->method_inst ||
8226                                 method->klass->valuetype) {
8227                         mono_get_vtable_var (cfg);
8228                 } else {
8229                         /* FIXME: Is there a better way to do this?
8230                            We need the variable live for the duration
8231                            of the whole method. */
8232                         cfg->args [0]->flags |= MONO_INST_VOLATILE;
8233                 }
8234         }
8235
8236         /* add a check for this != NULL to inlined methods */
8237         if (is_virtual_call) {
8238                 MonoInst *arg_ins;
8239
8240                 NEW_ARGLOAD (cfg, arg_ins, 0);
8241                 MONO_ADD_INS (cfg->cbb, arg_ins);
8242                 MONO_EMIT_NEW_CHECK_THIS (cfg, arg_ins->dreg);
8243         }
8244
8245         skip_dead_blocks = !dont_verify;
8246         if (skip_dead_blocks) {
8247                 original_bb = bb = mono_basic_block_split (method, &cfg->error);
8248                 CHECK_CFG_ERROR;
8249                 g_assert (bb);
8250         }
8251
8252         /* we use a spare stack slot in SWITCH and NEWOBJ and others */
8253         stack_start = sp = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
8254
8255         ins_flag = 0;
8256         start_new_bblock = 0;
8257         while (ip < end) {
8258                 if (cfg->method == method)
8259                         cfg->real_offset = ip - header->code;
8260                 else
8261                         cfg->real_offset = inline_offset;
8262                 cfg->ip = ip;
8263
8264                 context_used = 0;
8265
8266                 if (start_new_bblock) {
8267                         cfg->cbb->cil_length = ip - cfg->cbb->cil_code;
8268                         if (start_new_bblock == 2) {
8269                                 g_assert (ip == tblock->cil_code);
8270                         } else {
8271                                 GET_BBLOCK (cfg, tblock, ip);
8272                         }
8273                         cfg->cbb->next_bb = tblock;
8274                         cfg->cbb = tblock;
8275                         start_new_bblock = 0;
8276                         for (i = 0; i < cfg->cbb->in_scount; ++i) {
8277                                 if (cfg->verbose_level > 3)
8278                                         printf ("loading %d from temp %d\n", i, (int)cfg->cbb->in_stack [i]->inst_c0);
8279                                 EMIT_NEW_TEMPLOAD (cfg, ins, cfg->cbb->in_stack [i]->inst_c0);
8280                                 *sp++ = ins;
8281                         }
8282                         if (class_inits)
8283                                 g_slist_free (class_inits);
8284                         class_inits = NULL;
8285                 } else {
8286                         if ((tblock = cfg->cil_offset_to_bb [ip - cfg->cil_start]) && (tblock != cfg->cbb)) {
8287                                 link_bblock (cfg, cfg->cbb, tblock);
8288                                 if (sp != stack_start) {
8289                                         handle_stack_args (cfg, stack_start, sp - stack_start);
8290                                         sp = stack_start;
8291                                         CHECK_UNVERIFIABLE (cfg);
8292                                 }
8293                                 cfg->cbb->next_bb = tblock;
8294                                 cfg->cbb = tblock;
8295                                 for (i = 0; i < cfg->cbb->in_scount; ++i) {
8296                                         if (cfg->verbose_level > 3)
8297                                                 printf ("loading %d from temp %d\n", i, (int)cfg->cbb->in_stack [i]->inst_c0);
8298                                         EMIT_NEW_TEMPLOAD (cfg, ins, cfg->cbb->in_stack [i]->inst_c0);
8299                                         *sp++ = ins;
8300                                 }
8301                                 g_slist_free (class_inits);
8302                                 class_inits = NULL;
8303                         }
8304                 }
8305
8306                 if (skip_dead_blocks) {
8307                         int ip_offset = ip - header->code;
8308
8309                         if (ip_offset == bb->end)
8310                                 bb = bb->next;
8311
8312                         if (bb->dead) {
8313                                 int op_size = mono_opcode_size (ip, end);
8314                                 g_assert (op_size > 0); /*The BB formation pass must catch all bad ops*/
8315
8316                                 if (cfg->verbose_level > 3) printf ("SKIPPING DEAD OP at %x\n", ip_offset);
8317
8318                                 if (ip_offset + op_size == bb->end) {
8319                                         MONO_INST_NEW (cfg, ins, OP_NOP);
8320                                         MONO_ADD_INS (cfg->cbb, ins);
8321                                         start_new_bblock = 1;
8322                                 }
8323
8324                                 ip += op_size;
8325                                 continue;
8326                         }
8327                 }
8328                 /*
8329                  * Sequence points are points where the debugger can place a breakpoint.
8330                  * Currently, we generate these automatically at points where the IL
8331                  * stack is empty.
8332                  */
8333                 if (seq_points && ((!sym_seq_points && (sp == stack_start)) || (sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code)))) {
8334                         /*
8335                          * Make methods interruptable at the beginning, and at the targets of
8336                          * backward branches.
8337                          * Also, do this at the start of every bblock in methods with clauses too,
8338                          * to be able to handle instructions with inprecise control flow like
8339                          * throw/endfinally.
8340                          * Backward branches are handled at the end of method-to-ir ().
8341                          */
8342                         gboolean intr_loc = ip == header->code || (!cfg->cbb->last_ins && cfg->header->num_clauses);
8343                         gboolean sym_seq_point = sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code);
8344
8345                         /* Avoid sequence points on empty IL like .volatile */
8346                         // FIXME: Enable this
8347                         //if (!(cfg->cbb->last_ins && cfg->cbb->last_ins->opcode == OP_SEQ_POINT)) {
8348                         NEW_SEQ_POINT (cfg, ins, ip - header->code, intr_loc);
8349                         if ((sp != stack_start) && !sym_seq_point)
8350                                 ins->flags |= MONO_INST_NONEMPTY_STACK;
8351                         MONO_ADD_INS (cfg->cbb, ins);
8352
8353                         if (sym_seq_points)
8354                                 mono_bitset_set_fast (seq_point_set_locs, ip - header->code);
8355                 }
8356
8357                 cfg->cbb->real_offset = cfg->real_offset;
8358
8359                 if ((cfg->method == method) && cfg->coverage_info) {
8360                         guint32 cil_offset = ip - header->code;
8361                         cfg->coverage_info->data [cil_offset].cil_code = ip;
8362
8363                         /* TODO: Use an increment here */
8364 #if defined(TARGET_X86)
8365                         MONO_INST_NEW (cfg, ins, OP_STORE_MEM_IMM);
8366                         ins->inst_p0 = &(cfg->coverage_info->data [cil_offset].count);
8367                         ins->inst_imm = 1;
8368                         MONO_ADD_INS (cfg->cbb, ins);
8369 #else
8370                         EMIT_NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
8371                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, ins->dreg, 0, 1);
8372 #endif
8373                 }
8374
8375                 if (cfg->verbose_level > 3)
8376                         printf ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
8377
8378                 switch (*ip) {
8379                 case CEE_NOP:
8380                         if (seq_points && !sym_seq_points && sp != stack_start) {
8381                                 /*
8382                                  * The C# compiler uses these nops to notify the JIT that it should
8383                                  * insert seq points.
8384                                  */
8385                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, FALSE);
8386                                 MONO_ADD_INS (cfg->cbb, ins);
8387                         }
8388                         if (cfg->keep_cil_nops)
8389                                 MONO_INST_NEW (cfg, ins, OP_HARD_NOP);
8390                         else
8391                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8392                         ip++;
8393                         MONO_ADD_INS (cfg->cbb, ins);
8394                         break;
8395                 case CEE_BREAK:
8396                         if (should_insert_brekpoint (cfg->method)) {
8397                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
8398                         } else {
8399                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8400                         }
8401                         ip++;
8402                         MONO_ADD_INS (cfg->cbb, ins);
8403                         break;
8404                 case CEE_LDARG_0:
8405                 case CEE_LDARG_1:
8406                 case CEE_LDARG_2:
8407                 case CEE_LDARG_3:
8408                         CHECK_STACK_OVF (1);
8409                         n = (*ip)-CEE_LDARG_0;
8410                         CHECK_ARG (n);
8411                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8412                         ip++;
8413                         *sp++ = ins;
8414                         break;
8415                 case CEE_LDLOC_0:
8416                 case CEE_LDLOC_1:
8417                 case CEE_LDLOC_2:
8418                 case CEE_LDLOC_3:
8419                         CHECK_STACK_OVF (1);
8420                         n = (*ip)-CEE_LDLOC_0;
8421                         CHECK_LOCAL (n);
8422                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8423                         ip++;
8424                         *sp++ = ins;
8425                         break;
8426                 case CEE_STLOC_0:
8427                 case CEE_STLOC_1:
8428                 case CEE_STLOC_2:
8429                 case CEE_STLOC_3: {
8430                         CHECK_STACK (1);
8431                         n = (*ip)-CEE_STLOC_0;
8432                         CHECK_LOCAL (n);
8433                         --sp;
8434                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
8435                                 UNVERIFIED;
8436                         emit_stloc_ir (cfg, sp, header, n);
8437                         ++ip;
8438                         inline_costs += 1;
8439                         break;
8440                         }
8441                 case CEE_LDARG_S:
8442                         CHECK_OPSIZE (2);
8443                         CHECK_STACK_OVF (1);
8444                         n = ip [1];
8445                         CHECK_ARG (n);
8446                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8447                         *sp++ = ins;
8448                         ip += 2;
8449                         break;
8450                 case CEE_LDARGA_S:
8451                         CHECK_OPSIZE (2);
8452                         CHECK_STACK_OVF (1);
8453                         n = ip [1];
8454                         CHECK_ARG (n);
8455                         NEW_ARGLOADA (cfg, ins, n);
8456                         MONO_ADD_INS (cfg->cbb, ins);
8457                         *sp++ = ins;
8458                         ip += 2;
8459                         break;
8460                 case CEE_STARG_S:
8461                         CHECK_OPSIZE (2);
8462                         CHECK_STACK (1);
8463                         --sp;
8464                         n = ip [1];
8465                         CHECK_ARG (n);
8466                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [ip [1]], *sp))
8467                                 UNVERIFIED;
8468                         EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
8469                         ip += 2;
8470                         break;
8471                 case CEE_LDLOC_S:
8472                         CHECK_OPSIZE (2);
8473                         CHECK_STACK_OVF (1);
8474                         n = ip [1];
8475                         CHECK_LOCAL (n);
8476                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8477                         *sp++ = ins;
8478                         ip += 2;
8479                         break;
8480                 case CEE_LDLOCA_S: {
8481                         unsigned char *tmp_ip;
8482                         CHECK_OPSIZE (2);
8483                         CHECK_STACK_OVF (1);
8484                         CHECK_LOCAL (ip [1]);
8485
8486                         if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 1))) {
8487                                 ip = tmp_ip;
8488                                 inline_costs += 1;
8489                                 break;
8490                         }
8491
8492                         EMIT_NEW_LOCLOADA (cfg, ins, ip [1]);
8493                         *sp++ = ins;
8494                         ip += 2;
8495                         break;
8496                 }
8497                 case CEE_STLOC_S:
8498                         CHECK_OPSIZE (2);
8499                         CHECK_STACK (1);
8500                         --sp;
8501                         CHECK_LOCAL (ip [1]);
8502                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [ip [1]], *sp))
8503                                 UNVERIFIED;
8504                         emit_stloc_ir (cfg, sp, header, ip [1]);
8505                         ip += 2;
8506                         inline_costs += 1;
8507                         break;
8508                 case CEE_LDNULL:
8509                         CHECK_STACK_OVF (1);
8510                         EMIT_NEW_PCONST (cfg, ins, NULL);
8511                         ins->type = STACK_OBJ;
8512                         ++ip;
8513                         *sp++ = ins;
8514                         break;
8515                 case CEE_LDC_I4_M1:
8516                         CHECK_STACK_OVF (1);
8517                         EMIT_NEW_ICONST (cfg, ins, -1);
8518                         ++ip;
8519                         *sp++ = ins;
8520                         break;
8521                 case CEE_LDC_I4_0:
8522                 case CEE_LDC_I4_1:
8523                 case CEE_LDC_I4_2:
8524                 case CEE_LDC_I4_3:
8525                 case CEE_LDC_I4_4:
8526                 case CEE_LDC_I4_5:
8527                 case CEE_LDC_I4_6:
8528                 case CEE_LDC_I4_7:
8529                 case CEE_LDC_I4_8:
8530                         CHECK_STACK_OVF (1);
8531                         EMIT_NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
8532                         ++ip;
8533                         *sp++ = ins;
8534                         break;
8535                 case CEE_LDC_I4_S:
8536                         CHECK_OPSIZE (2);
8537                         CHECK_STACK_OVF (1);
8538                         ++ip;
8539                         EMIT_NEW_ICONST (cfg, ins, *((signed char*)ip));
8540                         ++ip;
8541                         *sp++ = ins;
8542                         break;
8543                 case CEE_LDC_I4:
8544                         CHECK_OPSIZE (5);
8545                         CHECK_STACK_OVF (1);
8546                         EMIT_NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
8547                         ip += 5;
8548                         *sp++ = ins;
8549                         break;
8550                 case CEE_LDC_I8:
8551                         CHECK_OPSIZE (9);
8552                         CHECK_STACK_OVF (1);
8553                         MONO_INST_NEW (cfg, ins, OP_I8CONST);
8554                         ins->type = STACK_I8;
8555                         ins->dreg = alloc_dreg (cfg, STACK_I8);
8556                         ++ip;
8557                         ins->inst_l = (gint64)read64 (ip);
8558                         MONO_ADD_INS (cfg->cbb, ins);
8559                         ip += 8;
8560                         *sp++ = ins;
8561                         break;
8562                 case CEE_LDC_R4: {
8563                         float *f;
8564                         gboolean use_aotconst = FALSE;
8565
8566 #ifdef TARGET_POWERPC
8567                         /* FIXME: Clean this up */
8568                         if (cfg->compile_aot)
8569                                 use_aotconst = TRUE;
8570 #endif
8571
8572                         /* FIXME: we should really allocate this only late in the compilation process */
8573                         f = mono_domain_alloc (cfg->domain, sizeof (float));
8574                         CHECK_OPSIZE (5);
8575                         CHECK_STACK_OVF (1);
8576
8577                         if (use_aotconst) {
8578                                 MonoInst *cons;
8579                                 int dreg;
8580
8581                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R4, f);
8582
8583                                 dreg = alloc_freg (cfg);
8584                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR4_MEMBASE, dreg, cons->dreg, 0);
8585                                 ins->type = cfg->r4_stack_type;
8586                         } else {
8587                                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
8588                                 ins->type = cfg->r4_stack_type;
8589                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8590                                 ins->inst_p0 = f;
8591                                 MONO_ADD_INS (cfg->cbb, ins);
8592                         }
8593                         ++ip;
8594                         readr4 (ip, f);
8595                         ip += 4;
8596                         *sp++ = ins;                    
8597                         break;
8598                 }
8599                 case CEE_LDC_R8: {
8600                         double *d;
8601                         gboolean use_aotconst = FALSE;
8602
8603 #ifdef TARGET_POWERPC
8604                         /* FIXME: Clean this up */
8605                         if (cfg->compile_aot)
8606                                 use_aotconst = TRUE;
8607 #endif
8608
8609                         /* FIXME: we should really allocate this only late in the compilation process */
8610                         d = mono_domain_alloc (cfg->domain, sizeof (double));
8611                         CHECK_OPSIZE (9);
8612                         CHECK_STACK_OVF (1);
8613
8614                         if (use_aotconst) {
8615                                 MonoInst *cons;
8616                                 int dreg;
8617
8618                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R8, d);
8619
8620                                 dreg = alloc_freg (cfg);
8621                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR8_MEMBASE, dreg, cons->dreg, 0);
8622                                 ins->type = STACK_R8;
8623                         } else {
8624                                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
8625                                 ins->type = STACK_R8;
8626                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8627                                 ins->inst_p0 = d;
8628                                 MONO_ADD_INS (cfg->cbb, ins);
8629                         }
8630                         ++ip;
8631                         readr8 (ip, d);
8632                         ip += 8;
8633                         *sp++ = ins;
8634                         break;
8635                 }
8636                 case CEE_DUP: {
8637                         MonoInst *temp, *store;
8638                         CHECK_STACK (1);
8639                         CHECK_STACK_OVF (1);
8640                         sp--;
8641                         ins = *sp;
8642
8643                         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
8644                         EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
8645
8646                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8647                         *sp++ = ins;
8648
8649                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8650                         *sp++ = ins;
8651
8652                         ++ip;
8653                         inline_costs += 2;
8654                         break;
8655                 }
8656                 case CEE_POP:
8657                         CHECK_STACK (1);
8658                         ip++;
8659                         --sp;
8660
8661 #ifdef TARGET_X86
8662                         if (sp [0]->type == STACK_R8)
8663                                 /* we need to pop the value from the x86 FP stack */
8664                                 MONO_EMIT_NEW_UNALU (cfg, OP_X86_FPOP, -1, sp [0]->dreg);
8665 #endif
8666                         break;
8667                 case CEE_JMP: {
8668                         MonoCallInst *call;
8669                         MonoMethodSignature *fsig;
8670                         int i, n;
8671
8672                         INLINE_FAILURE ("jmp");
8673                         GSHAREDVT_FAILURE (*ip);
8674
8675                         CHECK_OPSIZE (5);
8676                         if (stack_start != sp)
8677                                 UNVERIFIED;
8678                         token = read32 (ip + 1);
8679                         /* FIXME: check the signature matches */
8680                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
8681
8682                         if (!cmethod || mono_loader_get_last_error ())
8683                                 LOAD_ERROR;
8684  
8685                         if (cfg->gshared && mono_method_check_context_used (cmethod))
8686                                 GENERIC_SHARING_FAILURE (CEE_JMP);
8687
8688                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
8689
8690                         fsig = mono_method_signature (cmethod);
8691                         n = fsig->param_count + fsig->hasthis;
8692                         if (cfg->llvm_only) {
8693                                 MonoInst **args;
8694
8695                                 args = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
8696                                 for (i = 0; i < n; ++i)
8697                                         EMIT_NEW_ARGLOAD (cfg, args [i], i);
8698                                 ins = mono_emit_method_call_full (cfg, cmethod, fsig, TRUE, args, NULL, NULL, NULL);
8699                                 /*
8700                                  * The code in mono-basic-block.c treats the rest of the code as dead, but we
8701                                  * have to emit a normal return since llvm expects it.
8702                                  */
8703                                 if (cfg->ret)
8704                                         emit_setret (cfg, ins);
8705                                 MONO_INST_NEW (cfg, ins, OP_BR);
8706                                 ins->inst_target_bb = end_bblock;
8707                                 MONO_ADD_INS (cfg->cbb, ins);
8708                                 link_bblock (cfg, cfg->cbb, end_bblock);
8709                                 ip += 5;
8710                                 break;
8711                         } else if (cfg->backend->have_op_tail_call) {
8712                                 /* Handle tail calls similarly to calls */
8713                                 DISABLE_AOT (cfg);
8714
8715                                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
8716                                 call->method = cmethod;
8717                                 call->tail_call = TRUE;
8718                                 call->signature = mono_method_signature (cmethod);
8719                                 call->args = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
8720                                 call->inst.inst_p0 = cmethod;
8721                                 for (i = 0; i < n; ++i)
8722                                         EMIT_NEW_ARGLOAD (cfg, call->args [i], i);
8723
8724                                 mono_arch_emit_call (cfg, call);
8725                                 cfg->param_area = MAX(cfg->param_area, call->stack_usage);
8726                                 MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
8727                         } else {
8728                                 for (i = 0; i < num_args; ++i)
8729                                         /* Prevent arguments from being optimized away */
8730                                         arg_array [i]->flags |= MONO_INST_VOLATILE;
8731
8732                                 MONO_INST_NEW_CALL (cfg, call, OP_JMP);
8733                                 ins = (MonoInst*)call;
8734                                 ins->inst_p0 = cmethod;
8735                                 MONO_ADD_INS (cfg->cbb, ins);
8736                         }
8737
8738                         ip += 5;
8739                         start_new_bblock = 1;
8740                         break;
8741                 }
8742                 case CEE_CALLI: {
8743                         MonoInst *addr;
8744                         MonoMethodSignature *fsig;
8745
8746                         CHECK_OPSIZE (5);
8747                         token = read32 (ip + 1);
8748
8749                         ins = NULL;
8750
8751                         //GSHAREDVT_FAILURE (*ip);
8752                         cmethod = NULL;
8753                         CHECK_STACK (1);
8754                         --sp;
8755                         addr = *sp;
8756                         fsig = mini_get_signature (method, token, generic_context);
8757
8758                         if (method->dynamic && fsig->pinvoke) {
8759                                 MonoInst *args [3];
8760
8761                                 /*
8762                                  * This is a call through a function pointer using a pinvoke
8763                                  * signature. Have to create a wrapper and call that instead.
8764                                  * FIXME: This is very slow, need to create a wrapper at JIT time
8765                                  * instead based on the signature.
8766                                  */
8767                                 EMIT_NEW_IMAGECONST (cfg, args [0], method->klass->image);
8768                                 EMIT_NEW_PCONST (cfg, args [1], fsig);
8769                                 args [2] = addr;
8770                                 addr = mono_emit_jit_icall (cfg, mono_get_native_calli_wrapper, args);
8771                         }
8772
8773                         n = fsig->param_count + fsig->hasthis;
8774
8775                         CHECK_STACK (n);
8776
8777                         //g_assert (!virtual || fsig->hasthis);
8778
8779                         sp -= n;
8780
8781                         inline_costs += 10 * num_calls++;
8782
8783                         /*
8784                          * Making generic calls out of gsharedvt methods.
8785                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
8786                          * patching gshared method addresses into a gsharedvt method.
8787                          */
8788                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
8789                                 /*
8790                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
8791                                  */
8792                                 MonoInst *callee = addr;
8793
8794                                 if (method->wrapper_type != MONO_WRAPPER_DELEGATE_INVOKE)
8795                                         /* Not tested */
8796                                         GSHAREDVT_FAILURE (*ip);
8797
8798                                 addr = emit_get_rgctx_sig (cfg, context_used,
8799                                                                                           fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
8800                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
8801                                 goto calli_end;
8802                         }
8803
8804                         /* Prevent inlining of methods with indirect calls */
8805                         INLINE_FAILURE ("indirect call");
8806
8807                         if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST || addr->opcode == OP_GOT_ENTRY) {
8808                                 int info_type;
8809                                 gpointer info_data;
8810
8811                                 /*
8812                                  * Instead of emitting an indirect call, emit a direct call
8813                                  * with the contents of the aotconst as the patch info.
8814                                  */
8815                                 if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST) {
8816                                         info_type = addr->inst_c1;
8817                                         info_data = addr->inst_p0;
8818                                 } else {
8819                                         info_type = addr->inst_right->inst_c1;
8820                                         info_data = addr->inst_right->inst_left;
8821                                 }
8822
8823                                 if (info_type == MONO_PATCH_INFO_ICALL_ADDR || info_type == MONO_PATCH_INFO_JIT_ICALL_ADDR) {
8824                                         ins = (MonoInst*)mono_emit_abs_call (cfg, info_type, info_data, fsig, sp);
8825                                         NULLIFY_INS (addr);
8826                                         goto calli_end;
8827                                 }
8828                         }
8829                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8830
8831                         calli_end:
8832
8833                         /* End of call, INS should contain the result of the call, if any */
8834
8835                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8836                                 g_assert (ins);
8837                                 *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
8838                         }
8839
8840                         CHECK_CFG_EXCEPTION;
8841
8842                         ip += 5;
8843                         ins_flag = 0;
8844                         constrained_class = NULL;
8845                         break;
8846                 }
8847                 case CEE_CALL:
8848                 case CEE_CALLVIRT: {
8849                         MonoInst *addr = NULL;
8850                         MonoMethodSignature *fsig = NULL;
8851                         int array_rank = 0;
8852                         int virtual = *ip == CEE_CALLVIRT;
8853                         gboolean pass_imt_from_rgctx = FALSE;
8854                         MonoInst *imt_arg = NULL;
8855                         MonoInst *keep_this_alive = NULL;
8856                         gboolean pass_vtable = FALSE;
8857                         gboolean pass_mrgctx = FALSE;
8858                         MonoInst *vtable_arg = NULL;
8859                         gboolean check_this = FALSE;
8860                         gboolean supported_tail_call = FALSE;
8861                         gboolean tail_call = FALSE;
8862                         gboolean need_seq_point = FALSE;
8863                         guint32 call_opcode = *ip;
8864                         gboolean emit_widen = TRUE;
8865                         gboolean push_res = TRUE;
8866                         gboolean skip_ret = FALSE;
8867                         gboolean delegate_invoke = FALSE;
8868                         gboolean direct_icall = FALSE;
8869                         gboolean constrained_partial_call = FALSE;
8870                         MonoMethod *cil_method;
8871
8872                         CHECK_OPSIZE (5);
8873                         token = read32 (ip + 1);
8874
8875                         ins = NULL;
8876
8877                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
8878                         cil_method = cmethod;
8879                                 
8880                         if (constrained_class) {
8881                                 if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->gshared) {
8882                                         if (!mini_is_gsharedvt_klass (constrained_class)) {
8883                                                 g_assert (!cmethod->klass->valuetype);
8884                                                 if (!mini_type_is_reference (&constrained_class->byval_arg))
8885                                                         constrained_partial_call = TRUE;
8886                                         }
8887                                 }
8888
8889                                 if (method->wrapper_type != MONO_WRAPPER_NONE) {
8890                                         if (cfg->verbose_level > 2)
8891                                                 printf ("DM Constrained call to %s\n", mono_type_get_full_name (constrained_class));
8892                                         if (!((constrained_class->byval_arg.type == MONO_TYPE_VAR ||
8893                                                    constrained_class->byval_arg.type == MONO_TYPE_MVAR) &&
8894                                                   cfg->gshared)) {
8895                                                 cmethod = mono_get_method_constrained_with_method (image, cil_method, constrained_class, generic_context, &cfg->error);
8896                                                 CHECK_CFG_ERROR;
8897                                         }
8898                                 } else {
8899                                         if (cfg->verbose_level > 2)
8900                                                 printf ("Constrained call to %s\n", mono_type_get_full_name (constrained_class));
8901
8902                                         if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->gshared) {
8903                                                 /* 
8904                                                  * This is needed since get_method_constrained can't find 
8905                                                  * the method in klass representing a type var.
8906                                                  * The type var is guaranteed to be a reference type in this
8907                                                  * case.
8908                                                  */
8909                                                 if (!mini_is_gsharedvt_klass (constrained_class))
8910                                                         g_assert (!cmethod->klass->valuetype);
8911                                         } else {
8912                                                 cmethod = mono_get_method_constrained_checked (image, token, constrained_class, generic_context, &cil_method, &cfg->error);
8913                                                 CHECK_CFG_ERROR;
8914                                         }
8915                                 }
8916                         }
8917                                         
8918                         if (!cmethod || mono_loader_get_last_error ())
8919                                 LOAD_ERROR;
8920                         if (!dont_verify && !cfg->skip_visibility) {
8921                                 MonoMethod *target_method = cil_method;
8922                                 if (method->is_inflated) {
8923                                         target_method = mini_get_method_allow_open (method, token, NULL, &(mono_method_get_generic_container (method_definition)->context));
8924                                 }
8925                                 if (!mono_method_can_access_method (method_definition, target_method) &&
8926                                         !mono_method_can_access_method (method, cil_method))
8927                                         METHOD_ACCESS_FAILURE (method, cil_method);
8928                         }
8929
8930                         if (mono_security_core_clr_enabled ())
8931                                 ensure_method_is_allowed_to_call_method (cfg, method, cil_method);
8932
8933                         if (!virtual && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
8934                                 /* MS.NET seems to silently convert this to a callvirt */
8935                                 virtual = 1;
8936
8937                         {
8938                                 /*
8939                                  * MS.NET accepts non virtual calls to virtual final methods of transparent proxy classes and
8940                                  * converts to a callvirt.
8941                                  *
8942                                  * tests/bug-515884.il is an example of this behavior
8943                                  */
8944                                 const int test_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_STATIC;
8945                                 const int expected_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL;
8946                                 if (!virtual && mono_class_is_marshalbyref (cmethod->klass) && (cmethod->flags & test_flags) == expected_flags && cfg->method->wrapper_type == MONO_WRAPPER_NONE)
8947                                         virtual = 1;
8948                         }
8949
8950                         if (!cmethod->klass->inited)
8951                                 if (!mono_class_init (cmethod->klass))
8952                                         TYPE_LOAD_ERROR (cmethod->klass);
8953
8954                         fsig = mono_method_signature (cmethod);
8955                         if (!fsig)
8956                                 LOAD_ERROR;
8957                         if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
8958                                 mini_class_is_system_array (cmethod->klass)) {
8959                                 array_rank = cmethod->klass->rank;
8960                         } else if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && icall_is_direct_callable (cfg, cmethod)) {
8961                                 direct_icall = TRUE;
8962                         } else if (fsig->pinvoke) {
8963                                 MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
8964                                 fsig = mono_method_signature (wrapper);
8965                         } else if (constrained_class) {
8966                         } else {
8967                                 fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
8968                                 CHECK_CFG_ERROR;
8969                         }
8970
8971                         /* See code below */
8972                         if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
8973                                 MonoBasicBlock *tbb;
8974
8975                                 GET_BBLOCK (cfg, tbb, ip + 5);
8976                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
8977                                         /*
8978                                          * We want to extend the try block to cover the call, but we can't do it if the
8979                                          * call is made directly since its followed by an exception check.
8980                                          */
8981                                         direct_icall = FALSE;
8982                                 }
8983                         }
8984
8985                         mono_save_token_info (cfg, image, token, cil_method);
8986
8987                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip + 5 - header->code)))
8988                                 need_seq_point = TRUE;
8989
8990                         /* Don't support calls made using type arguments for now */
8991                         /*
8992                           if (cfg->gsharedvt) {
8993                           if (mini_is_gsharedvt_signature (fsig))
8994                           GSHAREDVT_FAILURE (*ip);
8995                           }
8996                         */
8997
8998                         if (cmethod->string_ctor && method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE)
8999                                 g_assert_not_reached ();
9000
9001                         n = fsig->param_count + fsig->hasthis;
9002
9003                         if (!cfg->gshared && cmethod->klass->generic_container)
9004                                 UNVERIFIED;
9005
9006                         if (!cfg->gshared)
9007                                 g_assert (!mono_method_check_context_used (cmethod));
9008
9009                         CHECK_STACK (n);
9010
9011                         //g_assert (!virtual || fsig->hasthis);
9012
9013                         sp -= n;
9014
9015                         /*
9016                          * We have the `constrained.' prefix opcode.
9017                          */
9018                         if (constrained_class) {
9019                                 if (mini_is_gsharedvt_klass (constrained_class)) {
9020                                         if ((cmethod->klass != mono_defaults.object_class) && constrained_class->valuetype && cmethod->klass->valuetype) {
9021                                                 /* The 'Own method' case below */
9022                                         } else if (cmethod->klass->image != mono_defaults.corlib && !(cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !cmethod->klass->valuetype) {
9023                                                 /* 'The type parameter is instantiated as a reference type' case below. */
9024                                         } else {
9025                                                 ins = handle_constrained_gsharedvt_call (cfg, cmethod, fsig, sp, constrained_class, &emit_widen);
9026                                                 CHECK_CFG_EXCEPTION;
9027                                                 g_assert (ins);
9028                                                 goto call_end;
9029                                         }
9030                                 }
9031
9032                                 if (constrained_partial_call) {
9033                                         gboolean need_box = TRUE;
9034
9035                                         /*
9036                                          * The receiver is a valuetype, but the exact type is not known at compile time. This means the
9037                                          * called method is not known at compile time either. The called method could end up being
9038                                          * one of the methods on the parent classes (object/valuetype/enum), in which case we need
9039                                          * to box the receiver.
9040                                          * A simple solution would be to box always and make a normal virtual call, but that would
9041                                          * be bad performance wise.
9042                                          */
9043                                         if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE && cmethod->klass->generic_class) {
9044                                                 /*
9045                                                  * The parent classes implement no generic interfaces, so the called method will be a vtype method, so no boxing neccessary.
9046                                                  */
9047                                                 need_box = FALSE;
9048                                         }
9049
9050                                         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)) {
9051                                                 /* The called method is not virtual, i.e. Object:GetType (), the receiver is a vtype, has to box */
9052                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9053                                                 ins->klass = constrained_class;
9054                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9055                                                 CHECK_CFG_EXCEPTION;
9056                                         } else if (need_box) {
9057                                                 MonoInst *box_type;
9058                                                 MonoBasicBlock *is_ref_bb, *end_bb;
9059                                                 MonoInst *nonbox_call;
9060
9061                                                 /*
9062                                                  * Determine at runtime whenever the called method is defined on object/valuetype/enum, and emit a boxing call
9063                                                  * if needed.
9064                                                  * FIXME: It is possible to inline the called method in a lot of cases, i.e. for T_INT,
9065                                                  * the no-box case goes to a method in Int32, while the box case goes to a method in Enum.
9066                                                  */
9067                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
9068
9069                                                 NEW_BBLOCK (cfg, is_ref_bb);
9070                                                 NEW_BBLOCK (cfg, end_bb);
9071
9072                                                 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);
9073                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, box_type->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
9074                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
9075
9076                                                 /* Non-ref case */
9077                                                 nonbox_call = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9078
9079                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
9080
9081                                                 /* Ref case */
9082                                                 MONO_START_BB (cfg, is_ref_bb);
9083                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9084                                                 ins->klass = constrained_class;
9085                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9086                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9087
9088                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
9089
9090                                                 MONO_START_BB (cfg, end_bb);
9091                                                 cfg->cbb = end_bb;
9092
9093                                                 nonbox_call->dreg = ins->dreg;
9094                                                 goto call_end;
9095                                         } else {
9096                                                 g_assert (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE);
9097                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
9098                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9099                                                 goto call_end;
9100                                         }
9101                                 } else if (constrained_class->valuetype && (cmethod->klass == mono_defaults.object_class || cmethod->klass == mono_defaults.enum_class->parent || cmethod->klass == mono_defaults.enum_class)) {
9102                                         /*
9103                                          * The type parameter is instantiated as a valuetype,
9104                                          * but that type doesn't override the method we're
9105                                          * calling, so we need to box `this'.
9106                                          */
9107                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9108                                         ins->klass = constrained_class;
9109                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9110                                         CHECK_CFG_EXCEPTION;
9111                                 } else if (!constrained_class->valuetype) {
9112                                         int dreg = alloc_ireg_ref (cfg);
9113
9114                                         /*
9115                                          * The type parameter is instantiated as a reference
9116                                          * type.  We have a managed pointer on the stack, so
9117                                          * we need to dereference it here.
9118                                          */
9119                                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, sp [0]->dreg, 0);
9120                                         ins->type = STACK_OBJ;
9121                                         sp [0] = ins;
9122                                 } else {
9123                                         if (cmethod->klass->valuetype) {
9124                                                 /* Own method */
9125                                         } else {
9126                                                 /* Interface method */
9127                                                 int ioffset, slot;
9128
9129                                                 mono_class_setup_vtable (constrained_class);
9130                                                 CHECK_TYPELOAD (constrained_class);
9131                                                 ioffset = mono_class_interface_offset (constrained_class, cmethod->klass);
9132                                                 if (ioffset == -1)
9133                                                         TYPE_LOAD_ERROR (constrained_class);
9134                                                 slot = mono_method_get_vtable_slot (cmethod);
9135                                                 if (slot == -1)
9136                                                         TYPE_LOAD_ERROR (cmethod->klass);
9137                                                 cmethod = constrained_class->vtable [ioffset + slot];
9138
9139                                                 if (cmethod->klass == mono_defaults.enum_class) {
9140                                                         /* Enum implements some interfaces, so treat this as the first case */
9141                                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9142                                                         ins->klass = constrained_class;
9143                                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9144                                                         CHECK_CFG_EXCEPTION;
9145                                                 }
9146                                         }
9147                                         virtual = 0;
9148                                 }
9149                                 constrained_class = NULL;
9150                         }
9151
9152                         if (check_call_signature (cfg, fsig, sp))
9153                                 UNVERIFIED;
9154
9155                         if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (cmethod->name, "Invoke"))
9156                                 delegate_invoke = TRUE;
9157
9158                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_sharable_method (cfg, cmethod, fsig, sp))) {
9159                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9160                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
9161                                         emit_widen = FALSE;
9162                                 }
9163
9164                                 goto call_end;
9165                         }
9166
9167                         /* 
9168                          * If the callee is a shared method, then its static cctor
9169                          * might not get called after the call was patched.
9170                          */
9171                         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)) {
9172                                 emit_class_init (cfg, cmethod->klass);
9173                                 CHECK_TYPELOAD (cmethod->klass);
9174                         }
9175
9176                         check_method_sharing (cfg, cmethod, &pass_vtable, &pass_mrgctx);
9177
9178                         if (cfg->gshared) {
9179                                 MonoGenericContext *cmethod_context = mono_method_get_context (cmethod);
9180
9181                                 context_used = mini_method_check_context_used (cfg, cmethod);
9182
9183                                 if (context_used && (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
9184                                         /* Generic method interface
9185                                            calls are resolved via a
9186                                            helper function and don't
9187                                            need an imt. */
9188                                         if (!cmethod_context || !cmethod_context->method_inst)
9189                                                 pass_imt_from_rgctx = TRUE;
9190                                 }
9191
9192                                 /*
9193                                  * If a shared method calls another
9194                                  * shared method then the caller must
9195                                  * have a generic sharing context
9196                                  * because the magic trampoline
9197                                  * requires it.  FIXME: We shouldn't
9198                                  * have to force the vtable/mrgctx
9199                                  * variable here.  Instead there
9200                                  * should be a flag in the cfg to
9201                                  * request a generic sharing context.
9202                                  */
9203                                 if (context_used &&
9204                                                 ((method->flags & METHOD_ATTRIBUTE_STATIC) || method->klass->valuetype))
9205                                         mono_get_vtable_var (cfg);
9206                         }
9207
9208                         if (pass_vtable) {
9209                                 if (context_used) {
9210                                         vtable_arg = emit_get_rgctx_klass (cfg, context_used, cmethod->klass, MONO_RGCTX_INFO_VTABLE);
9211                                 } else {
9212                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
9213
9214                                         CHECK_TYPELOAD (cmethod->klass);
9215                                         EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
9216                                 }
9217                         }
9218
9219                         if (pass_mrgctx) {
9220                                 g_assert (!vtable_arg);
9221
9222                                 if (!cfg->compile_aot) {
9223                                         /* 
9224                                          * emit_get_rgctx_method () calls mono_class_vtable () so check 
9225                                          * for type load errors before.
9226                                          */
9227                                         mono_class_setup_vtable (cmethod->klass);
9228                                         CHECK_TYPELOAD (cmethod->klass);
9229                                 }
9230
9231                                 vtable_arg = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
9232
9233                                 /* !marshalbyref is needed to properly handle generic methods + remoting */
9234                                 if ((!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
9235                                          MONO_METHOD_IS_FINAL (cmethod)) &&
9236                                         !mono_class_is_marshalbyref (cmethod->klass)) {
9237                                         if (virtual)
9238                                                 check_this = TRUE;
9239                                         virtual = 0;
9240                                 }
9241                         }
9242
9243                         if (pass_imt_from_rgctx) {
9244                                 g_assert (!pass_vtable);
9245
9246                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9247                                         cmethod, MONO_RGCTX_INFO_METHOD);
9248                         }
9249
9250                         if (check_this)
9251                                 MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9252
9253                         /* Calling virtual generic methods */
9254                         if (virtual && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) && 
9255                             !(MONO_METHOD_IS_FINAL (cmethod) && 
9256                               cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) &&
9257                             fsig->generic_param_count && 
9258                                 !(cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) &&
9259                                 !cfg->llvm_only) {
9260                                 MonoInst *this_temp, *this_arg_temp, *store;
9261                                 MonoInst *iargs [4];
9262
9263                                 g_assert (fsig->is_inflated);
9264
9265                                 /* Prevent inlining of methods that contain indirect calls */
9266                                 INLINE_FAILURE ("virtual generic call");
9267
9268                                 if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))
9269                                         GSHAREDVT_FAILURE (*ip);
9270
9271                                 if (cfg->backend->have_generalized_imt_thunk && cfg->backend->gshared_supported && cmethod->wrapper_type == MONO_WRAPPER_NONE) {
9272                                         g_assert (!imt_arg);
9273                                         if (!context_used)
9274                                                 g_assert (cmethod->is_inflated);
9275                                         imt_arg = emit_get_rgctx_method (cfg, context_used,
9276                                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
9277                                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, sp [0], imt_arg, NULL);
9278                                 } else {
9279                                         this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
9280                                         NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
9281                                         MONO_ADD_INS (cfg->cbb, store);
9282
9283                                         /* FIXME: This should be a managed pointer */
9284                                         this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
9285
9286                                         EMIT_NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
9287                                         iargs [1] = emit_get_rgctx_method (cfg, context_used,
9288                                                                                                            cmethod, MONO_RGCTX_INFO_METHOD);
9289                                         EMIT_NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
9290                                         addr = mono_emit_jit_icall (cfg,
9291                                                                                                 mono_helper_compile_generic_method, iargs);
9292
9293                                         EMIT_NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
9294
9295                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9296                                 }
9297
9298                                 goto call_end;
9299                         }
9300
9301                         /*
9302                          * Implement a workaround for the inherent races involved in locking:
9303                          * Monitor.Enter ()
9304                          * try {
9305                          * } finally {
9306                          *    Monitor.Exit ()
9307                          * }
9308                          * If a thread abort happens between the call to Monitor.Enter () and the start of the
9309                          * try block, the Exit () won't be executed, see:
9310                          * http://www.bluebytesoftware.com/blog/2007/01/30/MonitorEnterThreadAbortsAndOrphanedLocks.aspx
9311                          * To work around this, we extend such try blocks to include the last x bytes
9312                          * of the Monitor.Enter () call.
9313                          */
9314                         if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
9315                                 MonoBasicBlock *tbb;
9316
9317                                 GET_BBLOCK (cfg, tbb, ip + 5);
9318                                 /* 
9319                                  * Only extend try blocks with a finally, to avoid catching exceptions thrown
9320                                  * from Monitor.Enter like ArgumentNullException.
9321                                  */
9322                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
9323                                         /* Mark this bblock as needing to be extended */
9324                                         tbb->extend_try_block = TRUE;
9325                                 }
9326                         }
9327
9328                         /* Conversion to a JIT intrinsic */
9329                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_method (cfg, cmethod, fsig, sp))) {
9330                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9331                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
9332                                         emit_widen = FALSE;
9333                                 }
9334                                 goto call_end;
9335                         }
9336
9337                         /* Inlining */
9338                         if ((cfg->opt & MONO_OPT_INLINE) &&
9339                                 (!virtual || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || MONO_METHOD_IS_FINAL (cmethod)) &&
9340                             mono_method_check_inlining (cfg, cmethod)) {
9341                                 int costs;
9342                                 gboolean always = FALSE;
9343
9344                                 if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
9345                                         (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
9346                                         /* Prevent inlining of methods that call wrappers */
9347                                         INLINE_FAILURE ("wrapper call");
9348                                         cmethod = mono_marshal_get_native_wrapper (cmethod, TRUE, FALSE);
9349                                         always = TRUE;
9350                                 }
9351
9352                                 costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, always);
9353                                 if (costs) {
9354                                         cfg->real_offset += 5;
9355
9356                                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9357                                                 /* *sp is already set by inline_method */
9358                                                 sp++;
9359                                                 push_res = FALSE;
9360                                         }
9361
9362                                         inline_costs += costs;
9363
9364                                         goto call_end;
9365                                 }
9366                         }
9367
9368                         /* Tail recursion elimination */
9369                         if ((cfg->opt & MONO_OPT_TAILC) && call_opcode == CEE_CALL && cmethod == method && ip [5] == CEE_RET && !vtable_arg) {
9370                                 gboolean has_vtargs = FALSE;
9371                                 int i;
9372
9373                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9374                                 INLINE_FAILURE ("tail call");
9375
9376                                 /* keep it simple */
9377                                 for (i =  fsig->param_count - 1; i >= 0; i--) {
9378                                         if (MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->params [i])) 
9379                                                 has_vtargs = TRUE;
9380                                 }
9381
9382                                 if (!has_vtargs) {
9383                                         for (i = 0; i < n; ++i)
9384                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9385                                         MONO_INST_NEW (cfg, ins, OP_BR);
9386                                         MONO_ADD_INS (cfg->cbb, ins);
9387                                         tblock = start_bblock->out_bb [0];
9388                                         link_bblock (cfg, cfg->cbb, tblock);
9389                                         ins->inst_target_bb = tblock;
9390                                         start_new_bblock = 1;
9391
9392                                         /* skip the CEE_RET, too */
9393                                         if (ip_in_bb (cfg, cfg->cbb, ip + 5))
9394                                                 skip_ret = TRUE;
9395                                         push_res = FALSE;
9396                                         goto call_end;
9397                                 }
9398                         }
9399
9400                         inline_costs += 10 * num_calls++;
9401
9402                         /*
9403                          * Making generic calls out of gsharedvt methods.
9404                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
9405                          * patching gshared method addresses into a gsharedvt method.
9406                          */
9407                         if (cfg->gsharedvt && (mini_is_gsharedvt_signature (fsig) || cmethod->is_inflated || cmethod->klass->generic_class) &&
9408                                 !(cmethod->klass->rank && cmethod->klass->byval_arg.type != MONO_TYPE_SZARRAY)) {
9409                                 MonoRgctxInfoType info_type;
9410
9411                                 if (virtual) {
9412                                         //if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
9413                                                 //GSHAREDVT_FAILURE (*ip);
9414                                         // disable for possible remoting calls
9415                                         if (fsig->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class))
9416                                                 GSHAREDVT_FAILURE (*ip);
9417                                         if (fsig->generic_param_count) {
9418                                                 /* virtual generic call */
9419                                                 g_assert (!imt_arg);
9420                                                 /* Same as the virtual generic case above */
9421                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9422                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9423                                                 /* This is not needed, as the trampoline code will pass one, and it might be passed in the same reg as the imt arg */
9424                                                 vtable_arg = NULL;
9425                                         } else if ((cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !imt_arg) {
9426                                                 /* This can happen when we call a fully instantiated iface method */
9427                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9428                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9429                                                 vtable_arg = NULL;
9430                                         }
9431                                 }
9432
9433                                 if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (cmethod->name, "Invoke")))
9434                                         keep_this_alive = sp [0];
9435
9436                                 if (virtual && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))
9437                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
9438                                 else
9439                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE;
9440                                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, info_type);
9441
9442                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9443                                 goto call_end;
9444                         }
9445
9446                         /* Generic sharing */
9447
9448                         /*
9449                          * Use this if the callee is gsharedvt sharable too, since
9450                          * at runtime we might find an instantiation so the call cannot
9451                          * be patched (the 'no_patch' code path in mini-trampolines.c).
9452                          */
9453                         if (context_used && !imt_arg && !array_rank && !delegate_invoke &&
9454                                 (!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
9455                                  !mono_class_generic_sharing_enabled (cmethod->klass)) &&
9456                                 (!virtual || MONO_METHOD_IS_FINAL (cmethod) ||
9457                                  !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))) {
9458                                 INLINE_FAILURE ("gshared");
9459
9460                                 g_assert (cfg->gshared && cmethod);
9461                                 g_assert (!addr);
9462
9463                                 /*
9464                                  * We are compiling a call to a
9465                                  * generic method from shared code,
9466                                  * which means that we have to look up
9467                                  * the method in the rgctx and do an
9468                                  * indirect call.
9469                                  */
9470                                 if (fsig->hasthis)
9471                                         MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9472
9473                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
9474                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9475                                 goto call_end;
9476                         }
9477
9478                         /* Direct calls to icalls */
9479                         if (direct_icall) {
9480                                 MonoMethod *wrapper;
9481                                 int costs;
9482
9483                                 /* Inline the wrapper */
9484                                 wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
9485
9486                                 costs = inline_method (cfg, wrapper, fsig, sp, ip, cfg->real_offset, TRUE);
9487                                 g_assert (costs > 0);
9488                                 cfg->real_offset += 5;
9489
9490                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9491                                         /* *sp is already set by inline_method */
9492                                         sp++;
9493                                         push_res = FALSE;
9494                                 }
9495
9496                                 inline_costs += costs;
9497
9498                                 goto call_end;
9499                         }
9500                                         
9501                         /* Array methods */
9502                         if (array_rank) {
9503                                 MonoInst *addr;
9504
9505                                 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ 
9506                                         MonoInst *val = sp [fsig->param_count];
9507
9508                                         if (val->type == STACK_OBJ) {
9509                                                 MonoInst *iargs [2];
9510
9511                                                 iargs [0] = sp [0];
9512                                                 iargs [1] = val;
9513                                                 
9514                                                 mono_emit_jit_icall (cfg, mono_helper_stelem_ref_check, iargs);
9515                                         }
9516                                         
9517                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, TRUE);
9518                                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, fsig->params [fsig->param_count - 1], addr->dreg, 0, val->dreg);
9519                                         if (cfg->gen_write_barriers && val->type == STACK_OBJ && !(val->opcode == OP_PCONST && val->inst_c0 == 0))
9520                                                 emit_write_barrier (cfg, addr, val);
9521                                         if (cfg->gen_write_barriers && mini_is_gsharedvt_klass (cmethod->klass))
9522                                                 GSHAREDVT_FAILURE (*ip);
9523                                 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
9524                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9525
9526                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, addr->dreg, 0);
9527                                 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
9528                                         if (!cmethod->klass->element_class->valuetype && !readonly)
9529                                                 mini_emit_check_array_type (cfg, sp [0], cmethod->klass);
9530                                         CHECK_TYPELOAD (cmethod->klass);
9531                                         
9532                                         readonly = FALSE;
9533                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9534                                         ins = addr;
9535                                 } else {
9536                                         g_assert_not_reached ();
9537                                 }
9538
9539                                 emit_widen = FALSE;
9540                                 goto call_end;
9541                         }
9542
9543                         ins = mini_redirect_call (cfg, cmethod, fsig, sp, virtual ? sp [0] : NULL);
9544                         if (ins)
9545                                 goto call_end;
9546
9547                         /* Tail prefix / tail call optimization */
9548
9549                         /* FIXME: Enabling TAILC breaks some inlining/stack trace/etc tests */
9550                         /* FIXME: runtime generic context pointer for jumps? */
9551                         /* FIXME: handle this for generic sharing eventually */
9552                         if ((ins_flag & MONO_INST_TAILCALL) &&
9553                                 !vtable_arg && !cfg->gshared && is_supported_tail_call (cfg, method, cmethod, fsig, call_opcode))
9554                                 supported_tail_call = TRUE;
9555
9556                         if (supported_tail_call) {
9557                                 MonoCallInst *call;
9558
9559                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9560                                 INLINE_FAILURE ("tail call");
9561
9562                                 //printf ("HIT: %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
9563
9564                                 if (cfg->backend->have_op_tail_call) {
9565                                         /* Handle tail calls similarly to normal calls */
9566                                         tail_call = TRUE;
9567                                 } else {
9568                                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
9569
9570                                         MONO_INST_NEW_CALL (cfg, call, OP_JMP);
9571                                         call->tail_call = TRUE;
9572                                         call->method = cmethod;
9573                                         call->signature = mono_method_signature (cmethod);
9574
9575                                         /*
9576                                          * We implement tail calls by storing the actual arguments into the 
9577                                          * argument variables, then emitting a CEE_JMP.
9578                                          */
9579                                         for (i = 0; i < n; ++i) {
9580                                                 /* Prevent argument from being register allocated */
9581                                                 arg_array [i]->flags |= MONO_INST_VOLATILE;
9582                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9583                                         }
9584                                         ins = (MonoInst*)call;
9585                                         ins->inst_p0 = cmethod;
9586                                         ins->inst_p1 = arg_array [0];
9587                                         MONO_ADD_INS (cfg->cbb, ins);
9588                                         link_bblock (cfg, cfg->cbb, end_bblock);
9589                                         start_new_bblock = 1;
9590
9591                                         // FIXME: Eliminate unreachable epilogs
9592
9593                                         /*
9594                                          * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9595                                          * only reachable from this call.
9596                                          */
9597                                         GET_BBLOCK (cfg, tblock, ip + 5);
9598                                         if (tblock == cfg->cbb || tblock->in_count == 0)
9599                                                 skip_ret = TRUE;
9600                                         push_res = FALSE;
9601
9602                                         goto call_end;
9603                                 }
9604                         }
9605
9606                         /* 
9607                          * Synchronized wrappers.
9608                          * Its hard to determine where to replace a method with its synchronized
9609                          * wrapper without causing an infinite recursion. The current solution is
9610                          * to add the synchronized wrapper in the trampolines, and to
9611                          * change the called method to a dummy wrapper, and resolve that wrapper
9612                          * to the real method in mono_jit_compile_method ().
9613                          */
9614                         if (cfg->method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
9615                                 MonoMethod *orig = mono_marshal_method_from_wrapper (cfg->method);
9616                                 if (cmethod == orig || (cmethod->is_inflated && mono_method_get_declaring_generic_method (cmethod) == orig))
9617                                         cmethod = mono_marshal_get_synchronized_inner_wrapper (cmethod);
9618                         }
9619
9620                         /*
9621                          * Interface calls in llvm-only mode are complicated becase the callee might need an rgctx arg,
9622                          * (i.e. its a vtype method), and there is no way to for the caller to know this at compile time.
9623                          * So we make resolve_iface_call return the rgctx, and do two calls with different signatures
9624                          * based on whenever there is an rgctx or not.
9625                          */
9626                         if (cfg->llvm_only && virtual && cmethod && (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
9627                                 MonoInst *args_buf [16], *icall_args [16];
9628                                 MonoInst **args;
9629                                 MonoBasicBlock *rgctx_bb, *end_bb;
9630                                 MonoInst *call1, *call2, *call_target;
9631                                 MonoMethodSignature *rgctx_sig;
9632                                 int rgctx_reg, tmp_reg;
9633
9634                                 MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
9635
9636                                 NEW_BBLOCK (cfg, rgctx_bb);
9637                                 NEW_BBLOCK (cfg, end_bb);
9638
9639                                 // FIXME: Optimize this
9640
9641                                 guint32 imt_slot = mono_method_get_imt_slot (cmethod);
9642
9643                                 icall_args [0] = sp [0];
9644                                 EMIT_NEW_ICONST (cfg, icall_args [1], imt_slot);
9645                                 if (imt_arg) {
9646                                         icall_args [2] = imt_arg;
9647                                 } else {
9648                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_METHODCONST, cmethod);
9649                                         icall_args [2] = ins;
9650                                 }
9651
9652                                 rgctx_reg = alloc_preg (cfg);
9653                                 MONO_EMIT_NEW_PCONST (cfg, rgctx_reg, NULL);
9654                                 EMIT_NEW_VARLOADA_VREG (cfg, icall_args [3], rgctx_reg, &mono_defaults.int_class->byval_arg);
9655                                 //EMIT_NEW_PCONST (cfg, icall_args [3], NULL);
9656
9657                                 call_target = mono_emit_jit_icall (cfg, mono_resolve_iface_call, icall_args);
9658
9659                                 // FIXME: Only do this if needed (generic calls)
9660
9661                                 // Check whenever to pass an rgctx
9662                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rgctx_reg, 0);
9663                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, rgctx_bb);
9664                                 /* Non rgctx case */
9665                                 call1 = mono_emit_calli (cfg, fsig, sp, call_target, NULL, vtable_arg);
9666                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
9667                                 /* Rgctx case */
9668                                 MONO_START_BB (cfg, rgctx_bb);
9669                                 /* Make a call with an rgctx */
9670                                 if (fsig->param_count + 2 < 16)
9671                                         args = args_buf;
9672                                 else
9673                                         args = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (fsig->param_count + 2));
9674                                 args [0] = sp [0];
9675                                 for (i = 0; i < fsig->param_count; ++i)
9676                                         args [i + 1] = sp [i + 1];
9677                                 tmp_reg = alloc_preg (cfg);
9678                                 EMIT_NEW_UNALU (cfg, args [fsig->param_count + 1], OP_MOVE, tmp_reg, rgctx_reg);
9679                                 rgctx_sig = sig_to_rgctx_sig (fsig);
9680                                 call2 = mono_emit_calli (cfg, rgctx_sig, args, call_target, NULL, NULL);
9681                                 call2->dreg = call1->dreg;
9682                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
9683                                 /* End */
9684                                 MONO_START_BB (cfg, end_bb);
9685                                 ins = call1;
9686                                 goto call_end;
9687                         }
9688
9689                         /* Common call */
9690                         INLINE_FAILURE ("call");
9691                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, tail_call, sp, virtual ? sp [0] : NULL,
9692                                                                                           imt_arg, vtable_arg);
9693
9694                         if (tail_call && !cfg->llvm_only) {
9695                                 link_bblock (cfg, cfg->cbb, end_bblock);
9696                                 start_new_bblock = 1;
9697
9698                                 // FIXME: Eliminate unreachable epilogs
9699
9700                                 /*
9701                                  * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9702                                  * only reachable from this call.
9703                                  */
9704                                 GET_BBLOCK (cfg, tblock, ip + 5);
9705                                 if (tblock == cfg->cbb || tblock->in_count == 0)
9706                                         skip_ret = TRUE;
9707                                 push_res = FALSE;
9708                         }
9709
9710                         call_end:
9711
9712                         /* End of call, INS should contain the result of the call, if any */
9713
9714                         if (push_res && !MONO_TYPE_IS_VOID (fsig->ret)) {
9715                                 g_assert (ins);
9716                                 if (emit_widen)
9717                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
9718                                 else
9719                                         *sp++ = ins;
9720                         }
9721
9722                         if (keep_this_alive) {
9723                                 MonoInst *dummy_use;
9724
9725                                 /* See mono_emit_method_call_full () */
9726                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, keep_this_alive);
9727                         }
9728
9729                         CHECK_CFG_EXCEPTION;
9730
9731                         ip += 5;
9732                         if (skip_ret) {
9733                                 g_assert (*ip == CEE_RET);
9734                                 ip += 1;
9735                         }
9736                         ins_flag = 0;
9737                         constrained_class = NULL;
9738                         if (need_seq_point)
9739                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
9740                         break;
9741                 }
9742                 case CEE_RET:
9743                         if (cfg->method != method) {
9744                                 /* return from inlined method */
9745                                 /* 
9746                                  * If in_count == 0, that means the ret is unreachable due to
9747                                  * being preceeded by a throw. In that case, inline_method () will
9748                                  * handle setting the return value 
9749                                  * (test case: test_0_inline_throw ()).
9750                                  */
9751                                 if (return_var && cfg->cbb->in_count) {
9752                                         MonoType *ret_type = mono_method_signature (method)->ret;
9753
9754                                         MonoInst *store;
9755                                         CHECK_STACK (1);
9756                                         --sp;
9757
9758                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
9759                                                 UNVERIFIED;
9760
9761                                         //g_assert (returnvar != -1);
9762                                         EMIT_NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
9763                                         cfg->ret_var_set = TRUE;
9764                                 } 
9765                         } else {
9766                                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
9767
9768                                 if (cfg->lmf_var && cfg->cbb->in_count && !cfg->llvm_only)
9769                                         emit_pop_lmf (cfg);
9770
9771                                 if (cfg->ret) {
9772                                         MonoType *ret_type = mini_get_underlying_type (mono_method_signature (method)->ret);
9773
9774                                         if (seq_points && !sym_seq_points) {
9775                                                 /* 
9776                                                  * Place a seq point here too even through the IL stack is not
9777                                                  * empty, so a step over on
9778                                                  * call <FOO>
9779                                                  * ret
9780                                                  * will work correctly.
9781                                                  */
9782                                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, TRUE);
9783                                                 MONO_ADD_INS (cfg->cbb, ins);
9784                                         }
9785
9786                                         g_assert (!return_var);
9787                                         CHECK_STACK (1);
9788                                         --sp;
9789
9790                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
9791                                                 UNVERIFIED;
9792
9793                                         emit_setret (cfg, *sp);
9794                                 }
9795                         }
9796                         if (sp != stack_start)
9797                                 UNVERIFIED;
9798                         MONO_INST_NEW (cfg, ins, OP_BR);
9799                         ip++;
9800                         ins->inst_target_bb = end_bblock;
9801                         MONO_ADD_INS (cfg->cbb, ins);
9802                         link_bblock (cfg, cfg->cbb, end_bblock);
9803                         start_new_bblock = 1;
9804                         break;
9805                 case CEE_BR_S:
9806                         CHECK_OPSIZE (2);
9807                         MONO_INST_NEW (cfg, ins, OP_BR);
9808                         ip++;
9809                         target = ip + 1 + (signed char)(*ip);
9810                         ++ip;
9811                         GET_BBLOCK (cfg, tblock, target);
9812                         link_bblock (cfg, cfg->cbb, tblock);
9813                         ins->inst_target_bb = tblock;
9814                         if (sp != stack_start) {
9815                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9816                                 sp = stack_start;
9817                                 CHECK_UNVERIFIABLE (cfg);
9818                         }
9819                         MONO_ADD_INS (cfg->cbb, ins);
9820                         start_new_bblock = 1;
9821                         inline_costs += BRANCH_COST;
9822                         break;
9823                 case CEE_BEQ_S:
9824                 case CEE_BGE_S:
9825                 case CEE_BGT_S:
9826                 case CEE_BLE_S:
9827                 case CEE_BLT_S:
9828                 case CEE_BNE_UN_S:
9829                 case CEE_BGE_UN_S:
9830                 case CEE_BGT_UN_S:
9831                 case CEE_BLE_UN_S:
9832                 case CEE_BLT_UN_S:
9833                         CHECK_OPSIZE (2);
9834                         CHECK_STACK (2);
9835                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
9836                         ip++;
9837                         target = ip + 1 + *(signed char*)ip;
9838                         ip++;
9839
9840                         ADD_BINCOND (NULL);
9841
9842                         sp = stack_start;
9843                         inline_costs += BRANCH_COST;
9844                         break;
9845                 case CEE_BR:
9846                         CHECK_OPSIZE (5);
9847                         MONO_INST_NEW (cfg, ins, OP_BR);
9848                         ip++;
9849
9850                         target = ip + 4 + (gint32)read32(ip);
9851                         ip += 4;
9852                         GET_BBLOCK (cfg, tblock, target);
9853                         link_bblock (cfg, cfg->cbb, tblock);
9854                         ins->inst_target_bb = tblock;
9855                         if (sp != stack_start) {
9856                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9857                                 sp = stack_start;
9858                                 CHECK_UNVERIFIABLE (cfg);
9859                         }
9860
9861                         MONO_ADD_INS (cfg->cbb, ins);
9862
9863                         start_new_bblock = 1;
9864                         inline_costs += BRANCH_COST;
9865                         break;
9866                 case CEE_BRFALSE_S:
9867                 case CEE_BRTRUE_S:
9868                 case CEE_BRFALSE:
9869                 case CEE_BRTRUE: {
9870                         MonoInst *cmp;
9871                         gboolean is_short = ((*ip) == CEE_BRFALSE_S) || ((*ip) == CEE_BRTRUE_S);
9872                         gboolean is_true = ((*ip) == CEE_BRTRUE_S) || ((*ip) == CEE_BRTRUE);
9873                         guint32 opsize = is_short ? 1 : 4;
9874
9875                         CHECK_OPSIZE (opsize);
9876                         CHECK_STACK (1);
9877                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
9878                                 UNVERIFIED;
9879                         ip ++;
9880                         target = ip + opsize + (is_short ? *(signed char*)ip : (gint32)read32(ip));
9881                         ip += opsize;
9882
9883                         sp--;
9884
9885                         GET_BBLOCK (cfg, tblock, target);
9886                         link_bblock (cfg, cfg->cbb, tblock);
9887                         GET_BBLOCK (cfg, tblock, ip);
9888                         link_bblock (cfg, cfg->cbb, tblock);
9889
9890                         if (sp != stack_start) {
9891                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9892                                 CHECK_UNVERIFIABLE (cfg);
9893                         }
9894
9895                         MONO_INST_NEW(cfg, cmp, OP_ICOMPARE_IMM);
9896                         cmp->sreg1 = sp [0]->dreg;
9897                         type_from_op (cfg, cmp, sp [0], NULL);
9898                         CHECK_TYPE (cmp);
9899
9900 #if SIZEOF_REGISTER == 4
9901                         if (cmp->opcode == OP_LCOMPARE_IMM) {
9902                                 /* Convert it to OP_LCOMPARE */
9903                                 MONO_INST_NEW (cfg, ins, OP_I8CONST);
9904                                 ins->type = STACK_I8;
9905                                 ins->dreg = alloc_dreg (cfg, STACK_I8);
9906                                 ins->inst_l = 0;
9907                                 MONO_ADD_INS (cfg->cbb, ins);
9908                                 cmp->opcode = OP_LCOMPARE;
9909                                 cmp->sreg2 = ins->dreg;
9910                         }
9911 #endif
9912                         MONO_ADD_INS (cfg->cbb, cmp);
9913
9914                         MONO_INST_NEW (cfg, ins, is_true ? CEE_BNE_UN : CEE_BEQ);
9915                         type_from_op (cfg, ins, sp [0], NULL);
9916                         MONO_ADD_INS (cfg->cbb, ins);
9917                         ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);
9918                         GET_BBLOCK (cfg, tblock, target);
9919                         ins->inst_true_bb = tblock;
9920                         GET_BBLOCK (cfg, tblock, ip);
9921                         ins->inst_false_bb = tblock;
9922                         start_new_bblock = 2;
9923
9924                         sp = stack_start;
9925                         inline_costs += BRANCH_COST;
9926                         break;
9927                 }
9928                 case CEE_BEQ:
9929                 case CEE_BGE:
9930                 case CEE_BGT:
9931                 case CEE_BLE:
9932                 case CEE_BLT:
9933                 case CEE_BNE_UN:
9934                 case CEE_BGE_UN:
9935                 case CEE_BGT_UN:
9936                 case CEE_BLE_UN:
9937                 case CEE_BLT_UN:
9938                         CHECK_OPSIZE (5);
9939                         CHECK_STACK (2);
9940                         MONO_INST_NEW (cfg, ins, *ip);
9941                         ip++;
9942                         target = ip + 4 + (gint32)read32(ip);
9943                         ip += 4;
9944
9945                         ADD_BINCOND (NULL);
9946
9947                         sp = stack_start;
9948                         inline_costs += BRANCH_COST;
9949                         break;
9950                 case CEE_SWITCH: {
9951                         MonoInst *src1;
9952                         MonoBasicBlock **targets;
9953                         MonoBasicBlock *default_bblock;
9954                         MonoJumpInfoBBTable *table;
9955                         int offset_reg = alloc_preg (cfg);
9956                         int target_reg = alloc_preg (cfg);
9957                         int table_reg = alloc_preg (cfg);
9958                         int sum_reg = alloc_preg (cfg);
9959                         gboolean use_op_switch;
9960
9961                         CHECK_OPSIZE (5);
9962                         CHECK_STACK (1);
9963                         n = read32 (ip + 1);
9964                         --sp;
9965                         src1 = sp [0];
9966                         if ((src1->type != STACK_I4) && (src1->type != STACK_PTR)) 
9967                                 UNVERIFIED;
9968
9969                         ip += 5;
9970                         CHECK_OPSIZE (n * sizeof (guint32));
9971                         target = ip + n * sizeof (guint32);
9972
9973                         GET_BBLOCK (cfg, default_bblock, target);
9974                         default_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
9975
9976                         targets = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * n);
9977                         for (i = 0; i < n; ++i) {
9978                                 GET_BBLOCK (cfg, tblock, target + (gint32)read32(ip));
9979                                 targets [i] = tblock;
9980                                 targets [i]->flags |= BB_INDIRECT_JUMP_TARGET;
9981                                 ip += 4;
9982                         }
9983
9984                         if (sp != stack_start) {
9985                                 /* 
9986                                  * Link the current bb with the targets as well, so handle_stack_args
9987                                  * will set their in_stack correctly.
9988                                  */
9989                                 link_bblock (cfg, cfg->cbb, default_bblock);
9990                                 for (i = 0; i < n; ++i)
9991                                         link_bblock (cfg, cfg->cbb, targets [i]);
9992
9993                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9994                                 sp = stack_start;
9995                                 CHECK_UNVERIFIABLE (cfg);
9996
9997                                 /* Undo the links */
9998                                 mono_unlink_bblock (cfg, cfg->cbb, default_bblock);
9999                                 for (i = 0; i < n; ++i)
10000                                         mono_unlink_bblock (cfg, cfg->cbb, targets [i]);
10001                         }
10002
10003                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, src1->dreg, n);
10004                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBGE_UN, default_bblock);
10005
10006                         for (i = 0; i < n; ++i)
10007                                 link_bblock (cfg, cfg->cbb, targets [i]);
10008
10009                         table = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
10010                         table->table = targets;
10011                         table->table_size = n;
10012
10013                         use_op_switch = FALSE;
10014 #ifdef TARGET_ARM
10015                         /* ARM implements SWITCH statements differently */
10016                         /* FIXME: Make it use the generic implementation */
10017                         if (!cfg->compile_aot)
10018                                 use_op_switch = TRUE;
10019 #endif
10020
10021                         if (COMPILE_LLVM (cfg))
10022                                 use_op_switch = TRUE;
10023
10024                         cfg->cbb->has_jump_table = 1;
10025
10026                         if (use_op_switch) {
10027                                 MONO_INST_NEW (cfg, ins, OP_SWITCH);
10028                                 ins->sreg1 = src1->dreg;
10029                                 ins->inst_p0 = table;
10030                                 ins->inst_many_bb = targets;
10031                                 ins->klass = GUINT_TO_POINTER (n);
10032                                 MONO_ADD_INS (cfg->cbb, ins);
10033                         } else {
10034                                 if (sizeof (gpointer) == 8)
10035                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 3);
10036                                 else
10037                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 2);
10038
10039 #if SIZEOF_REGISTER == 8
10040                                 /* The upper word might not be zero, and we add it to a 64 bit address later */
10041                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, offset_reg, offset_reg);
10042 #endif
10043
10044                                 if (cfg->compile_aot) {
10045                                         MONO_EMIT_NEW_AOTCONST (cfg, table_reg, table, MONO_PATCH_INFO_SWITCH);
10046                                 } else {
10047                                         MONO_INST_NEW (cfg, ins, OP_JUMP_TABLE);
10048                                         ins->inst_c1 = MONO_PATCH_INFO_SWITCH;
10049                                         ins->inst_p0 = table;
10050                                         ins->dreg = table_reg;
10051                                         MONO_ADD_INS (cfg->cbb, ins);
10052                                 }
10053
10054                                 /* FIXME: Use load_memindex */
10055                                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, table_reg, offset_reg);
10056                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, target_reg, sum_reg, 0);
10057                                 MONO_EMIT_NEW_UNALU (cfg, OP_BR_REG, -1, target_reg);
10058                         }
10059                         start_new_bblock = 1;
10060                         inline_costs += (BRANCH_COST * 2);
10061                         break;
10062                 }
10063                 case CEE_LDIND_I1:
10064                 case CEE_LDIND_U1:
10065                 case CEE_LDIND_I2:
10066                 case CEE_LDIND_U2:
10067                 case CEE_LDIND_I4:
10068                 case CEE_LDIND_U4:
10069                 case CEE_LDIND_I8:
10070                 case CEE_LDIND_I:
10071                 case CEE_LDIND_R4:
10072                 case CEE_LDIND_R8:
10073                 case CEE_LDIND_REF:
10074                         CHECK_STACK (1);
10075                         --sp;
10076
10077                         switch (*ip) {
10078                         case CEE_LDIND_R4:
10079                         case CEE_LDIND_R8:
10080                                 dreg = alloc_freg (cfg);
10081                                 break;
10082                         case CEE_LDIND_I8:
10083                                 dreg = alloc_lreg (cfg);
10084                                 break;
10085                         case CEE_LDIND_REF:
10086                                 dreg = alloc_ireg_ref (cfg);
10087                                 break;
10088                         default:
10089                                 dreg = alloc_preg (cfg);
10090                         }
10091
10092                         NEW_LOAD_MEMBASE (cfg, ins, ldind_to_load_membase (*ip), dreg, sp [0]->dreg, 0);
10093                         ins->type = ldind_type [*ip - CEE_LDIND_I1];
10094                         if (*ip == CEE_LDIND_R4)
10095                                 ins->type = cfg->r4_stack_type;
10096                         ins->flags |= ins_flag;
10097                         MONO_ADD_INS (cfg->cbb, ins);
10098                         *sp++ = ins;
10099                         if (ins_flag & MONO_INST_VOLATILE) {
10100                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10101                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10102                         }
10103                         ins_flag = 0;
10104                         ++ip;
10105                         break;
10106                 case CEE_STIND_REF:
10107                 case CEE_STIND_I1:
10108                 case CEE_STIND_I2:
10109                 case CEE_STIND_I4:
10110                 case CEE_STIND_I8:
10111                 case CEE_STIND_R4:
10112                 case CEE_STIND_R8:
10113                 case CEE_STIND_I:
10114                         CHECK_STACK (2);
10115                         sp -= 2;
10116
10117                         if (ins_flag & MONO_INST_VOLATILE) {
10118                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
10119                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
10120                         }
10121
10122                         NEW_STORE_MEMBASE (cfg, ins, stind_to_store_membase (*ip), sp [0]->dreg, 0, sp [1]->dreg);
10123                         ins->flags |= ins_flag;
10124                         ins_flag = 0;
10125
10126                         MONO_ADD_INS (cfg->cbb, ins);
10127
10128                         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)))
10129                                 emit_write_barrier (cfg, sp [0], sp [1]);
10130
10131                         inline_costs += 1;
10132                         ++ip;
10133                         break;
10134
10135                 case CEE_MUL:
10136                         CHECK_STACK (2);
10137
10138                         MONO_INST_NEW (cfg, ins, (*ip));
10139                         sp -= 2;
10140                         ins->sreg1 = sp [0]->dreg;
10141                         ins->sreg2 = sp [1]->dreg;
10142                         type_from_op (cfg, ins, sp [0], sp [1]);
10143                         CHECK_TYPE (ins);
10144                         ins->dreg = alloc_dreg ((cfg), (ins)->type);
10145
10146                         /* Use the immediate opcodes if possible */
10147                         if ((sp [1]->opcode == OP_ICONST) && mono_arch_is_inst_imm (sp [1]->inst_c0)) {
10148                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
10149                                 if (imm_opcode != -1) {
10150                                         ins->opcode = imm_opcode;
10151                                         ins->inst_p1 = (gpointer)(gssize)(sp [1]->inst_c0);
10152                                         ins->sreg2 = -1;
10153
10154                                         NULLIFY_INS (sp [1]);
10155                                 }
10156                         }
10157
10158                         MONO_ADD_INS ((cfg)->cbb, (ins));
10159
10160                         *sp++ = mono_decompose_opcode (cfg, ins);
10161                         ip++;
10162                         break;
10163                 case CEE_ADD:
10164                 case CEE_SUB:
10165                 case CEE_DIV:
10166                 case CEE_DIV_UN:
10167                 case CEE_REM:
10168                 case CEE_REM_UN:
10169                 case CEE_AND:
10170                 case CEE_OR:
10171                 case CEE_XOR:
10172                 case CEE_SHL:
10173                 case CEE_SHR:
10174                 case CEE_SHR_UN:
10175                         CHECK_STACK (2);
10176
10177                         MONO_INST_NEW (cfg, ins, (*ip));
10178                         sp -= 2;
10179                         ins->sreg1 = sp [0]->dreg;
10180                         ins->sreg2 = sp [1]->dreg;
10181                         type_from_op (cfg, ins, sp [0], sp [1]);
10182                         CHECK_TYPE (ins);
10183                         add_widen_op (cfg, ins, &sp [0], &sp [1]);
10184                         ins->dreg = alloc_dreg ((cfg), (ins)->type);
10185
10186                         /* FIXME: Pass opcode to is_inst_imm */
10187
10188                         /* Use the immediate opcodes if possible */
10189                         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)) {
10190                                 int imm_opcode;
10191
10192                                 imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
10193 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
10194                                 /* Keep emulated opcodes which are optimized away later */
10195                                 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) {
10196                                         imm_opcode = mono_op_to_op_imm (ins->opcode);
10197                                 }
10198 #endif
10199                                 if (imm_opcode != -1) {
10200                                         ins->opcode = imm_opcode;
10201                                         if (sp [1]->opcode == OP_I8CONST) {
10202 #if SIZEOF_REGISTER == 8
10203                                                 ins->inst_imm = sp [1]->inst_l;
10204 #else
10205                                                 ins->inst_ls_word = sp [1]->inst_ls_word;
10206                                                 ins->inst_ms_word = sp [1]->inst_ms_word;
10207 #endif
10208                                         }
10209                                         else
10210                                                 ins->inst_imm = (gssize)(sp [1]->inst_c0);
10211                                         ins->sreg2 = -1;
10212
10213                                         /* Might be followed by an instruction added by add_widen_op */
10214                                         if (sp [1]->next == NULL)
10215                                                 NULLIFY_INS (sp [1]);
10216                                 }
10217                         }
10218                         MONO_ADD_INS ((cfg)->cbb, (ins));
10219
10220                         *sp++ = mono_decompose_opcode (cfg, ins);
10221                         ip++;
10222                         break;
10223                 case CEE_NEG:
10224                 case CEE_NOT:
10225                 case CEE_CONV_I1:
10226                 case CEE_CONV_I2:
10227                 case CEE_CONV_I4:
10228                 case CEE_CONV_R4:
10229                 case CEE_CONV_R8:
10230                 case CEE_CONV_U4:
10231                 case CEE_CONV_I8:
10232                 case CEE_CONV_U8:
10233                 case CEE_CONV_OVF_I8:
10234                 case CEE_CONV_OVF_U8:
10235                 case CEE_CONV_R_UN:
10236                         CHECK_STACK (1);
10237
10238                         /* Special case this earlier so we have long constants in the IR */
10239                         if ((((*ip) == CEE_CONV_I8) || ((*ip) == CEE_CONV_U8)) && (sp [-1]->opcode == OP_ICONST)) {
10240                                 int data = sp [-1]->inst_c0;
10241                                 sp [-1]->opcode = OP_I8CONST;
10242                                 sp [-1]->type = STACK_I8;
10243 #if SIZEOF_REGISTER == 8
10244                                 if ((*ip) == CEE_CONV_U8)
10245                                         sp [-1]->inst_c0 = (guint32)data;
10246                                 else
10247                                         sp [-1]->inst_c0 = data;
10248 #else
10249                                 sp [-1]->inst_ls_word = data;
10250                                 if ((*ip) == CEE_CONV_U8)
10251                                         sp [-1]->inst_ms_word = 0;
10252                                 else
10253                                         sp [-1]->inst_ms_word = (data < 0) ? -1 : 0;
10254 #endif
10255                                 sp [-1]->dreg = alloc_dreg (cfg, STACK_I8);
10256                         }
10257                         else {
10258                                 ADD_UNOP (*ip);
10259                         }
10260                         ip++;
10261                         break;
10262                 case CEE_CONV_OVF_I4:
10263                 case CEE_CONV_OVF_I1:
10264                 case CEE_CONV_OVF_I2:
10265                 case CEE_CONV_OVF_I:
10266                 case CEE_CONV_OVF_U:
10267                         CHECK_STACK (1);
10268
10269                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
10270                                 ADD_UNOP (CEE_CONV_OVF_I8);
10271                                 ADD_UNOP (*ip);
10272                         } else {
10273                                 ADD_UNOP (*ip);
10274                         }
10275                         ip++;
10276                         break;
10277                 case CEE_CONV_OVF_U1:
10278                 case CEE_CONV_OVF_U2:
10279                 case CEE_CONV_OVF_U4:
10280                         CHECK_STACK (1);
10281
10282                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
10283                                 ADD_UNOP (CEE_CONV_OVF_U8);
10284                                 ADD_UNOP (*ip);
10285                         } else {
10286                                 ADD_UNOP (*ip);
10287                         }
10288                         ip++;
10289                         break;
10290                 case CEE_CONV_OVF_I1_UN:
10291                 case CEE_CONV_OVF_I2_UN:
10292                 case CEE_CONV_OVF_I4_UN:
10293                 case CEE_CONV_OVF_I8_UN:
10294                 case CEE_CONV_OVF_U1_UN:
10295                 case CEE_CONV_OVF_U2_UN:
10296                 case CEE_CONV_OVF_U4_UN:
10297                 case CEE_CONV_OVF_U8_UN:
10298                 case CEE_CONV_OVF_I_UN:
10299                 case CEE_CONV_OVF_U_UN:
10300                 case CEE_CONV_U2:
10301                 case CEE_CONV_U1:
10302                 case CEE_CONV_I:
10303                 case CEE_CONV_U:
10304                         CHECK_STACK (1);
10305                         ADD_UNOP (*ip);
10306                         CHECK_CFG_EXCEPTION;
10307                         ip++;
10308                         break;
10309                 case CEE_ADD_OVF:
10310                 case CEE_ADD_OVF_UN:
10311                 case CEE_MUL_OVF:
10312                 case CEE_MUL_OVF_UN:
10313                 case CEE_SUB_OVF:
10314                 case CEE_SUB_OVF_UN:
10315                         CHECK_STACK (2);
10316                         ADD_BINOP (*ip);
10317                         ip++;
10318                         break;
10319                 case CEE_CPOBJ:
10320                         GSHAREDVT_FAILURE (*ip);
10321                         CHECK_OPSIZE (5);
10322                         CHECK_STACK (2);
10323                         token = read32 (ip + 1);
10324                         klass = mini_get_class (method, token, generic_context);
10325                         CHECK_TYPELOAD (klass);
10326                         sp -= 2;
10327                         if (generic_class_is_reference_type (cfg, klass)) {
10328                                 MonoInst *store, *load;
10329                                 int dreg = alloc_ireg_ref (cfg);
10330
10331                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, dreg, sp [1]->dreg, 0);
10332                                 load->flags |= ins_flag;
10333                                 MONO_ADD_INS (cfg->cbb, load);
10334
10335                                 NEW_STORE_MEMBASE (cfg, store, OP_STORE_MEMBASE_REG, sp [0]->dreg, 0, dreg);
10336                                 store->flags |= ins_flag;
10337                                 MONO_ADD_INS (cfg->cbb, store);
10338
10339                                 if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER)
10340                                         emit_write_barrier (cfg, sp [0], sp [1]);
10341                         } else {
10342                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
10343                         }
10344                         ins_flag = 0;
10345                         ip += 5;
10346                         break;
10347                 case CEE_LDOBJ: {
10348                         int loc_index = -1;
10349                         int stloc_len = 0;
10350
10351                         CHECK_OPSIZE (5);
10352                         CHECK_STACK (1);
10353                         --sp;
10354                         token = read32 (ip + 1);
10355                         klass = mini_get_class (method, token, generic_context);
10356                         CHECK_TYPELOAD (klass);
10357
10358                         /* Optimize the common ldobj+stloc combination */
10359                         switch (ip [5]) {
10360                         case CEE_STLOC_S:
10361                                 loc_index = ip [6];
10362                                 stloc_len = 2;
10363                                 break;
10364                         case CEE_STLOC_0:
10365                         case CEE_STLOC_1:
10366                         case CEE_STLOC_2:
10367                         case CEE_STLOC_3:
10368                                 loc_index = ip [5] - CEE_STLOC_0;
10369                                 stloc_len = 1;
10370                                 break;
10371                         default:
10372                                 break;
10373                         }
10374
10375                         if ((loc_index != -1) && ip_in_bb (cfg, cfg->cbb, ip + 5)) {
10376                                 CHECK_LOCAL (loc_index);
10377
10378                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10379                                 ins->dreg = cfg->locals [loc_index]->dreg;
10380                                 ins->flags |= ins_flag;
10381                                 ip += 5;
10382                                 ip += stloc_len;
10383                                 if (ins_flag & MONO_INST_VOLATILE) {
10384                                         /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10385                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10386                                 }
10387                                 ins_flag = 0;
10388                                 break;
10389                         }
10390
10391                         /* Optimize the ldobj+stobj combination */
10392                         /* The reference case ends up being a load+store anyway */
10393                         /* Skip this if the operation is volatile. */
10394                         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)) {
10395                                 CHECK_STACK (1);
10396
10397                                 sp --;
10398
10399                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
10400
10401                                 ip += 5 + 5;
10402                                 ins_flag = 0;
10403                                 break;
10404                         }
10405
10406                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10407                         ins->flags |= ins_flag;
10408                         *sp++ = ins;
10409
10410                         if (ins_flag & MONO_INST_VOLATILE) {
10411                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10412                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10413                         }
10414
10415                         ip += 5;
10416                         ins_flag = 0;
10417                         inline_costs += 1;
10418                         break;
10419                 }
10420                 case CEE_LDSTR:
10421                         CHECK_STACK_OVF (1);
10422                         CHECK_OPSIZE (5);
10423                         n = read32 (ip + 1);
10424
10425                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
10426                                 EMIT_NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
10427                                 ins->type = STACK_OBJ;
10428                                 *sp = ins;
10429                         }
10430                         else if (method->wrapper_type != MONO_WRAPPER_NONE) {
10431                                 MonoInst *iargs [1];
10432                                 char *str = mono_method_get_wrapper_data (method, n);
10433
10434                                 if (cfg->compile_aot)
10435                                         EMIT_NEW_LDSTRLITCONST (cfg, iargs [0], str);
10436                                 else
10437                                         EMIT_NEW_PCONST (cfg, iargs [0], str);
10438                                 *sp = mono_emit_jit_icall (cfg, mono_string_new_wrapper, iargs);
10439                         } else {
10440                                 if (cfg->opt & MONO_OPT_SHARED) {
10441                                         MonoInst *iargs [3];
10442
10443                                         if (cfg->compile_aot) {
10444                                                 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
10445                                         }
10446                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10447                                         EMIT_NEW_IMAGECONST (cfg, iargs [1], image);
10448                                         EMIT_NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
10449                                         *sp = mono_emit_jit_icall (cfg, mono_ldstr, iargs);
10450                                         mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
10451                                 } else {
10452                                         if (cfg->cbb->out_of_line) {
10453                                                 MonoInst *iargs [2];
10454
10455                                                 if (image == mono_defaults.corlib) {
10456                                                         /* 
10457                                                          * Avoid relocations in AOT and save some space by using a 
10458                                                          * version of helper_ldstr specialized to mscorlib.
10459                                                          */
10460                                                         EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (n));
10461                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr_mscorlib, iargs);
10462                                                 } else {
10463                                                         /* Avoid creating the string object */
10464                                                         EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
10465                                                         EMIT_NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n));
10466                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr, iargs);
10467                                                 }
10468                                         } 
10469                                         else
10470                                         if (cfg->compile_aot) {
10471                                                 NEW_LDSTRCONST (cfg, ins, image, n);
10472                                                 *sp = ins;
10473                                                 MONO_ADD_INS (cfg->cbb, ins);
10474                                         } 
10475                                         else {
10476                                                 NEW_PCONST (cfg, ins, NULL);
10477                                                 ins->type = STACK_OBJ;
10478                                                 ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
10479                                                 if (!ins->inst_p0)
10480                                                         OUT_OF_MEMORY_FAILURE;
10481
10482                                                 *sp = ins;
10483                                                 MONO_ADD_INS (cfg->cbb, ins);
10484                                         }
10485                                 }
10486                         }
10487
10488                         sp++;
10489                         ip += 5;
10490                         break;
10491                 case CEE_NEWOBJ: {
10492                         MonoInst *iargs [2];
10493                         MonoMethodSignature *fsig;
10494                         MonoInst this_ins;
10495                         MonoInst *alloc;
10496                         MonoInst *vtable_arg = NULL;
10497
10498                         CHECK_OPSIZE (5);
10499                         token = read32 (ip + 1);
10500                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
10501                         if (!cmethod || mono_loader_get_last_error ())
10502                                 LOAD_ERROR;
10503                         fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
10504                         CHECK_CFG_ERROR;
10505
10506                         mono_save_token_info (cfg, image, token, cmethod);
10507
10508                         if (!mono_class_init (cmethod->klass))
10509                                 TYPE_LOAD_ERROR (cmethod->klass);
10510
10511                         context_used = mini_method_check_context_used (cfg, cmethod);
10512
10513                         if (mono_security_core_clr_enabled ())
10514                                 ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
10515
10516                         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)) {
10517                                 emit_class_init (cfg, cmethod->klass);
10518                                 CHECK_TYPELOAD (cmethod->klass);
10519                         }
10520
10521                         /*
10522                         if (cfg->gsharedvt) {
10523                                 if (mini_is_gsharedvt_variable_signature (sig))
10524                                         GSHAREDVT_FAILURE (*ip);
10525                         }
10526                         */
10527
10528                         n = fsig->param_count;
10529                         CHECK_STACK (n);
10530
10531                         /* 
10532                          * Generate smaller code for the common newobj <exception> instruction in
10533                          * argument checking code.
10534                          */
10535                         if (cfg->cbb->out_of_line && cmethod->klass->image == mono_defaults.corlib &&
10536                                 is_exception_class (cmethod->klass) && n <= 2 &&
10537                                 ((n < 1) || (!fsig->params [0]->byref && fsig->params [0]->type == MONO_TYPE_STRING)) && 
10538                                 ((n < 2) || (!fsig->params [1]->byref && fsig->params [1]->type == MONO_TYPE_STRING))) {
10539                                 MonoInst *iargs [3];
10540
10541                                 sp -= n;
10542
10543                                 EMIT_NEW_ICONST (cfg, iargs [0], cmethod->klass->type_token);
10544                                 switch (n) {
10545                                 case 0:
10546                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_0, iargs);
10547                                         break;
10548                                 case 1:
10549                                         iargs [1] = sp [0];
10550                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_1, iargs);
10551                                         break;
10552                                 case 2:
10553                                         iargs [1] = sp [0];
10554                                         iargs [2] = sp [1];
10555                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_2, iargs);
10556                                         break;
10557                                 default:
10558                                         g_assert_not_reached ();
10559                                 }
10560
10561                                 ip += 5;
10562                                 inline_costs += 5;
10563                                 break;
10564                         }
10565
10566                         /* move the args to allow room for 'this' in the first position */
10567                         while (n--) {
10568                                 --sp;
10569                                 sp [1] = sp [0];
10570                         }
10571
10572                         /* check_call_signature () requires sp[0] to be set */
10573                         this_ins.type = STACK_OBJ;
10574                         sp [0] = &this_ins;
10575                         if (check_call_signature (cfg, fsig, sp))
10576                                 UNVERIFIED;
10577
10578                         iargs [0] = NULL;
10579
10580                         if (mini_class_is_system_array (cmethod->klass)) {
10581                                 *sp = emit_get_rgctx_method (cfg, context_used,
10582                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
10583
10584                                 /* Avoid varargs in the common case */
10585                                 if (fsig->param_count == 1)
10586                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_1, sp);
10587                                 else if (fsig->param_count == 2)
10588                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_2, sp);
10589                                 else if (fsig->param_count == 3)
10590                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_3, sp);
10591                                 else if (fsig->param_count == 4)
10592                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_4, sp);
10593                                 else
10594                                         alloc = handle_array_new (cfg, fsig->param_count, sp, ip);
10595                         } else if (cmethod->string_ctor) {
10596                                 g_assert (!context_used);
10597                                 g_assert (!vtable_arg);
10598                                 /* we simply pass a null pointer */
10599                                 EMIT_NEW_PCONST (cfg, *sp, NULL); 
10600                                 /* now call the string ctor */
10601                                 alloc = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, NULL, NULL, NULL);
10602                         } else {
10603                                 if (cmethod->klass->valuetype) {
10604                                         iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
10605                                         emit_init_rvar (cfg, iargs [0]->dreg, &cmethod->klass->byval_arg);
10606                                         EMIT_NEW_TEMPLOADA (cfg, *sp, iargs [0]->inst_c0);
10607
10608                                         alloc = NULL;
10609
10610                                         /* 
10611                                          * The code generated by mini_emit_virtual_call () expects
10612                                          * iargs [0] to be a boxed instance, but luckily the vcall
10613                                          * will be transformed into a normal call there.
10614                                          */
10615                                 } else if (context_used) {
10616                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, context_used);
10617                                         *sp = alloc;
10618                                 } else {
10619                                         MonoVTable *vtable = NULL;
10620
10621                                         if (!cfg->compile_aot)
10622                                                 vtable = mono_class_vtable (cfg->domain, cmethod->klass);
10623                                         CHECK_TYPELOAD (cmethod->klass);
10624
10625                                         /*
10626                                          * TypeInitializationExceptions thrown from the mono_runtime_class_init
10627                                          * call in mono_jit_runtime_invoke () can abort the finalizer thread.
10628                                          * As a workaround, we call class cctors before allocating objects.
10629                                          */
10630                                         if (mini_field_access_needs_cctor_run (cfg, method, cmethod->klass, vtable) && !(g_slist_find (class_inits, cmethod->klass))) {
10631                                                 emit_class_init (cfg, cmethod->klass);
10632                                                 if (cfg->verbose_level > 2)
10633                                                         printf ("class %s.%s needs init call for ctor\n", cmethod->klass->name_space, cmethod->klass->name);
10634                                                 class_inits = g_slist_prepend (class_inits, cmethod->klass);
10635                                         }
10636
10637                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, 0);
10638                                         *sp = alloc;
10639                                 }
10640                                 CHECK_CFG_EXCEPTION; /*for handle_alloc*/
10641
10642                                 if (alloc)
10643                                         MONO_EMIT_NEW_UNALU (cfg, OP_NOT_NULL, -1, alloc->dreg);
10644
10645                                 /* Now call the actual ctor */
10646                                 handle_ctor_call (cfg, cmethod, fsig, context_used, sp, ip, &inline_costs);
10647                                 CHECK_CFG_EXCEPTION;
10648                         }
10649
10650                         if (alloc == NULL) {
10651                                 /* Valuetype */
10652                                 EMIT_NEW_TEMPLOAD (cfg, ins, iargs [0]->inst_c0);
10653                                 type_to_eval_stack_type (cfg, &ins->klass->byval_arg, ins);
10654                                 *sp++= ins;
10655                         } else {
10656                                 *sp++ = alloc;
10657                         }
10658                         
10659                         ip += 5;
10660                         inline_costs += 5;
10661                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip - header->code)))
10662                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
10663                         break;
10664                 }
10665                 case CEE_CASTCLASS:
10666                         CHECK_STACK (1);
10667                         --sp;
10668                         CHECK_OPSIZE (5);
10669                         token = read32 (ip + 1);
10670                         klass = mini_get_class (method, token, generic_context);
10671                         CHECK_TYPELOAD (klass);
10672                         if (sp [0]->type != STACK_OBJ)
10673                                 UNVERIFIED;
10674
10675                         ins = handle_castclass (cfg, klass, *sp, ip, &inline_costs);
10676                         CHECK_CFG_EXCEPTION;
10677
10678                         *sp ++ = ins;
10679                         ip += 5;
10680                         break;
10681                 case CEE_ISINST: {
10682                         CHECK_STACK (1);
10683                         --sp;
10684                         CHECK_OPSIZE (5);
10685                         token = read32 (ip + 1);
10686                         klass = mini_get_class (method, token, generic_context);
10687                         CHECK_TYPELOAD (klass);
10688                         if (sp [0]->type != STACK_OBJ)
10689                                 UNVERIFIED;
10690  
10691                         context_used = mini_class_check_context_used (cfg, klass);
10692
10693                         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
10694                                 MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
10695                                 MonoInst *args [3];
10696                                 int idx;
10697
10698                                 /* obj */
10699                                 args [0] = *sp;
10700
10701                                 /* klass */
10702                                 EMIT_NEW_CLASSCONST (cfg, args [1], klass);
10703
10704                                 /* inline cache*/
10705                                 idx = get_castclass_cache_idx (cfg);
10706                                 args [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
10707
10708                                 *sp++ = mono_emit_method_call (cfg, mono_isinst, args, NULL);
10709                                 ip += 5;
10710                                 inline_costs += 2;
10711                         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
10712                                 MonoMethod *mono_isinst;
10713                                 MonoInst *iargs [1];
10714                                 int costs;
10715
10716                                 mono_isinst = mono_marshal_get_isinst (klass); 
10717                                 iargs [0] = sp [0];
10718
10719                                 costs = inline_method (cfg, mono_isinst, mono_method_signature (mono_isinst), 
10720                                                                            iargs, ip, cfg->real_offset, TRUE);
10721                                 CHECK_CFG_EXCEPTION;
10722                                 g_assert (costs > 0);
10723                                 
10724                                 ip += 5;
10725                                 cfg->real_offset += 5;
10726
10727                                 *sp++= iargs [0];
10728
10729                                 inline_costs += costs;
10730                         }
10731                         else {
10732                                 ins = handle_isinst (cfg, klass, *sp, context_used);
10733                                 CHECK_CFG_EXCEPTION;
10734                                 *sp ++ = ins;
10735                                 ip += 5;
10736                         }
10737                         break;
10738                 }
10739                 case CEE_UNBOX_ANY: {
10740                         MonoInst *res, *addr;
10741
10742                         CHECK_STACK (1);
10743                         --sp;
10744                         CHECK_OPSIZE (5);
10745                         token = read32 (ip + 1);
10746                         klass = mini_get_class (method, token, generic_context);
10747                         CHECK_TYPELOAD (klass);
10748
10749                         mono_save_token_info (cfg, image, token, klass);
10750
10751                         context_used = mini_class_check_context_used (cfg, klass);
10752
10753                         if (mini_is_gsharedvt_klass (klass)) {
10754                                 res = handle_unbox_gsharedvt (cfg, klass, *sp);
10755                                 inline_costs += 2;
10756                         } else if (generic_class_is_reference_type (cfg, klass)) {
10757                                 res = handle_castclass (cfg, klass, *sp, ip, &inline_costs);
10758                                 CHECK_CFG_EXCEPTION;
10759                         } else if (mono_class_is_nullable (klass)) {
10760                                 res = handle_unbox_nullable (cfg, *sp, klass, context_used);
10761                         } else {
10762                                 addr = handle_unbox (cfg, klass, sp, context_used);
10763                                 /* LDOBJ */
10764                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
10765                                 res = ins;
10766                                 inline_costs += 2;
10767                         }
10768
10769                         *sp ++ = res;
10770                         ip += 5;
10771                         break;
10772                 }
10773                 case CEE_BOX: {
10774                         MonoInst *val;
10775                         MonoClass *enum_class;
10776                         MonoMethod *has_flag;
10777
10778                         CHECK_STACK (1);
10779                         --sp;
10780                         val = *sp;
10781                         CHECK_OPSIZE (5);
10782                         token = read32 (ip + 1);
10783                         klass = mini_get_class (method, token, generic_context);
10784                         CHECK_TYPELOAD (klass);
10785
10786                         mono_save_token_info (cfg, image, token, klass);
10787
10788                         context_used = mini_class_check_context_used (cfg, klass);
10789
10790                         if (generic_class_is_reference_type (cfg, klass)) {
10791                                 *sp++ = val;
10792                                 ip += 5;
10793                                 break;
10794                         }
10795
10796                         if (klass == mono_defaults.void_class)
10797                                 UNVERIFIED;
10798                         if (target_type_is_incompatible (cfg, &klass->byval_arg, *sp))
10799                                 UNVERIFIED;
10800                         /* frequent check in generic code: box (struct), brtrue */
10801
10802                         /*
10803                          * Look for:
10804                          *
10805                          *   <push int/long ptr>
10806                          *   <push int/long>
10807                          *   box MyFlags
10808                          *   constrained. MyFlags
10809                          *   callvirt instace bool class [mscorlib] System.Enum::HasFlag (class [mscorlib] System.Enum)
10810                          *
10811                          * If we find this sequence and the operand types on box and constrained
10812                          * are equal, we can emit a specialized instruction sequence instead of
10813                          * the very slow HasFlag () call.
10814                          */
10815                         if ((cfg->opt & MONO_OPT_INTRINS) &&
10816                             /* Cheap checks first. */
10817                             ip + 5 + 6 + 5 < end &&
10818                             ip [5] == CEE_PREFIX1 &&
10819                             ip [6] == CEE_CONSTRAINED_ &&
10820                             ip [11] == CEE_CALLVIRT &&
10821                             ip_in_bb (cfg, cfg->cbb, ip + 5 + 6 + 5) &&
10822                             mono_class_is_enum (klass) &&
10823                             (enum_class = mini_get_class (method, read32 (ip + 7), generic_context)) &&
10824                             (has_flag = mini_get_method (cfg, method, read32 (ip + 12), NULL, generic_context)) &&
10825                             has_flag->klass == mono_defaults.enum_class &&
10826                             !strcmp (has_flag->name, "HasFlag") &&
10827                             has_flag->signature->hasthis &&
10828                             has_flag->signature->param_count == 1) {
10829                                 CHECK_TYPELOAD (enum_class);
10830
10831                                 if (enum_class == klass) {
10832                                         MonoInst *enum_this, *enum_flag;
10833
10834                                         ip += 5 + 6 + 5;
10835                                         --sp;
10836
10837                                         enum_this = sp [0];
10838                                         enum_flag = sp [1];
10839
10840                                         *sp++ = handle_enum_has_flag (cfg, klass, enum_this, enum_flag);
10841                                         break;
10842                                 }
10843                         }
10844
10845                         // FIXME: LLVM can't handle the inconsistent bb linking
10846                         if (!mono_class_is_nullable (klass) &&
10847                                 !mini_is_gsharedvt_klass (klass) &&
10848                                 ip + 5 < end && ip_in_bb (cfg, cfg->cbb, ip + 5) &&
10849                                 (ip [5] == CEE_BRTRUE || 
10850                                  ip [5] == CEE_BRTRUE_S ||
10851                                  ip [5] == CEE_BRFALSE ||
10852                                  ip [5] == CEE_BRFALSE_S)) {
10853                                 gboolean is_true = ip [5] == CEE_BRTRUE || ip [5] == CEE_BRTRUE_S;
10854                                 int dreg;
10855                                 MonoBasicBlock *true_bb, *false_bb;
10856
10857                                 ip += 5;
10858
10859                                 if (cfg->verbose_level > 3) {
10860                                         printf ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
10861                                         printf ("<box+brtrue opt>\n");
10862                                 }
10863
10864                                 switch (*ip) {
10865                                 case CEE_BRTRUE_S:
10866                                 case CEE_BRFALSE_S:
10867                                         CHECK_OPSIZE (2);
10868                                         ip++;
10869                                         target = ip + 1 + (signed char)(*ip);
10870                                         ip++;
10871                                         break;
10872                                 case CEE_BRTRUE:
10873                                 case CEE_BRFALSE:
10874                                         CHECK_OPSIZE (5);
10875                                         ip++;
10876                                         target = ip + 4 + (gint)(read32 (ip));
10877                                         ip += 4;
10878                                         break;
10879                                 default:
10880                                         g_assert_not_reached ();
10881                                 }
10882
10883                                 /* 
10884                                  * We need to link both bblocks, since it is needed for handling stack
10885                                  * arguments correctly (See test_0_box_brtrue_opt_regress_81102).
10886                                  * Branching to only one of them would lead to inconsistencies, so
10887                                  * generate an ICONST+BRTRUE, the branch opts will get rid of them.
10888                                  */
10889                                 GET_BBLOCK (cfg, true_bb, target);
10890                                 GET_BBLOCK (cfg, false_bb, ip);
10891
10892                                 mono_link_bblock (cfg, cfg->cbb, true_bb);
10893                                 mono_link_bblock (cfg, cfg->cbb, false_bb);
10894
10895                                 if (sp != stack_start) {
10896                                         handle_stack_args (cfg, stack_start, sp - stack_start);
10897                                         sp = stack_start;
10898                                         CHECK_UNVERIFIABLE (cfg);
10899                                 }
10900
10901                                 if (COMPILE_LLVM (cfg)) {
10902                                         dreg = alloc_ireg (cfg);
10903                                         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
10904                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, dreg, is_true ? 0 : 1);
10905
10906                                         MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, OP_IBEQ, true_bb, false_bb);
10907                                 } else {
10908                                         /* The JIT can't eliminate the iconst+compare */
10909                                         MONO_INST_NEW (cfg, ins, OP_BR);
10910                                         ins->inst_target_bb = is_true ? true_bb : false_bb;
10911                                         MONO_ADD_INS (cfg->cbb, ins);
10912                                 }
10913
10914                                 start_new_bblock = 1;
10915                                 break;
10916                         }
10917
10918                         *sp++ = handle_box (cfg, val, klass, context_used);
10919
10920                         CHECK_CFG_EXCEPTION;
10921                         ip += 5;
10922                         inline_costs += 1;
10923                         break;
10924                 }
10925                 case CEE_UNBOX: {
10926                         CHECK_STACK (1);
10927                         --sp;
10928                         CHECK_OPSIZE (5);
10929                         token = read32 (ip + 1);
10930                         klass = mini_get_class (method, token, generic_context);
10931                         CHECK_TYPELOAD (klass);
10932
10933                         mono_save_token_info (cfg, image, token, klass);
10934
10935                         context_used = mini_class_check_context_used (cfg, klass);
10936
10937                         if (mono_class_is_nullable (klass)) {
10938                                 MonoInst *val;
10939
10940                                 val = handle_unbox_nullable (cfg, *sp, klass, context_used);
10941                                 EMIT_NEW_VARLOADA (cfg, ins, get_vreg_to_inst (cfg, val->dreg), &val->klass->byval_arg);
10942
10943                                 *sp++= ins;
10944                         } else {
10945                                 ins = handle_unbox (cfg, klass, sp, context_used);
10946                                 *sp++ = ins;
10947                         }
10948                         ip += 5;
10949                         inline_costs += 2;
10950                         break;
10951                 }
10952                 case CEE_LDFLD:
10953                 case CEE_LDFLDA:
10954                 case CEE_STFLD:
10955                 case CEE_LDSFLD:
10956                 case CEE_LDSFLDA:
10957                 case CEE_STSFLD: {
10958                         MonoClassField *field;
10959 #ifndef DISABLE_REMOTING
10960                         int costs;
10961 #endif
10962                         guint foffset;
10963                         gboolean is_instance;
10964                         int op;
10965                         gpointer addr = NULL;
10966                         gboolean is_special_static;
10967                         MonoType *ftype;
10968                         MonoInst *store_val = NULL;
10969                         MonoInst *thread_ins;
10970
10971                         op = *ip;
10972                         is_instance = (op == CEE_LDFLD || op == CEE_LDFLDA || op == CEE_STFLD);
10973                         if (is_instance) {
10974                                 if (op == CEE_STFLD) {
10975                                         CHECK_STACK (2);
10976                                         sp -= 2;
10977                                         store_val = sp [1];
10978                                 } else {
10979                                         CHECK_STACK (1);
10980                                         --sp;
10981                                 }
10982                                 if (sp [0]->type == STACK_I4 || sp [0]->type == STACK_I8 || sp [0]->type == STACK_R8)
10983                                         UNVERIFIED;
10984                                 if (*ip != CEE_LDFLD && sp [0]->type == STACK_VTYPE)
10985                                         UNVERIFIED;
10986                         } else {
10987                                 if (op == CEE_STSFLD) {
10988                                         CHECK_STACK (1);
10989                                         sp--;
10990                                         store_val = sp [0];
10991                                 }
10992                         }
10993
10994                         CHECK_OPSIZE (5);
10995                         token = read32 (ip + 1);
10996                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
10997                                 field = mono_method_get_wrapper_data (method, token);
10998                                 klass = field->parent;
10999                         }
11000                         else {
11001                                 field = mono_field_from_token_checked (image, token, &klass, generic_context, &cfg->error);
11002                                 CHECK_CFG_ERROR;
11003                         }
11004                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
11005                                 FIELD_ACCESS_FAILURE (method, field);
11006                         mono_class_init (klass);
11007
11008                         /* if the class is Critical then transparent code cannot access it's fields */
11009                         if (!is_instance && mono_security_core_clr_enabled ())
11010                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
11011
11012                         /* XXX this is technically required but, so far (SL2), no [SecurityCritical] types (not many exists) have
11013                            any visible *instance* field  (in fact there's a single case for a static field in Marshal) XXX
11014                         if (mono_security_core_clr_enabled ())
11015                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
11016                         */
11017
11018                         ftype = mono_field_get_type (field);
11019
11020                         /*
11021                          * LDFLD etc. is usable on static fields as well, so convert those cases to
11022                          * the static case.
11023                          */
11024                         if (is_instance && ftype->attrs & FIELD_ATTRIBUTE_STATIC) {
11025                                 switch (op) {
11026                                 case CEE_LDFLD:
11027                                         op = CEE_LDSFLD;
11028                                         break;
11029                                 case CEE_STFLD:
11030                                         op = CEE_STSFLD;
11031                                         break;
11032                                 case CEE_LDFLDA:
11033                                         op = CEE_LDSFLDA;
11034                                         break;
11035                                 default:
11036                                         g_assert_not_reached ();
11037                                 }
11038                                 is_instance = FALSE;
11039                         }
11040
11041                         context_used = mini_class_check_context_used (cfg, klass);
11042
11043                         /* INSTANCE CASE */
11044
11045                         foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
11046                         if (op == CEE_STFLD) {
11047                                 if (target_type_is_incompatible (cfg, field->type, sp [1]))
11048                                         UNVERIFIED;
11049 #ifndef DISABLE_REMOTING
11050                                 if ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class) {
11051                                         MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type); 
11052                                         MonoInst *iargs [5];
11053
11054                                         GSHAREDVT_FAILURE (op);
11055
11056                                         iargs [0] = sp [0];
11057                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11058                                         EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
11059                                         EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : 
11060                                                     field->offset);
11061                                         iargs [4] = sp [1];
11062
11063                                         if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
11064                                                 costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), 
11065                                                                                            iargs, ip, cfg->real_offset, TRUE);
11066                                                 CHECK_CFG_EXCEPTION;
11067                                                 g_assert (costs > 0);
11068                                                       
11069                                                 cfg->real_offset += 5;
11070
11071                                                 inline_costs += costs;
11072                                         } else {
11073                                                 mono_emit_method_call (cfg, stfld_wrapper, iargs, NULL);
11074                                         }
11075                                 } else
11076 #endif
11077                                 {
11078                                         MonoInst *store;
11079
11080                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
11081
11082                                         if (mini_is_gsharedvt_klass (klass)) {
11083                                                 MonoInst *offset_ins;
11084
11085                                                 context_used = mini_class_check_context_used (cfg, klass);
11086
11087                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11088                                                 /* The value is offset by 1 */
11089                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
11090                                                 dreg = alloc_ireg_mp (cfg);
11091                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11092                                                 /* The decomposition will call mini_emit_stobj () which will emit a wbarrier if needed */
11093                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, dreg, 0, sp [1]->dreg);
11094                                         } else {
11095                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, sp [0]->dreg, foffset, sp [1]->dreg);
11096                                         }
11097                                         if (sp [0]->opcode != OP_LDADDR)
11098                                                 store->flags |= MONO_INST_FAULT;
11099
11100                                 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)) {
11101                                         /* insert call to write barrier */
11102                                         MonoInst *ptr;
11103                                         int dreg;
11104
11105                                         dreg = alloc_ireg_mp (cfg);
11106                                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
11107                                         emit_write_barrier (cfg, ptr, sp [1]);
11108                                 }
11109
11110                                         store->flags |= ins_flag;
11111                                 }
11112                                 ins_flag = 0;
11113                                 ip += 5;
11114                                 break;
11115                         }
11116
11117 #ifndef DISABLE_REMOTING
11118                         if (is_instance && ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class)) {
11119                                 MonoMethod *wrapper = (op == CEE_LDFLDA) ? mono_marshal_get_ldflda_wrapper (field->type) : mono_marshal_get_ldfld_wrapper (field->type); 
11120                                 MonoInst *iargs [4];
11121
11122                                 GSHAREDVT_FAILURE (op);
11123
11124                                 iargs [0] = sp [0];
11125                                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11126                                 EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
11127                                 EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
11128                                 if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
11129                                         costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), 
11130                                                                                    iargs, ip, cfg->real_offset, TRUE);
11131                                         CHECK_CFG_EXCEPTION;
11132                                         g_assert (costs > 0);
11133                                                       
11134                                         cfg->real_offset += 5;
11135
11136                                         *sp++ = iargs [0];
11137
11138                                         inline_costs += costs;
11139                                 } else {
11140                                         ins = mono_emit_method_call (cfg, wrapper, iargs, NULL);
11141                                         *sp++ = ins;
11142                                 }
11143                         } else 
11144 #endif
11145                         if (is_instance) {
11146                                 if (sp [0]->type == STACK_VTYPE) {
11147                                         MonoInst *var;
11148
11149                                         /* Have to compute the address of the variable */
11150
11151                                         var = get_vreg_to_inst (cfg, sp [0]->dreg);
11152                                         if (!var)
11153                                                 var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, sp [0]->dreg);
11154                                         else
11155                                                 g_assert (var->klass == klass);
11156                                         
11157                                         EMIT_NEW_VARLOADA (cfg, ins, var, &var->klass->byval_arg);
11158                                         sp [0] = ins;
11159                                 }
11160
11161                                 if (op == CEE_LDFLDA) {
11162                                         if (sp [0]->type == STACK_OBJ) {
11163                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
11164                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "NullReferenceException");
11165                                         }
11166
11167                                         dreg = alloc_ireg_mp (cfg);
11168
11169                                         if (mini_is_gsharedvt_klass (klass)) {
11170                                                 MonoInst *offset_ins;
11171
11172                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11173                                                 /* The value is offset by 1 */
11174                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
11175                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11176                                         } else {
11177                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
11178                                         }
11179                                         ins->klass = mono_class_from_mono_type (field->type);
11180                                         ins->type = STACK_MP;
11181                                         *sp++ = ins;
11182                                 } else {
11183                                         MonoInst *load;
11184
11185                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
11186
11187                                         if (mini_is_gsharedvt_klass (klass)) {
11188                                                 MonoInst *offset_ins;
11189
11190                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11191                                                 /* The value is offset by 1 */
11192                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
11193                                                 dreg = alloc_ireg_mp (cfg);
11194                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11195                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, dreg, 0);
11196                                         } else {
11197                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, sp [0]->dreg, foffset);
11198                                         }
11199                                         load->flags |= ins_flag;
11200                                         if (sp [0]->opcode != OP_LDADDR)
11201                                                 load->flags |= MONO_INST_FAULT;
11202                                         *sp++ = load;
11203                                 }
11204                         }
11205
11206                         if (is_instance) {
11207                                 ins_flag = 0;
11208                                 ip += 5;
11209                                 break;
11210                         }
11211
11212                         /* STATIC CASE */
11213                         context_used = mini_class_check_context_used (cfg, klass);
11214
11215                         if (ftype->attrs & FIELD_ATTRIBUTE_LITERAL)
11216                                 UNVERIFIED;
11217
11218                         /* The special_static_fields field is init'd in mono_class_vtable, so it needs
11219                          * to be called here.
11220                          */
11221                         if (!context_used && !(cfg->opt & MONO_OPT_SHARED)) {
11222                                 mono_class_vtable (cfg->domain, klass);
11223                                 CHECK_TYPELOAD (klass);
11224                         }
11225                         mono_domain_lock (cfg->domain);
11226                         if (cfg->domain->special_static_fields)
11227                                 addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
11228                         mono_domain_unlock (cfg->domain);
11229
11230                         is_special_static = mono_class_field_is_special_static (field);
11231
11232                         if (is_special_static && ((gsize)addr & 0x80000000) == 0)
11233                                 thread_ins = mono_get_thread_intrinsic (cfg);
11234                         else
11235                                 thread_ins = NULL;
11236
11237                         /* Generate IR to compute the field address */
11238                         if (is_special_static && ((gsize)addr & 0x80000000) == 0 && thread_ins && !(cfg->opt & MONO_OPT_SHARED) && !context_used) {
11239                                 /*
11240                                  * Fast access to TLS data
11241                                  * Inline version of get_thread_static_data () in
11242                                  * threads.c.
11243                                  */
11244                                 guint32 offset;
11245                                 int idx, static_data_reg, array_reg, dreg;
11246
11247                                 GSHAREDVT_FAILURE (op);
11248
11249                                 MONO_ADD_INS (cfg->cbb, thread_ins);
11250                                 static_data_reg = alloc_ireg (cfg);
11251                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, MONO_STRUCT_OFFSET (MonoInternalThread, static_data));
11252
11253                                 if (cfg->compile_aot) {
11254                                         int offset_reg, offset2_reg, idx_reg;
11255
11256                                         /* For TLS variables, this will return the TLS offset */
11257                                         EMIT_NEW_SFLDACONST (cfg, ins, field);
11258                                         offset_reg = ins->dreg;
11259                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset_reg, offset_reg, 0x7fffffff);
11260                                         idx_reg = alloc_ireg (cfg);
11261                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, idx_reg, offset_reg, 0x3f);
11262                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
11263                                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
11264                                         array_reg = alloc_ireg (cfg);
11265                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
11266                                         offset2_reg = alloc_ireg (cfg);
11267                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, offset2_reg, offset_reg, 6);
11268                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset2_reg, 0x1ffffff);
11269                                         dreg = alloc_ireg (cfg);
11270                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, array_reg, offset2_reg);
11271                                 } else {
11272                                         offset = (gsize)addr & 0x7fffffff;
11273                                         idx = offset & 0x3f;
11274
11275                                         array_reg = alloc_ireg (cfg);
11276                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, idx * sizeof (gpointer));
11277                                         dreg = alloc_ireg (cfg);
11278                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_ADD_IMM, dreg, array_reg, ((offset >> 6) & 0x1ffffff));
11279                                 }
11280                         } else if ((cfg->opt & MONO_OPT_SHARED) ||
11281                                         (cfg->compile_aot && is_special_static) ||
11282                                         (context_used && is_special_static)) {
11283                                 MonoInst *iargs [2];
11284
11285                                 g_assert (field->parent);
11286                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11287                                 if (context_used) {
11288                                         iargs [1] = emit_get_rgctx_field (cfg, context_used,
11289                                                 field, MONO_RGCTX_INFO_CLASS_FIELD);
11290                                 } else {
11291                                         EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
11292                                 }
11293                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
11294                         } else if (context_used) {
11295                                 MonoInst *static_data;
11296
11297                                 /*
11298                                 g_print ("sharing static field access in %s.%s.%s - depth %d offset %d\n",
11299                                         method->klass->name_space, method->klass->name, method->name,
11300                                         depth, field->offset);
11301                                 */
11302
11303                                 if (mono_class_needs_cctor_run (klass, method))
11304                                         emit_class_init (cfg, klass);
11305
11306                                 /*
11307                                  * The pointer we're computing here is
11308                                  *
11309                                  *   super_info.static_data + field->offset
11310                                  */
11311                                 static_data = emit_get_rgctx_klass (cfg, context_used,
11312                                         klass, MONO_RGCTX_INFO_STATIC_DATA);
11313
11314                                 if (mini_is_gsharedvt_klass (klass)) {
11315                                         MonoInst *offset_ins;
11316
11317                                         offset_ins = emit_get_rgctx_field (cfg, context_used, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11318                                         /* The value is offset by 1 */
11319                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
11320                                         dreg = alloc_ireg_mp (cfg);
11321                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, static_data->dreg, offset_ins->dreg);
11322                                 } else if (field->offset == 0) {
11323                                         ins = static_data;
11324                                 } else {
11325                                         int addr_reg = mono_alloc_preg (cfg);
11326                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, addr_reg, static_data->dreg, field->offset);
11327                                 }
11328                                 } else if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
11329                                 MonoInst *iargs [2];
11330
11331                                 g_assert (field->parent);
11332                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11333                                 EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
11334                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
11335                         } else {
11336                                 MonoVTable *vtable = NULL;
11337
11338                                 if (!cfg->compile_aot)
11339                                         vtable = mono_class_vtable (cfg->domain, klass);
11340                                 CHECK_TYPELOAD (klass);
11341
11342                                 if (!addr) {
11343                                         if (mini_field_access_needs_cctor_run (cfg, method, klass, vtable)) {
11344                                                 if (!(g_slist_find (class_inits, klass))) {
11345                                                         emit_class_init (cfg, klass);
11346                                                         if (cfg->verbose_level > 2)
11347                                                                 printf ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, mono_field_get_name (field));
11348                                                         class_inits = g_slist_prepend (class_inits, klass);
11349                                                 }
11350                                         } else {
11351                                                 if (cfg->run_cctors) {
11352                                                         MonoException *ex;
11353                                                         /* This makes so that inline cannot trigger */
11354                                                         /* .cctors: too many apps depend on them */
11355                                                         /* running with a specific order... */
11356                                                         g_assert (vtable);
11357                                                         if (! vtable->initialized)
11358                                                                 INLINE_FAILURE ("class init");
11359                                                         ex = mono_runtime_class_init_full (vtable, FALSE);
11360                                                         if (ex) {
11361                                                                 set_exception_object (cfg, ex);
11362                                                                 goto exception_exit;
11363                                                         }
11364                                                 }
11365                                         }
11366                                         if (cfg->compile_aot)
11367                                                 EMIT_NEW_SFLDACONST (cfg, ins, field);
11368                                         else {
11369                                                 g_assert (vtable);
11370                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11371                                                 g_assert (addr);
11372                                                 EMIT_NEW_PCONST (cfg, ins, addr);
11373                                         }
11374                                 } else {
11375                                         MonoInst *iargs [1];
11376                                         EMIT_NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
11377                                         ins = mono_emit_jit_icall (cfg, mono_get_special_static_data, iargs);
11378                                 }
11379                         }
11380
11381                         /* Generate IR to do the actual load/store operation */
11382
11383                         if ((op == CEE_STFLD || op == CEE_STSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11384                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11385                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11386                         }
11387
11388                         if (op == CEE_LDSFLDA) {
11389                                 ins->klass = mono_class_from_mono_type (ftype);
11390                                 ins->type = STACK_PTR;
11391                                 *sp++ = ins;
11392                         } else if (op == CEE_STSFLD) {
11393                                 MonoInst *store;
11394
11395                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, ftype, ins->dreg, 0, store_val->dreg);
11396                                 store->flags |= ins_flag;
11397                         } else {
11398                                 gboolean is_const = FALSE;
11399                                 MonoVTable *vtable = NULL;
11400                                 gpointer addr = NULL;
11401
11402                                 if (!context_used) {
11403                                         vtable = mono_class_vtable (cfg->domain, klass);
11404                                         CHECK_TYPELOAD (klass);
11405                                 }
11406                                 if ((ftype->attrs & FIELD_ATTRIBUTE_INIT_ONLY) && (((addr = mono_aot_readonly_field_override (field)) != NULL) ||
11407                                                 (!context_used && !((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && vtable->initialized))) {
11408                                         int ro_type = ftype->type;
11409                                         if (!addr)
11410                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11411                                         if (ro_type == MONO_TYPE_VALUETYPE && ftype->data.klass->enumtype) {
11412                                                 ro_type = mono_class_enum_basetype (ftype->data.klass)->type;
11413                                         }
11414
11415                                         GSHAREDVT_FAILURE (op);
11416
11417                                         /* printf ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, mono_field_get_name (field));*/
11418                                         is_const = TRUE;
11419                                         switch (ro_type) {
11420                                         case MONO_TYPE_BOOLEAN:
11421                                         case MONO_TYPE_U1:
11422                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint8 *)addr));
11423                                                 sp++;
11424                                                 break;
11425                                         case MONO_TYPE_I1:
11426                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint8 *)addr));
11427                                                 sp++;
11428                                                 break;                                          
11429                                         case MONO_TYPE_CHAR:
11430                                         case MONO_TYPE_U2:
11431                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint16 *)addr));
11432                                                 sp++;
11433                                                 break;
11434                                         case MONO_TYPE_I2:
11435                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint16 *)addr));
11436                                                 sp++;
11437                                                 break;
11438                                                 break;
11439                                         case MONO_TYPE_I4:
11440                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint32 *)addr));
11441                                                 sp++;
11442                                                 break;                                          
11443                                         case MONO_TYPE_U4:
11444                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint32 *)addr));
11445                                                 sp++;
11446                                                 break;
11447                                         case MONO_TYPE_I:
11448                                         case MONO_TYPE_U:
11449                                         case MONO_TYPE_PTR:
11450                                         case MONO_TYPE_FNPTR:
11451                                                 EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11452                                                 type_to_eval_stack_type ((cfg), field->type, *sp);
11453                                                 sp++;
11454                                                 break;
11455                                         case MONO_TYPE_STRING:
11456                                         case MONO_TYPE_OBJECT:
11457                                         case MONO_TYPE_CLASS:
11458                                         case MONO_TYPE_SZARRAY:
11459                                         case MONO_TYPE_ARRAY:
11460                                                 if (!mono_gc_is_moving ()) {
11461                                                         EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11462                                                         type_to_eval_stack_type ((cfg), field->type, *sp);
11463                                                         sp++;
11464                                                 } else {
11465                                                         is_const = FALSE;
11466                                                 }
11467                                                 break;
11468                                         case MONO_TYPE_I8:
11469                                         case MONO_TYPE_U8:
11470                                                 EMIT_NEW_I8CONST (cfg, *sp, *((gint64 *)addr));
11471                                                 sp++;
11472                                                 break;
11473                                         case MONO_TYPE_R4:
11474                                         case MONO_TYPE_R8:
11475                                         case MONO_TYPE_VALUETYPE:
11476                                         default:
11477                                                 is_const = FALSE;
11478                                                 break;
11479                                         }
11480                                 }
11481
11482                                 if (!is_const) {
11483                                         MonoInst *load;
11484
11485                                         CHECK_STACK_OVF (1);
11486
11487                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, ins->dreg, 0);
11488                                         load->flags |= ins_flag;
11489                                         ins_flag = 0;
11490                                         *sp++ = load;
11491                                 }
11492                         }
11493
11494                         if ((op == CEE_LDFLD || op == CEE_LDSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11495                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
11496                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
11497                         }
11498
11499                         ins_flag = 0;
11500                         ip += 5;
11501                         break;
11502                 }
11503                 case CEE_STOBJ:
11504                         CHECK_STACK (2);
11505                         sp -= 2;
11506                         CHECK_OPSIZE (5);
11507                         token = read32 (ip + 1);
11508                         klass = mini_get_class (method, token, generic_context);
11509                         CHECK_TYPELOAD (klass);
11510                         if (ins_flag & MONO_INST_VOLATILE) {
11511                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11512                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11513                         }
11514                         /* FIXME: should check item at sp [1] is compatible with the type of the store. */
11515                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0, sp [1]->dreg);
11516                         ins->flags |= ins_flag;
11517                         if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER &&
11518                                         generic_class_is_reference_type (cfg, klass)) {
11519                                 /* insert call to write barrier */
11520                                 emit_write_barrier (cfg, sp [0], sp [1]);
11521                         }
11522                         ins_flag = 0;
11523                         ip += 5;
11524                         inline_costs += 1;
11525                         break;
11526
11527                         /*
11528                          * Array opcodes
11529                          */
11530                 case CEE_NEWARR: {
11531                         MonoInst *len_ins;
11532                         const char *data_ptr;
11533                         int data_size = 0;
11534                         guint32 field_token;
11535
11536                         CHECK_STACK (1);
11537                         --sp;
11538
11539                         CHECK_OPSIZE (5);
11540                         token = read32 (ip + 1);
11541
11542                         klass = mini_get_class (method, token, generic_context);
11543                         CHECK_TYPELOAD (klass);
11544
11545                         context_used = mini_class_check_context_used (cfg, klass);
11546
11547                         if (sp [0]->type == STACK_I8 || (SIZEOF_VOID_P == 8 && sp [0]->type == STACK_PTR)) {
11548                                 MONO_INST_NEW (cfg, ins, OP_LCONV_TO_OVF_U4);
11549                                 ins->sreg1 = sp [0]->dreg;
11550                                 ins->type = STACK_I4;
11551                                 ins->dreg = alloc_ireg (cfg);
11552                                 MONO_ADD_INS (cfg->cbb, ins);
11553                                 *sp = mono_decompose_opcode (cfg, ins);
11554                         }
11555
11556                         if (context_used) {
11557                                 MonoInst *args [3];
11558                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11559                                 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
11560
11561                                 /* FIXME: Use OP_NEWARR and decompose later to help abcrem */
11562
11563                                 /* vtable */
11564                                 args [0] = emit_get_rgctx_klass (cfg, context_used,
11565                                         array_class, MONO_RGCTX_INFO_VTABLE);
11566                                 /* array len */
11567                                 args [1] = sp [0];
11568
11569                                 if (managed_alloc)
11570                                         ins = mono_emit_method_call (cfg, managed_alloc, args, NULL);
11571                                 else
11572                                         ins = mono_emit_jit_icall (cfg, mono_array_new_specific, args);
11573                         } else {
11574                                 if (cfg->opt & MONO_OPT_SHARED) {
11575                                         /* Decompose now to avoid problems with references to the domainvar */
11576                                         MonoInst *iargs [3];
11577
11578                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11579                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11580                                         iargs [2] = sp [0];
11581
11582                                         ins = mono_emit_jit_icall (cfg, mono_array_new, iargs);
11583                                 } else {
11584                                         /* Decompose later since it is needed by abcrem */
11585                                         MonoClass *array_type = mono_array_class_get (klass, 1);
11586                                         mono_class_vtable (cfg->domain, array_type);
11587                                         CHECK_TYPELOAD (array_type);
11588
11589                                         MONO_INST_NEW (cfg, ins, OP_NEWARR);
11590                                         ins->dreg = alloc_ireg_ref (cfg);
11591                                         ins->sreg1 = sp [0]->dreg;
11592                                         ins->inst_newa_class = klass;
11593                                         ins->type = STACK_OBJ;
11594                                         ins->klass = array_type;
11595                                         MONO_ADD_INS (cfg->cbb, ins);
11596                                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11597                                         cfg->cbb->has_array_access = TRUE;
11598
11599                                         /* Needed so mono_emit_load_get_addr () gets called */
11600                                         mono_get_got_var (cfg);
11601                                 }
11602                         }
11603
11604                         len_ins = sp [0];
11605                         ip += 5;
11606                         *sp++ = ins;
11607                         inline_costs += 1;
11608
11609                         /* 
11610                          * we inline/optimize the initialization sequence if possible.
11611                          * we should also allocate the array as not cleared, since we spend as much time clearing to 0 as initializing
11612                          * for small sizes open code the memcpy
11613                          * ensure the rva field is big enough
11614                          */
11615                         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))) {
11616                                 MonoMethod *memcpy_method = get_memcpy_method ();
11617                                 MonoInst *iargs [3];
11618                                 int add_reg = alloc_ireg_mp (cfg);
11619
11620                                 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, add_reg, ins->dreg, MONO_STRUCT_OFFSET (MonoArray, vector));
11621                                 if (cfg->compile_aot) {
11622                                         EMIT_NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(field_token), STACK_PTR, NULL);
11623                                 } else {
11624                                         EMIT_NEW_PCONST (cfg, iargs [1], (char*)data_ptr);
11625                                 }
11626                                 EMIT_NEW_ICONST (cfg, iargs [2], data_size);
11627                                 mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
11628                                 ip += 11;
11629                         }
11630
11631                         break;
11632                 }
11633                 case CEE_LDLEN:
11634                         CHECK_STACK (1);
11635                         --sp;
11636                         if (sp [0]->type != STACK_OBJ)
11637                                 UNVERIFIED;
11638
11639                         MONO_INST_NEW (cfg, ins, OP_LDLEN);
11640                         ins->dreg = alloc_preg (cfg);
11641                         ins->sreg1 = sp [0]->dreg;
11642                         ins->type = STACK_I4;
11643                         /* This flag will be inherited by the decomposition */
11644                         ins->flags |= MONO_INST_FAULT;
11645                         MONO_ADD_INS (cfg->cbb, ins);
11646                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11647                         cfg->cbb->has_array_access = TRUE;
11648                         ip ++;
11649                         *sp++ = ins;
11650                         break;
11651                 case CEE_LDELEMA:
11652                         CHECK_STACK (2);
11653                         sp -= 2;
11654                         CHECK_OPSIZE (5);
11655                         if (sp [0]->type != STACK_OBJ)
11656                                 UNVERIFIED;
11657
11658                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11659
11660                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11661                         CHECK_TYPELOAD (klass);
11662                         /* we need to make sure that this array is exactly the type it needs
11663                          * to be for correctness. the wrappers are lax with their usage
11664                          * so we need to ignore them here
11665                          */
11666                         if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE && !readonly) {
11667                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11668                                 mini_emit_check_array_type (cfg, sp [0], array_class);
11669                                 CHECK_TYPELOAD (array_class);
11670                         }
11671
11672                         readonly = FALSE;
11673                         ins = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11674                         *sp++ = ins;
11675                         ip += 5;
11676                         break;
11677                 case CEE_LDELEM:
11678                 case CEE_LDELEM_I1:
11679                 case CEE_LDELEM_U1:
11680                 case CEE_LDELEM_I2:
11681                 case CEE_LDELEM_U2:
11682                 case CEE_LDELEM_I4:
11683                 case CEE_LDELEM_U4:
11684                 case CEE_LDELEM_I8:
11685                 case CEE_LDELEM_I:
11686                 case CEE_LDELEM_R4:
11687                 case CEE_LDELEM_R8:
11688                 case CEE_LDELEM_REF: {
11689                         MonoInst *addr;
11690
11691                         CHECK_STACK (2);
11692                         sp -= 2;
11693
11694                         if (*ip == CEE_LDELEM) {
11695                                 CHECK_OPSIZE (5);
11696                                 token = read32 (ip + 1);
11697                                 klass = mini_get_class (method, token, generic_context);
11698                                 CHECK_TYPELOAD (klass);
11699                                 mono_class_init (klass);
11700                         }
11701                         else
11702                                 klass = array_access_to_klass (*ip);
11703
11704                         if (sp [0]->type != STACK_OBJ)
11705                                 UNVERIFIED;
11706
11707                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11708
11709                         if (mini_is_gsharedvt_variable_klass (klass)) {
11710                                 // FIXME-VT: OP_ICONST optimization
11711                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11712                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11713                                 ins->opcode = OP_LOADV_MEMBASE;
11714                         } else if (sp [1]->opcode == OP_ICONST) {
11715                                 int array_reg = sp [0]->dreg;
11716                                 int index_reg = sp [1]->dreg;
11717                                 int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
11718
11719                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
11720                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset);
11721                         } else {
11722                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11723                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11724                         }
11725                         *sp++ = ins;
11726                         if (*ip == CEE_LDELEM)
11727                                 ip += 5;
11728                         else
11729                                 ++ip;
11730                         break;
11731                 }
11732                 case CEE_STELEM_I:
11733                 case CEE_STELEM_I1:
11734                 case CEE_STELEM_I2:
11735                 case CEE_STELEM_I4:
11736                 case CEE_STELEM_I8:
11737                 case CEE_STELEM_R4:
11738                 case CEE_STELEM_R8:
11739                 case CEE_STELEM_REF:
11740                 case CEE_STELEM: {
11741                         CHECK_STACK (3);
11742                         sp -= 3;
11743
11744                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11745
11746                         if (*ip == CEE_STELEM) {
11747                                 CHECK_OPSIZE (5);
11748                                 token = read32 (ip + 1);
11749                                 klass = mini_get_class (method, token, generic_context);
11750                                 CHECK_TYPELOAD (klass);
11751                                 mono_class_init (klass);
11752                         }
11753                         else
11754                                 klass = array_access_to_klass (*ip);
11755
11756                         if (sp [0]->type != STACK_OBJ)
11757                                 UNVERIFIED;
11758
11759                         emit_array_store (cfg, klass, sp, TRUE);
11760
11761                         if (*ip == CEE_STELEM)
11762                                 ip += 5;
11763                         else
11764                                 ++ip;
11765                         inline_costs += 1;
11766                         break;
11767                 }
11768                 case CEE_CKFINITE: {
11769                         CHECK_STACK (1);
11770                         --sp;
11771
11772                         if (cfg->llvm_only) {
11773                                 MonoInst *iargs [1];
11774
11775                                 iargs [0] = sp [0];
11776                                 *sp++ = mono_emit_jit_icall (cfg, mono_ckfinite, iargs);
11777                         } else  {
11778                                 MONO_INST_NEW (cfg, ins, OP_CKFINITE);
11779                                 ins->sreg1 = sp [0]->dreg;
11780                                 ins->dreg = alloc_freg (cfg);
11781                                 ins->type = STACK_R8;
11782                                 MONO_ADD_INS (cfg->cbb, ins);
11783
11784                                 *sp++ = mono_decompose_opcode (cfg, ins);
11785                         }
11786
11787                         ++ip;
11788                         break;
11789                 }
11790                 case CEE_REFANYVAL: {
11791                         MonoInst *src_var, *src;
11792
11793                         int klass_reg = alloc_preg (cfg);
11794                         int dreg = alloc_preg (cfg);
11795
11796                         GSHAREDVT_FAILURE (*ip);
11797
11798                         CHECK_STACK (1);
11799                         MONO_INST_NEW (cfg, ins, *ip);
11800                         --sp;
11801                         CHECK_OPSIZE (5);
11802                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11803                         CHECK_TYPELOAD (klass);
11804
11805                         context_used = mini_class_check_context_used (cfg, klass);
11806
11807                         // FIXME:
11808                         src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
11809                         if (!src_var)
11810                                 src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
11811                         EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
11812                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass));
11813
11814                         if (context_used) {
11815                                 MonoInst *klass_ins;
11816
11817                                 klass_ins = emit_get_rgctx_klass (cfg, context_used,
11818                                                 klass, MONO_RGCTX_INFO_KLASS);
11819
11820                                 // FIXME:
11821                                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_ins->dreg);
11822                                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
11823                         } else {
11824                                 mini_emit_class_check (cfg, klass_reg, klass);
11825                         }
11826                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value));
11827                         ins->type = STACK_MP;
11828                         ins->klass = klass;
11829                         *sp++ = ins;
11830                         ip += 5;
11831                         break;
11832                 }
11833                 case CEE_MKREFANY: {
11834                         MonoInst *loc, *addr;
11835
11836                         GSHAREDVT_FAILURE (*ip);
11837
11838                         CHECK_STACK (1);
11839                         MONO_INST_NEW (cfg, ins, *ip);
11840                         --sp;
11841                         CHECK_OPSIZE (5);
11842                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11843                         CHECK_TYPELOAD (klass);
11844
11845                         context_used = mini_class_check_context_used (cfg, klass);
11846
11847                         loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
11848                         EMIT_NEW_TEMPLOADA (cfg, addr, loc->inst_c0);
11849
11850                         if (context_used) {
11851                                 MonoInst *const_ins;
11852                                 int type_reg = alloc_preg (cfg);
11853
11854                                 const_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
11855                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_ins->dreg);
11856                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_ins->dreg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
11857                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
11858                         } else if (cfg->compile_aot) {
11859                                 int const_reg = alloc_preg (cfg);
11860                                 int type_reg = alloc_preg (cfg);
11861
11862                                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
11863                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_reg);
11864                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_reg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
11865                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
11866                         } else {
11867                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), &klass->byval_arg);
11868                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), klass);
11869                         }
11870                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value), sp [0]->dreg);
11871
11872                         EMIT_NEW_TEMPLOAD (cfg, ins, loc->inst_c0);
11873                         ins->type = STACK_VTYPE;
11874                         ins->klass = mono_defaults.typed_reference_class;
11875                         *sp++ = ins;
11876                         ip += 5;
11877                         break;
11878                 }
11879                 case CEE_LDTOKEN: {
11880                         gpointer handle;
11881                         MonoClass *handle_class;
11882
11883                         CHECK_STACK_OVF (1);
11884
11885                         CHECK_OPSIZE (5);
11886                         n = read32 (ip + 1);
11887
11888                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD ||
11889                                         method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
11890                                 handle = mono_method_get_wrapper_data (method, n);
11891                                 handle_class = mono_method_get_wrapper_data (method, n + 1);
11892                                 if (handle_class == mono_defaults.typehandle_class)
11893                                         handle = &((MonoClass*)handle)->byval_arg;
11894                         }
11895                         else {
11896                                 handle = mono_ldtoken_checked (image, n, &handle_class, generic_context, &cfg->error);
11897                                 CHECK_CFG_ERROR;
11898                         }
11899                         if (!handle)
11900                                 LOAD_ERROR;
11901                         mono_class_init (handle_class);
11902                         if (cfg->gshared) {
11903                                 if (mono_metadata_token_table (n) == MONO_TABLE_TYPEDEF ||
11904                                                 mono_metadata_token_table (n) == MONO_TABLE_TYPEREF) {
11905                                         /* This case handles ldtoken
11906                                            of an open type, like for
11907                                            typeof(Gen<>). */
11908                                         context_used = 0;
11909                                 } else if (handle_class == mono_defaults.typehandle_class) {
11910                                         context_used = mini_class_check_context_used (cfg, mono_class_from_mono_type (handle));
11911                                 } else if (handle_class == mono_defaults.fieldhandle_class)
11912                                         context_used = mini_class_check_context_used (cfg, ((MonoClassField*)handle)->parent);
11913                                 else if (handle_class == mono_defaults.methodhandle_class)
11914                                         context_used = mini_method_check_context_used (cfg, handle);
11915                                 else
11916                                         g_assert_not_reached ();
11917                         }
11918
11919                         if ((cfg->opt & MONO_OPT_SHARED) &&
11920                                         method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD &&
11921                                         method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED) {
11922                                 MonoInst *addr, *vtvar, *iargs [3];
11923                                 int method_context_used;
11924
11925                                 method_context_used = mini_method_check_context_used (cfg, method);
11926
11927                                 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL); 
11928
11929                                 EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
11930                                 EMIT_NEW_ICONST (cfg, iargs [1], n);
11931                                 if (method_context_used) {
11932                                         iargs [2] = emit_get_rgctx_method (cfg, method_context_used,
11933                                                 method, MONO_RGCTX_INFO_METHOD);
11934                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper_generic_shared, iargs);
11935                                 } else {
11936                                         EMIT_NEW_PCONST (cfg, iargs [2], generic_context);
11937                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper, iargs);
11938                                 }
11939                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
11940
11941                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
11942
11943                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
11944                         } else {
11945                                 if ((ip + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 5) && 
11946                                         ((ip [5] == CEE_CALL) || (ip [5] == CEE_CALLVIRT)) && 
11947                                         (cmethod = mini_get_method (cfg, method, read32 (ip + 6), NULL, generic_context)) &&
11948                                         (cmethod->klass == mono_defaults.systemtype_class) &&
11949                                         (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
11950                                         MonoClass *tclass = mono_class_from_mono_type (handle);
11951
11952                                         mono_class_init (tclass);
11953                                         if (context_used) {
11954                                                 ins = emit_get_rgctx_klass (cfg, context_used,
11955                                                         tclass, MONO_RGCTX_INFO_REFLECTION_TYPE);
11956                                         } else if (cfg->compile_aot) {
11957                                                 if (method->wrapper_type) {
11958                                                         mono_error_init (&error); //got to do it since there are multiple conditionals below
11959                                                         if (mono_class_get_checked (tclass->image, tclass->type_token, &error) == tclass && !generic_context) {
11960                                                                 /* Special case for static synchronized wrappers */
11961                                                                 EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, tclass->image, tclass->type_token, generic_context);
11962                                                         } else {
11963                                                                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
11964                                                                 /* FIXME: n is not a normal token */
11965                                                                 DISABLE_AOT (cfg);
11966                                                                 EMIT_NEW_PCONST (cfg, ins, NULL);
11967                                                         }
11968                                                 } else {
11969                                                         EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n, generic_context);
11970                                                 }
11971                                         } else {
11972                                                 EMIT_NEW_PCONST (cfg, ins, mono_type_get_object (cfg->domain, handle));
11973                                         }
11974                                         ins->type = STACK_OBJ;
11975                                         ins->klass = cmethod->klass;
11976                                         ip += 5;
11977                                 } else {
11978                                         MonoInst *addr, *vtvar;
11979
11980                                         vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
11981
11982                                         if (context_used) {
11983                                                 if (handle_class == mono_defaults.typehandle_class) {
11984                                                         ins = emit_get_rgctx_klass (cfg, context_used,
11985                                                                         mono_class_from_mono_type (handle),
11986                                                                         MONO_RGCTX_INFO_TYPE);
11987                                                 } else if (handle_class == mono_defaults.methodhandle_class) {
11988                                                         ins = emit_get_rgctx_method (cfg, context_used,
11989                                                                         handle, MONO_RGCTX_INFO_METHOD);
11990                                                 } else if (handle_class == mono_defaults.fieldhandle_class) {
11991                                                         ins = emit_get_rgctx_field (cfg, context_used,
11992                                                                         handle, MONO_RGCTX_INFO_CLASS_FIELD);
11993                                                 } else {
11994                                                         g_assert_not_reached ();
11995                                                 }
11996                                         } else if (cfg->compile_aot) {
11997                                                 EMIT_NEW_LDTOKENCONST (cfg, ins, image, n, generic_context);
11998                                         } else {
11999                                                 EMIT_NEW_PCONST (cfg, ins, handle);
12000                                         }
12001                                         EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
12002                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
12003                                         EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
12004                                 }
12005                         }
12006
12007                         *sp++ = ins;
12008                         ip += 5;
12009                         break;
12010                 }
12011                 case CEE_THROW:
12012                         CHECK_STACK (1);
12013                         MONO_INST_NEW (cfg, ins, OP_THROW);
12014                         --sp;
12015                         ins->sreg1 = sp [0]->dreg;
12016                         ip++;
12017                         cfg->cbb->out_of_line = TRUE;
12018                         MONO_ADD_INS (cfg->cbb, ins);
12019                         MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
12020                         MONO_ADD_INS (cfg->cbb, ins);
12021                         sp = stack_start;
12022                         
12023                         link_bblock (cfg, cfg->cbb, end_bblock);
12024                         start_new_bblock = 1;
12025                         /* This can complicate code generation for llvm since the return value might not be defined */
12026                         if (COMPILE_LLVM (cfg))
12027                                 INLINE_FAILURE ("throw");
12028                         break;
12029                 case CEE_ENDFINALLY:
12030                         /* mono_save_seq_point_info () depends on this */
12031                         if (sp != stack_start)
12032                                 emit_seq_point (cfg, method, ip, FALSE, FALSE);
12033                         MONO_INST_NEW (cfg, ins, OP_ENDFINALLY);
12034                         MONO_ADD_INS (cfg->cbb, ins);
12035                         ip++;
12036                         start_new_bblock = 1;
12037
12038                         /*
12039                          * Control will leave the method so empty the stack, otherwise
12040                          * the next basic block will start with a nonempty stack.
12041                          */
12042                         while (sp != stack_start) {
12043                                 sp--;
12044                         }
12045                         break;
12046                 case CEE_LEAVE:
12047                 case CEE_LEAVE_S: {
12048                         GList *handlers;
12049
12050                         if (*ip == CEE_LEAVE) {
12051                                 CHECK_OPSIZE (5);
12052                                 target = ip + 5 + (gint32)read32(ip + 1);
12053                         } else {
12054                                 CHECK_OPSIZE (2);
12055                                 target = ip + 2 + (signed char)(ip [1]);
12056                         }
12057
12058                         /* empty the stack */
12059                         while (sp != stack_start) {
12060                                 sp--;
12061                         }
12062
12063                         /* 
12064                          * If this leave statement is in a catch block, check for a
12065                          * pending exception, and rethrow it if necessary.
12066                          * We avoid doing this in runtime invoke wrappers, since those are called
12067                          * by native code which excepts the wrapper to catch all exceptions.
12068                          */
12069                         for (i = 0; i < header->num_clauses; ++i) {
12070                                 MonoExceptionClause *clause = &header->clauses [i];
12071
12072                                 /* 
12073                                  * Use <= in the final comparison to handle clauses with multiple
12074                                  * leave statements, like in bug #78024.
12075                                  * The ordering of the exception clauses guarantees that we find the
12076                                  * innermost clause.
12077                                  */
12078                                 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) {
12079                                         MonoInst *exc_ins;
12080                                         MonoBasicBlock *dont_throw;
12081
12082                                         /*
12083                                           MonoInst *load;
12084
12085                                           NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, clause->handler_offset)->inst_c0);
12086                                         */
12087
12088                                         exc_ins = mono_emit_jit_icall (cfg, mono_thread_get_undeniable_exception, NULL);
12089
12090                                         NEW_BBLOCK (cfg, dont_throw);
12091
12092                                         /*
12093                                          * Currently, we always rethrow the abort exception, despite the 
12094                                          * fact that this is not correct. See thread6.cs for an example. 
12095                                          * But propagating the abort exception is more important than 
12096                                          * getting the sematics right.
12097                                          */
12098                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, exc_ins->dreg, 0);
12099                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, dont_throw);
12100                                         MONO_EMIT_NEW_UNALU (cfg, OP_THROW, -1, exc_ins->dreg);
12101
12102                                         MONO_START_BB (cfg, dont_throw);
12103                                 }
12104                         }
12105
12106 #ifdef ENABLE_LLVM
12107                         cfg->cbb->try_end = (intptr_t)(ip - header->code);
12108 #endif
12109
12110                         if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
12111                                 GList *tmp;
12112                                 MonoExceptionClause *clause;
12113
12114                                 for (tmp = handlers; tmp; tmp = tmp->next) {
12115                                         clause = tmp->data;
12116                                         tblock = cfg->cil_offset_to_bb [clause->handler_offset];
12117                                         g_assert (tblock);
12118                                         link_bblock (cfg, cfg->cbb, tblock);
12119                                         MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
12120                                         ins->inst_target_bb = tblock;
12121                                         ins->inst_eh_block = clause;
12122                                         MONO_ADD_INS (cfg->cbb, ins);
12123                                         cfg->cbb->has_call_handler = 1;
12124                                         if (COMPILE_LLVM (cfg)) {
12125                                                 MonoBasicBlock *target_bb;
12126
12127                                                 /* 
12128                                                  * Link the finally bblock with the target, since it will
12129                                                  * conceptually branch there.
12130                                                  * FIXME: Have to link the bblock containing the endfinally.
12131                                                  */
12132                                                 GET_BBLOCK (cfg, target_bb, target);
12133                                                 link_bblock (cfg, tblock, target_bb);
12134                                         }
12135                                 }
12136                                 g_list_free (handlers);
12137                         } 
12138
12139                         MONO_INST_NEW (cfg, ins, OP_BR);
12140                         MONO_ADD_INS (cfg->cbb, ins);
12141                         GET_BBLOCK (cfg, tblock, target);
12142                         link_bblock (cfg, cfg->cbb, tblock);
12143                         ins->inst_target_bb = tblock;
12144
12145                         start_new_bblock = 1;
12146
12147                         if (*ip == CEE_LEAVE)
12148                                 ip += 5;
12149                         else
12150                                 ip += 2;
12151
12152                         break;
12153                 }
12154
12155                         /*
12156                          * Mono specific opcodes
12157                          */
12158                 case MONO_CUSTOM_PREFIX: {
12159
12160                         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
12161
12162                         CHECK_OPSIZE (2);
12163                         switch (ip [1]) {
12164                         case CEE_MONO_ICALL: {
12165                                 gpointer func;
12166                                 MonoJitICallInfo *info;
12167
12168                                 token = read32 (ip + 2);
12169                                 func = mono_method_get_wrapper_data (method, token);
12170                                 info = mono_find_jit_icall_by_addr (func);
12171                                 if (!info)
12172                                         g_error ("Could not find icall address in wrapper %s", mono_method_full_name (method, 1));
12173                                 g_assert (info);
12174
12175                                 CHECK_STACK (info->sig->param_count);
12176                                 sp -= info->sig->param_count;
12177
12178                                 ins = mono_emit_jit_icall (cfg, info->func, sp);
12179                                 if (!MONO_TYPE_IS_VOID (info->sig->ret))
12180                                         *sp++ = ins;
12181
12182                                 ip += 6;
12183                                 inline_costs += 10 * num_calls++;
12184
12185                                 break;
12186                         }
12187                         case CEE_MONO_LDPTR_CARD_TABLE:
12188                         case CEE_MONO_LDPTR_NURSERY_START:
12189                         case CEE_MONO_LDPTR_NURSERY_BITS:
12190                         case CEE_MONO_LDPTR_INT_REQ_FLAG: {
12191                                 CHECK_STACK_OVF (1);
12192
12193                                 switch (ip [1]) {
12194                                         case CEE_MONO_LDPTR_CARD_TABLE:
12195                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR, NULL);
12196                                                 break;
12197                                         case CEE_MONO_LDPTR_NURSERY_START:
12198                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_NURSERY_START, NULL);
12199                                                 break;
12200                                         case CEE_MONO_LDPTR_NURSERY_BITS:
12201                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_NURSERY_BITS, NULL);
12202                                                 break;
12203                                         case CEE_MONO_LDPTR_INT_REQ_FLAG:
12204                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG, NULL);
12205                                                 break;
12206                                 }
12207
12208                                 *sp++ = ins;
12209                                 ip += 2;
12210                                 inline_costs += 10 * num_calls++;
12211                                 break;
12212                         }
12213                         case CEE_MONO_LDPTR: {
12214                                 gpointer ptr;
12215
12216                                 CHECK_STACK_OVF (1);
12217                                 CHECK_OPSIZE (6);
12218                                 token = read32 (ip + 2);
12219
12220                                 ptr = mono_method_get_wrapper_data (method, token);
12221                                 EMIT_NEW_PCONST (cfg, ins, ptr);
12222                                 *sp++ = ins;
12223                                 ip += 6;
12224                                 inline_costs += 10 * num_calls++;
12225                                 /* Can't embed random pointers into AOT code */
12226                                 DISABLE_AOT (cfg);
12227                                 break;
12228                         }
12229                         case CEE_MONO_JIT_ICALL_ADDR: {
12230                                 MonoJitICallInfo *callinfo;
12231                                 gpointer ptr;
12232
12233                                 CHECK_STACK_OVF (1);
12234                                 CHECK_OPSIZE (6);
12235                                 token = read32 (ip + 2);
12236
12237                                 ptr = mono_method_get_wrapper_data (method, token);
12238                                 callinfo = mono_find_jit_icall_by_addr (ptr);
12239                                 g_assert (callinfo);
12240                                 EMIT_NEW_JIT_ICALL_ADDRCONST (cfg, ins, (char*)callinfo->name);
12241                                 *sp++ = ins;
12242                                 ip += 6;
12243                                 inline_costs += 10 * num_calls++;
12244                                 break;
12245                         }
12246                         case CEE_MONO_ICALL_ADDR: {
12247                                 MonoMethod *cmethod;
12248                                 gpointer ptr;
12249
12250                                 CHECK_STACK_OVF (1);
12251                                 CHECK_OPSIZE (6);
12252                                 token = read32 (ip + 2);
12253
12254                                 cmethod = mono_method_get_wrapper_data (method, token);
12255
12256                                 if (cfg->compile_aot) {
12257                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, cmethod);
12258                                 } else {
12259                                         ptr = mono_lookup_internal_call (cmethod);
12260                                         g_assert (ptr);
12261                                         EMIT_NEW_PCONST (cfg, ins, ptr);
12262                                 }
12263                                 *sp++ = ins;
12264                                 ip += 6;
12265                                 break;
12266                         }
12267                         case CEE_MONO_VTADDR: {
12268                                 MonoInst *src_var, *src;
12269
12270                                 CHECK_STACK (1);
12271                                 --sp;
12272
12273                                 // FIXME:
12274                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
12275                                 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
12276                                 *sp++ = src;
12277                                 ip += 2;
12278                                 break;
12279                         }
12280                         case CEE_MONO_NEWOBJ: {
12281                                 MonoInst *iargs [2];
12282
12283                                 CHECK_STACK_OVF (1);
12284                                 CHECK_OPSIZE (6);
12285                                 token = read32 (ip + 2);
12286                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12287                                 mono_class_init (klass);
12288                                 NEW_DOMAINCONST (cfg, iargs [0]);
12289                                 MONO_ADD_INS (cfg->cbb, iargs [0]);
12290                                 NEW_CLASSCONST (cfg, iargs [1], klass);
12291                                 MONO_ADD_INS (cfg->cbb, iargs [1]);
12292                                 *sp++ = mono_emit_jit_icall (cfg, mono_object_new, iargs);
12293                                 ip += 6;
12294                                 inline_costs += 10 * num_calls++;
12295                                 break;
12296                         }
12297                         case CEE_MONO_OBJADDR:
12298                                 CHECK_STACK (1);
12299                                 --sp;
12300                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
12301                                 ins->dreg = alloc_ireg_mp (cfg);
12302                                 ins->sreg1 = sp [0]->dreg;
12303                                 ins->type = STACK_MP;
12304                                 MONO_ADD_INS (cfg->cbb, ins);
12305                                 *sp++ = ins;
12306                                 ip += 2;
12307                                 break;
12308                         case CEE_MONO_LDNATIVEOBJ:
12309                                 /*
12310                                  * Similar to LDOBJ, but instead load the unmanaged 
12311                                  * representation of the vtype to the stack.
12312                                  */
12313                                 CHECK_STACK (1);
12314                                 CHECK_OPSIZE (6);
12315                                 --sp;
12316                                 token = read32 (ip + 2);
12317                                 klass = mono_method_get_wrapper_data (method, token);
12318                                 g_assert (klass->valuetype);
12319                                 mono_class_init (klass);
12320
12321                                 {
12322                                         MonoInst *src, *dest, *temp;
12323
12324                                         src = sp [0];
12325                                         temp = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
12326                                         temp->backend.is_pinvoke = 1;
12327                                         EMIT_NEW_TEMPLOADA (cfg, dest, temp->inst_c0);
12328                                         mini_emit_stobj (cfg, dest, src, klass, TRUE);
12329
12330                                         EMIT_NEW_TEMPLOAD (cfg, dest, temp->inst_c0);
12331                                         dest->type = STACK_VTYPE;
12332                                         dest->klass = klass;
12333
12334                                         *sp ++ = dest;
12335                                         ip += 6;
12336                                 }
12337                                 break;
12338                         case CEE_MONO_RETOBJ: {
12339                                 /*
12340                                  * Same as RET, but return the native representation of a vtype
12341                                  * to the caller.
12342                                  */
12343                                 g_assert (cfg->ret);
12344                                 g_assert (mono_method_signature (method)->pinvoke); 
12345                                 CHECK_STACK (1);
12346                                 --sp;
12347                                 
12348                                 CHECK_OPSIZE (6);
12349                                 token = read32 (ip + 2);    
12350                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12351
12352                                 if (!cfg->vret_addr) {
12353                                         g_assert (cfg->ret_var_is_local);
12354
12355                                         EMIT_NEW_VARLOADA (cfg, ins, cfg->ret, cfg->ret->inst_vtype);
12356                                 } else {
12357                                         EMIT_NEW_RETLOADA (cfg, ins);
12358                                 }
12359                                 mini_emit_stobj (cfg, ins, sp [0], klass, TRUE);
12360                                 
12361                                 if (sp != stack_start)
12362                                         UNVERIFIED;
12363                                 
12364                                 MONO_INST_NEW (cfg, ins, OP_BR);
12365                                 ins->inst_target_bb = end_bblock;
12366                                 MONO_ADD_INS (cfg->cbb, ins);
12367                                 link_bblock (cfg, cfg->cbb, end_bblock);
12368                                 start_new_bblock = 1;
12369                                 ip += 6;
12370                                 break;
12371                         }
12372                         case CEE_MONO_CISINST:
12373                         case CEE_MONO_CCASTCLASS: {
12374                                 int token;
12375                                 CHECK_STACK (1);
12376                                 --sp;
12377                                 CHECK_OPSIZE (6);
12378                                 token = read32 (ip + 2);
12379                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12380                                 if (ip [1] == CEE_MONO_CISINST)
12381                                         ins = handle_cisinst (cfg, klass, sp [0]);
12382                                 else
12383                                         ins = handle_ccastclass (cfg, klass, sp [0]);
12384                                 *sp++ = ins;
12385                                 ip += 6;
12386                                 break;
12387                         }
12388                         case CEE_MONO_SAVE_LMF:
12389                         case CEE_MONO_RESTORE_LMF:
12390                                 ip += 2;
12391                                 break;
12392                         case CEE_MONO_CLASSCONST:
12393                                 CHECK_STACK_OVF (1);
12394                                 CHECK_OPSIZE (6);
12395                                 token = read32 (ip + 2);
12396                                 EMIT_NEW_CLASSCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
12397                                 *sp++ = ins;
12398                                 ip += 6;
12399                                 inline_costs += 10 * num_calls++;
12400                                 break;
12401                         case CEE_MONO_NOT_TAKEN:
12402                                 cfg->cbb->out_of_line = TRUE;
12403                                 ip += 2;
12404                                 break;
12405                         case CEE_MONO_TLS: {
12406                                 int key;
12407
12408                                 CHECK_STACK_OVF (1);
12409                                 CHECK_OPSIZE (6);
12410                                 key = (gint32)read32 (ip + 2);
12411                                 g_assert (key < TLS_KEY_NUM);
12412
12413                                 ins = mono_create_tls_get (cfg, key);
12414                                 if (!ins) {
12415                                         if (cfg->compile_aot) {
12416                                                 DISABLE_AOT (cfg);
12417                                                 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
12418                                                 ins->dreg = alloc_preg (cfg);
12419                                                 ins->type = STACK_PTR;
12420                                         } else {
12421                                                 g_assert_not_reached ();
12422                                         }
12423                                 }
12424                                 ins->type = STACK_PTR;
12425                                 MONO_ADD_INS (cfg->cbb, ins);
12426                                 *sp++ = ins;
12427                                 ip += 6;
12428                                 break;
12429                         }
12430                         case CEE_MONO_DYN_CALL: {
12431                                 MonoCallInst *call;
12432
12433                                 /* It would be easier to call a trampoline, but that would put an
12434                                  * extra frame on the stack, confusing exception handling. So
12435                                  * implement it inline using an opcode for now.
12436                                  */
12437
12438                                 if (!cfg->dyn_call_var) {
12439                                         cfg->dyn_call_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12440                                         /* prevent it from being register allocated */
12441                                         cfg->dyn_call_var->flags |= MONO_INST_VOLATILE;
12442                                 }
12443
12444                                 /* Has to use a call inst since it local regalloc expects it */
12445                                 MONO_INST_NEW_CALL (cfg, call, OP_DYN_CALL);
12446                                 ins = (MonoInst*)call;
12447                                 sp -= 2;
12448                                 ins->sreg1 = sp [0]->dreg;
12449                                 ins->sreg2 = sp [1]->dreg;
12450                                 MONO_ADD_INS (cfg->cbb, ins);
12451
12452                                 cfg->param_area = MAX (cfg->param_area, cfg->backend->dyn_call_param_area);
12453
12454                                 ip += 2;
12455                                 inline_costs += 10 * num_calls++;
12456
12457                                 break;
12458                         }
12459                         case CEE_MONO_MEMORY_BARRIER: {
12460                                 CHECK_OPSIZE (6);
12461                                 emit_memory_barrier (cfg, (int)read32 (ip + 2));
12462                                 ip += 6;
12463                                 break;
12464                         }
12465                         case CEE_MONO_JIT_ATTACH: {
12466                                 MonoInst *args [16], *domain_ins;
12467                                 MonoInst *ad_ins, *jit_tls_ins;
12468                                 MonoBasicBlock *next_bb = NULL, *call_bb = NULL;
12469
12470                                 cfg->orig_domain_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12471
12472                                 EMIT_NEW_PCONST (cfg, ins, NULL);
12473                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12474
12475                                 ad_ins = mono_get_domain_intrinsic (cfg);
12476                                 jit_tls_ins = mono_get_jit_tls_intrinsic (cfg);
12477
12478                                 if (cfg->backend->have_tls_get && ad_ins && jit_tls_ins) {
12479                                         NEW_BBLOCK (cfg, next_bb);
12480                                         NEW_BBLOCK (cfg, call_bb);
12481
12482                                         if (cfg->compile_aot) {
12483                                                 /* AOT code is only used in the root domain */
12484                                                 EMIT_NEW_PCONST (cfg, domain_ins, NULL);
12485                                         } else {
12486                                                 EMIT_NEW_PCONST (cfg, domain_ins, cfg->domain);
12487                                         }
12488                                         MONO_ADD_INS (cfg->cbb, ad_ins);
12489                                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, ad_ins->dreg, domain_ins->dreg);
12490                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, call_bb);
12491
12492                                         MONO_ADD_INS (cfg->cbb, jit_tls_ins);
12493                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, jit_tls_ins->dreg, 0);
12494                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, call_bb);
12495
12496                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, next_bb);
12497                                         MONO_START_BB (cfg, call_bb);
12498                                 }
12499
12500                                 if (cfg->compile_aot) {
12501                                         /* AOT code is only used in the root domain */
12502                                         EMIT_NEW_PCONST (cfg, args [0], NULL);
12503                                 } else {
12504                                         EMIT_NEW_PCONST (cfg, args [0], cfg->domain);
12505                                 }
12506                                 ins = mono_emit_jit_icall (cfg, mono_jit_thread_attach, args);
12507                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12508
12509                                 if (next_bb)
12510                                         MONO_START_BB (cfg, next_bb);
12511                                 ip += 2;
12512                                 break;
12513                         }
12514                         case CEE_MONO_JIT_DETACH: {
12515                                 MonoInst *args [16];
12516
12517                                 /* Restore the original domain */
12518                                 dreg = alloc_ireg (cfg);
12519                                 EMIT_NEW_UNALU (cfg, args [0], OP_MOVE, dreg, cfg->orig_domain_var->dreg);
12520                                 mono_emit_jit_icall (cfg, mono_jit_set_domain, args);
12521                                 ip += 2;
12522                                 break;
12523                         }
12524                         default:
12525                                 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
12526                                 break;
12527                         }
12528                         break;
12529                 }
12530
12531                 case CEE_PREFIX1: {
12532                         CHECK_OPSIZE (2);
12533                         switch (ip [1]) {
12534                         case CEE_ARGLIST: {
12535                                 /* somewhat similar to LDTOKEN */
12536                                 MonoInst *addr, *vtvar;
12537                                 CHECK_STACK_OVF (1);
12538                                 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL); 
12539
12540                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
12541                                 EMIT_NEW_UNALU (cfg, ins, OP_ARGLIST, -1, addr->dreg);
12542
12543                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
12544                                 ins->type = STACK_VTYPE;
12545                                 ins->klass = mono_defaults.argumenthandle_class;
12546                                 *sp++ = ins;
12547                                 ip += 2;
12548                                 break;
12549                         }
12550                         case CEE_CEQ:
12551                         case CEE_CGT:
12552                         case CEE_CGT_UN:
12553                         case CEE_CLT:
12554                         case CEE_CLT_UN: {
12555                                 MonoInst *cmp, *arg1, *arg2;
12556
12557                                 CHECK_STACK (2);
12558                                 sp -= 2;
12559                                 arg1 = sp [0];
12560                                 arg2 = sp [1];
12561
12562                                 /*
12563                                  * The following transforms:
12564                                  *    CEE_CEQ    into OP_CEQ
12565                                  *    CEE_CGT    into OP_CGT
12566                                  *    CEE_CGT_UN into OP_CGT_UN
12567                                  *    CEE_CLT    into OP_CLT
12568                                  *    CEE_CLT_UN into OP_CLT_UN
12569                                  */
12570                                 MONO_INST_NEW (cfg, cmp, (OP_CEQ - CEE_CEQ) + ip [1]);
12571
12572                                 MONO_INST_NEW (cfg, ins, cmp->opcode);
12573                                 cmp->sreg1 = arg1->dreg;
12574                                 cmp->sreg2 = arg2->dreg;
12575                                 type_from_op (cfg, cmp, arg1, arg2);
12576                                 CHECK_TYPE (cmp);
12577                                 add_widen_op (cfg, cmp, &arg1, &arg2);
12578                                 if ((arg1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((arg1->type == STACK_PTR) || (arg1->type == STACK_OBJ) || (arg1->type == STACK_MP))))
12579                                         cmp->opcode = OP_LCOMPARE;
12580                                 else if (arg1->type == STACK_R4)
12581                                         cmp->opcode = OP_RCOMPARE;
12582                                 else if (arg1->type == STACK_R8)
12583                                         cmp->opcode = OP_FCOMPARE;
12584                                 else
12585                                         cmp->opcode = OP_ICOMPARE;
12586                                 MONO_ADD_INS (cfg->cbb, cmp);
12587                                 ins->type = STACK_I4;
12588                                 ins->dreg = alloc_dreg (cfg, ins->type);
12589                                 type_from_op (cfg, ins, arg1, arg2);
12590
12591                                 if (cmp->opcode == OP_FCOMPARE || cmp->opcode == OP_RCOMPARE) {
12592                                         /*
12593                                          * The backends expect the fceq opcodes to do the
12594                                          * comparison too.
12595                                          */
12596                                         ins->sreg1 = cmp->sreg1;
12597                                         ins->sreg2 = cmp->sreg2;
12598                                         NULLIFY_INS (cmp);
12599                                 }
12600                                 MONO_ADD_INS (cfg->cbb, ins);
12601                                 *sp++ = ins;
12602                                 ip += 2;
12603                                 break;
12604                         }
12605                         case CEE_LDFTN: {
12606                                 MonoInst *argconst;
12607                                 MonoMethod *cil_method;
12608
12609                                 CHECK_STACK_OVF (1);
12610                                 CHECK_OPSIZE (6);
12611                                 n = read32 (ip + 2);
12612                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
12613                                 if (!cmethod || mono_loader_get_last_error ())
12614                                         LOAD_ERROR;
12615                                 mono_class_init (cmethod->klass);
12616
12617                                 mono_save_token_info (cfg, image, n, cmethod);
12618
12619                                 context_used = mini_method_check_context_used (cfg, cmethod);
12620
12621                                 cil_method = cmethod;
12622                                 if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
12623                                         METHOD_ACCESS_FAILURE (method, cil_method);
12624
12625                                 if (mono_security_core_clr_enabled ())
12626                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
12627
12628                                 /* 
12629                                  * Optimize the common case of ldftn+delegate creation
12630                                  */
12631                                 if ((sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 6) && (ip [6] == CEE_NEWOBJ)) {
12632                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
12633                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
12634                                                 MonoInst *target_ins, *handle_ins;
12635                                                 MonoMethod *invoke;
12636                                                 int invoke_context_used;
12637
12638                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
12639                                                 if (!invoke || !mono_method_signature (invoke))
12640                                                         LOAD_ERROR;
12641
12642                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
12643
12644                                                 target_ins = sp [-1];
12645
12646                                                 if (mono_security_core_clr_enabled ())
12647                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
12648
12649                                                 if (!(cmethod->flags & METHOD_ATTRIBUTE_STATIC)) {
12650                                                         /*LAME IMPL: We must not add a null check for virtual invoke delegates.*/
12651                                                         if (mono_method_signature (invoke)->param_count == mono_method_signature (cmethod)->param_count) {
12652                                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, target_ins->dreg, 0);
12653                                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "ArgumentException");
12654                                                         }
12655                                                 }
12656
12657                                                 /* FIXME: SGEN support */
12658                                                 if (invoke_context_used == 0) {
12659                                                         ip += 6;
12660                                                         if (cfg->verbose_level > 3)
12661                                                                 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));
12662                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, FALSE))) {
12663                                                                 sp --;
12664                                                                 *sp = handle_ins;
12665                                                                 CHECK_CFG_EXCEPTION;
12666                                                                 ip += 5;
12667                                                                 sp ++;
12668                                                                 break;
12669                                                         }
12670                                                         ip -= 6;
12671                                                 }
12672                                         }
12673                                 }
12674
12675                                 argconst = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD);
12676                                 ins = mono_emit_jit_icall (cfg, mono_ldftn, &argconst);
12677                                 *sp++ = ins;
12678                                 
12679                                 ip += 6;
12680                                 inline_costs += 10 * num_calls++;
12681                                 break;
12682                         }
12683                         case CEE_LDVIRTFTN: {
12684                                 MonoInst *args [2];
12685
12686                                 CHECK_STACK (1);
12687                                 CHECK_OPSIZE (6);
12688                                 n = read32 (ip + 2);
12689                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
12690                                 if (!cmethod || mono_loader_get_last_error ())
12691                                         LOAD_ERROR;
12692                                 mono_class_init (cmethod->klass);
12693  
12694                                 context_used = mini_method_check_context_used (cfg, cmethod);
12695
12696                                 if (mono_security_core_clr_enabled ())
12697                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
12698
12699                                 /*
12700                                  * Optimize the common case of ldvirtftn+delegate creation
12701                                  */
12702                                 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)) {
12703                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
12704                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
12705                                                 MonoInst *target_ins, *handle_ins;
12706                                                 MonoMethod *invoke;
12707                                                 int invoke_context_used;
12708                                                 gboolean is_virtual = cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL;
12709
12710                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
12711                                                 if (!invoke || !mono_method_signature (invoke))
12712                                                         LOAD_ERROR;
12713
12714                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
12715
12716                                                 target_ins = sp [-1];
12717
12718                                                 if (mono_security_core_clr_enabled ())
12719                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
12720
12721                                                 /* FIXME: SGEN support */
12722                                                 if (invoke_context_used == 0 || cfg->llvm_only) {
12723                                                         ip += 6;
12724                                                         if (cfg->verbose_level > 3)
12725                                                                 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));
12726                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, is_virtual))) {
12727                                                                 sp -= 2;
12728                                                                 *sp = handle_ins;
12729                                                                 CHECK_CFG_EXCEPTION;
12730                                                                 ip += 5;
12731                                                                 sp ++;
12732                                                                 break;
12733                                                         }
12734                                                         ip -= 6;
12735                                                 }
12736                                         }
12737                                 }
12738
12739                                 --sp;
12740                                 args [0] = *sp;
12741
12742                                 args [1] = emit_get_rgctx_method (cfg, context_used,
12743                                                                                                   cmethod, MONO_RGCTX_INFO_METHOD);
12744
12745                                 if (context_used)
12746                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn_gshared, args);
12747                                 else
12748                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn, args);
12749
12750                                 ip += 6;
12751                                 inline_costs += 10 * num_calls++;
12752                                 break;
12753                         }
12754                         case CEE_LDARG:
12755                                 CHECK_STACK_OVF (1);
12756                                 CHECK_OPSIZE (4);
12757                                 n = read16 (ip + 2);
12758                                 CHECK_ARG (n);
12759                                 EMIT_NEW_ARGLOAD (cfg, ins, n);
12760                                 *sp++ = ins;
12761                                 ip += 4;
12762                                 break;
12763                         case CEE_LDARGA:
12764                                 CHECK_STACK_OVF (1);
12765                                 CHECK_OPSIZE (4);
12766                                 n = read16 (ip + 2);
12767                                 CHECK_ARG (n);
12768                                 NEW_ARGLOADA (cfg, ins, n);
12769                                 MONO_ADD_INS (cfg->cbb, ins);
12770                                 *sp++ = ins;
12771                                 ip += 4;
12772                                 break;
12773                         case CEE_STARG:
12774                                 CHECK_STACK (1);
12775                                 --sp;
12776                                 CHECK_OPSIZE (4);
12777                                 n = read16 (ip + 2);
12778                                 CHECK_ARG (n);
12779                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
12780                                         UNVERIFIED;
12781                                 EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
12782                                 ip += 4;
12783                                 break;
12784                         case CEE_LDLOC:
12785                                 CHECK_STACK_OVF (1);
12786                                 CHECK_OPSIZE (4);
12787                                 n = read16 (ip + 2);
12788                                 CHECK_LOCAL (n);
12789                                 EMIT_NEW_LOCLOAD (cfg, ins, n);
12790                                 *sp++ = ins;
12791                                 ip += 4;
12792                                 break;
12793                         case CEE_LDLOCA: {
12794                                 unsigned char *tmp_ip;
12795                                 CHECK_STACK_OVF (1);
12796                                 CHECK_OPSIZE (4);
12797                                 n = read16 (ip + 2);
12798                                 CHECK_LOCAL (n);
12799
12800                                 if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 2))) {
12801                                         ip = tmp_ip;
12802                                         inline_costs += 1;
12803                                         break;
12804                                 }                       
12805                                 
12806                                 EMIT_NEW_LOCLOADA (cfg, ins, n);
12807                                 *sp++ = ins;
12808                                 ip += 4;
12809                                 break;
12810                         }
12811                         case CEE_STLOC:
12812                                 CHECK_STACK (1);
12813                                 --sp;
12814                                 CHECK_OPSIZE (4);
12815                                 n = read16 (ip + 2);
12816                                 CHECK_LOCAL (n);
12817                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
12818                                         UNVERIFIED;
12819                                 emit_stloc_ir (cfg, sp, header, n);
12820                                 ip += 4;
12821                                 inline_costs += 1;
12822                                 break;
12823                         case CEE_LOCALLOC:
12824                                 CHECK_STACK (1);
12825                                 --sp;
12826                                 if (sp != stack_start) 
12827                                         UNVERIFIED;
12828                                 if (cfg->method != method) 
12829                                         /* 
12830                                          * Inlining this into a loop in a parent could lead to 
12831                                          * stack overflows which is different behavior than the
12832                                          * non-inlined case, thus disable inlining in this case.
12833                                          */
12834                                         INLINE_FAILURE("localloc");
12835
12836                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
12837                                 ins->dreg = alloc_preg (cfg);
12838                                 ins->sreg1 = sp [0]->dreg;
12839                                 ins->type = STACK_PTR;
12840                                 MONO_ADD_INS (cfg->cbb, ins);
12841
12842                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12843                                 if (init_locals)
12844                                         ins->flags |= MONO_INST_INIT;
12845
12846                                 *sp++ = ins;
12847                                 ip += 2;
12848                                 break;
12849                         case CEE_ENDFILTER: {
12850                                 MonoExceptionClause *clause, *nearest;
12851                                 int cc;
12852
12853                                 CHECK_STACK (1);
12854                                 --sp;
12855                                 if ((sp != stack_start) || (sp [0]->type != STACK_I4)) 
12856                                         UNVERIFIED;
12857                                 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
12858                                 ins->sreg1 = (*sp)->dreg;
12859                                 MONO_ADD_INS (cfg->cbb, ins);
12860                                 start_new_bblock = 1;
12861                                 ip += 2;
12862
12863                                 nearest = NULL;
12864                                 for (cc = 0; cc < header->num_clauses; ++cc) {
12865                                         clause = &header->clauses [cc];
12866                                         if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
12867                                                 ((ip - header->code) > clause->data.filter_offset && (ip - header->code) <= clause->handler_offset) &&
12868                                             (!nearest || (clause->data.filter_offset < nearest->data.filter_offset)))
12869                                                 nearest = clause;
12870                                 }
12871                                 g_assert (nearest);
12872                                 if ((ip - header->code) != nearest->handler_offset)
12873                                         UNVERIFIED;
12874
12875                                 break;
12876                         }
12877                         case CEE_UNALIGNED_:
12878                                 ins_flag |= MONO_INST_UNALIGNED;
12879                                 /* FIXME: record alignment? we can assume 1 for now */
12880                                 CHECK_OPSIZE (3);
12881                                 ip += 3;
12882                                 break;
12883                         case CEE_VOLATILE_:
12884                                 ins_flag |= MONO_INST_VOLATILE;
12885                                 ip += 2;
12886                                 break;
12887                         case CEE_TAIL_:
12888                                 ins_flag   |= MONO_INST_TAILCALL;
12889                                 cfg->flags |= MONO_CFG_HAS_TAIL;
12890                                 /* Can't inline tail calls at this time */
12891                                 inline_costs += 100000;
12892                                 ip += 2;
12893                                 break;
12894                         case CEE_INITOBJ:
12895                                 CHECK_STACK (1);
12896                                 --sp;
12897                                 CHECK_OPSIZE (6);
12898                                 token = read32 (ip + 2);
12899                                 klass = mini_get_class (method, token, generic_context);
12900                                 CHECK_TYPELOAD (klass);
12901                                 if (generic_class_is_reference_type (cfg, klass))
12902                                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, sp [0]->dreg, 0, 0);
12903                                 else
12904                                         mini_emit_initobj (cfg, *sp, NULL, klass);
12905                                 ip += 6;
12906                                 inline_costs += 1;
12907                                 break;
12908                         case CEE_CONSTRAINED_:
12909                                 CHECK_OPSIZE (6);
12910                                 token = read32 (ip + 2);
12911                                 constrained_class = mini_get_class (method, token, generic_context);
12912                                 CHECK_TYPELOAD (constrained_class);
12913                                 ip += 6;
12914                                 break;
12915                         case CEE_CPBLK:
12916                         case CEE_INITBLK: {
12917                                 MonoInst *iargs [3];
12918                                 CHECK_STACK (3);
12919                                 sp -= 3;
12920
12921                                 /* Skip optimized paths for volatile operations. */
12922                                 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)) {
12923                                         mini_emit_memcpy (cfg, sp [0]->dreg, 0, sp [1]->dreg, 0, sp [2]->inst_c0, 0);
12924                                 } 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)) {
12925                                         /* emit_memset only works when val == 0 */
12926                                         mini_emit_memset (cfg, sp [0]->dreg, 0, sp [2]->inst_c0, sp [1]->inst_c0, 0);
12927                                 } else {
12928                                         MonoInst *call;
12929                                         iargs [0] = sp [0];
12930                                         iargs [1] = sp [1];
12931                                         iargs [2] = sp [2];
12932                                         if (ip [1] == CEE_CPBLK) {
12933                                                 /*
12934                                                  * FIXME: It's unclear whether we should be emitting both the acquire
12935                                                  * and release barriers for cpblk. It is technically both a load and
12936                                                  * store operation, so it seems like that's the sensible thing to do.
12937                                                  *
12938                                                  * FIXME: We emit full barriers on both sides of the operation for
12939                                                  * simplicity. We should have a separate atomic memcpy method instead.
12940                                                  */
12941                                                 MonoMethod *memcpy_method = get_memcpy_method ();
12942
12943                                                 if (ins_flag & MONO_INST_VOLATILE)
12944                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
12945
12946                                                 call = mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
12947                                                 call->flags |= ins_flag;
12948
12949                                                 if (ins_flag & MONO_INST_VOLATILE)
12950                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
12951                                         } else {
12952                                                 MonoMethod *memset_method = get_memset_method ();
12953                                                 if (ins_flag & MONO_INST_VOLATILE) {
12954                                                         /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
12955                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
12956                                                 }
12957                                                 call = mono_emit_method_call (cfg, memset_method, iargs, NULL);
12958                                                 call->flags |= ins_flag;
12959                                         }
12960                                 }
12961                                 ip += 2;
12962                                 ins_flag = 0;
12963                                 inline_costs += 1;
12964                                 break;
12965                         }
12966                         case CEE_NO_:
12967                                 CHECK_OPSIZE (3);
12968                                 if (ip [2] & 0x1)
12969                                         ins_flag |= MONO_INST_NOTYPECHECK;
12970                                 if (ip [2] & 0x2)
12971                                         ins_flag |= MONO_INST_NORANGECHECK;
12972                                 /* we ignore the no-nullcheck for now since we
12973                                  * really do it explicitly only when doing callvirt->call
12974                                  */
12975                                 ip += 3;
12976                                 break;
12977                         case CEE_RETHROW: {
12978                                 MonoInst *load;
12979                                 int handler_offset = -1;
12980
12981                                 for (i = 0; i < header->num_clauses; ++i) {
12982                                         MonoExceptionClause *clause = &header->clauses [i];
12983                                         if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
12984                                                 handler_offset = clause->handler_offset;
12985                                                 break;
12986                                         }
12987                                 }
12988
12989                                 cfg->cbb->flags |= BB_EXCEPTION_UNSAFE;
12990
12991                                 if (handler_offset == -1)
12992                                         UNVERIFIED;
12993
12994                                 EMIT_NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
12995                                 MONO_INST_NEW (cfg, ins, OP_RETHROW);
12996                                 ins->sreg1 = load->dreg;
12997                                 MONO_ADD_INS (cfg->cbb, ins);
12998
12999                                 MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
13000                                 MONO_ADD_INS (cfg->cbb, ins);
13001
13002                                 sp = stack_start;
13003                                 link_bblock (cfg, cfg->cbb, end_bblock);
13004                                 start_new_bblock = 1;
13005                                 ip += 2;
13006                                 break;
13007                         }
13008                         case CEE_SIZEOF: {
13009                                 guint32 val;
13010                                 int ialign;
13011
13012                                 CHECK_STACK_OVF (1);
13013                                 CHECK_OPSIZE (6);
13014                                 token = read32 (ip + 2);
13015                                 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC && !image_is_dynamic (method->klass->image) && !generic_context) {
13016                                         MonoType *type = mono_type_create_from_typespec_checked (image, token, &cfg->error);
13017                                         CHECK_CFG_ERROR;
13018
13019                                         val = mono_type_size (type, &ialign);
13020                                 } else {
13021                                         MonoClass *klass = mini_get_class (method, token, generic_context);
13022                                         CHECK_TYPELOAD (klass);
13023
13024                                         val = mono_type_size (&klass->byval_arg, &ialign);
13025
13026                                         if (mini_is_gsharedvt_klass (klass))
13027                                                 GSHAREDVT_FAILURE (*ip);
13028                                 }
13029                                 EMIT_NEW_ICONST (cfg, ins, val);
13030                                 *sp++= ins;
13031                                 ip += 6;
13032                                 break;
13033                         }
13034                         case CEE_REFANYTYPE: {
13035                                 MonoInst *src_var, *src;
13036
13037                                 GSHAREDVT_FAILURE (*ip);
13038
13039                                 CHECK_STACK (1);
13040                                 --sp;
13041
13042                                 // FIXME:
13043                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
13044                                 if (!src_var)
13045                                         src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
13046                                 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
13047                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &mono_defaults.typehandle_class->byval_arg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type));
13048                                 *sp++ = ins;
13049                                 ip += 2;
13050                                 break;
13051                         }
13052                         case CEE_READONLY_:
13053                                 readonly = TRUE;
13054                                 ip += 2;
13055                                 break;
13056
13057                         case CEE_UNUSED56:
13058                         case CEE_UNUSED57:
13059                         case CEE_UNUSED70:
13060                         case CEE_UNUSED:
13061                         case CEE_UNUSED99:
13062                                 UNVERIFIED;
13063                                 
13064                         default:
13065                                 g_warning ("opcode 0xfe 0x%02x not handled", ip [1]);
13066                                 UNVERIFIED;
13067                         }
13068                         break;
13069                 }
13070                 case CEE_UNUSED58:
13071                 case CEE_UNUSED1:
13072                         UNVERIFIED;
13073
13074                 default:
13075                         g_warning ("opcode 0x%02x not handled", *ip);
13076                         UNVERIFIED;
13077                 }
13078         }
13079         if (start_new_bblock != 1)
13080                 UNVERIFIED;
13081
13082         cfg->cbb->cil_length = ip - cfg->cbb->cil_code;
13083         if (cfg->cbb->next_bb) {
13084                 /* This could already be set because of inlining, #693905 */
13085                 MonoBasicBlock *bb = cfg->cbb;
13086
13087                 while (bb->next_bb)
13088                         bb = bb->next_bb;
13089                 bb->next_bb = end_bblock;
13090         } else {
13091                 cfg->cbb->next_bb = end_bblock;
13092         }
13093
13094         if (cfg->method == method && cfg->domainvar) {
13095                 MonoInst *store;
13096                 MonoInst *get_domain;
13097
13098                 cfg->cbb = init_localsbb;
13099
13100                 if ((get_domain = mono_get_domain_intrinsic (cfg))) {
13101                         MONO_ADD_INS (cfg->cbb, get_domain);
13102                 } else {
13103                         get_domain = mono_emit_jit_icall (cfg, mono_domain_get, NULL);
13104                 }
13105                 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, get_domain);
13106                 MONO_ADD_INS (cfg->cbb, store);
13107         }
13108
13109 #if defined(TARGET_POWERPC) || defined(TARGET_X86)
13110         if (cfg->compile_aot)
13111                 /* FIXME: The plt slots require a GOT var even if the method doesn't use it */
13112                 mono_get_got_var (cfg);
13113 #endif
13114
13115         if (cfg->method == method && cfg->got_var)
13116                 mono_emit_load_got_addr (cfg);
13117
13118         if (init_localsbb) {
13119                 cfg->cbb = init_localsbb;
13120                 cfg->ip = NULL;
13121                 for (i = 0; i < header->num_locals; ++i) {
13122                         emit_init_local (cfg, i, header->locals [i], init_locals);
13123                 }
13124         }
13125
13126         if (cfg->init_ref_vars && cfg->method == method) {
13127                 /* Emit initialization for ref vars */
13128                 // FIXME: Avoid duplication initialization for IL locals.
13129                 for (i = 0; i < cfg->num_varinfo; ++i) {
13130                         MonoInst *ins = cfg->varinfo [i];
13131
13132                         if (ins->opcode == OP_LOCAL && ins->type == STACK_OBJ)
13133                                 MONO_EMIT_NEW_PCONST (cfg, ins->dreg, NULL);
13134                 }
13135         }
13136
13137         if (cfg->lmf_var && cfg->method == method && !cfg->llvm_only) {
13138                 cfg->cbb = init_localsbb;
13139                 emit_push_lmf (cfg);
13140         }
13141
13142         cfg->cbb = init_localsbb;
13143         emit_instrumentation_call (cfg, mono_profiler_method_enter);
13144
13145         if (seq_points) {
13146                 MonoBasicBlock *bb;
13147
13148                 /*
13149                  * Make seq points at backward branch targets interruptable.
13150                  */
13151                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
13152                         if (bb->code && bb->in_count > 1 && bb->code->opcode == OP_SEQ_POINT)
13153                                 bb->code->flags |= MONO_INST_SINGLE_STEP_LOC;
13154         }
13155
13156         /* Add a sequence point for method entry/exit events */
13157         if (seq_points && cfg->gen_sdb_seq_points) {
13158                 NEW_SEQ_POINT (cfg, ins, METHOD_ENTRY_IL_OFFSET, FALSE);
13159                 MONO_ADD_INS (init_localsbb, ins);
13160                 NEW_SEQ_POINT (cfg, ins, METHOD_EXIT_IL_OFFSET, FALSE);
13161                 MONO_ADD_INS (cfg->bb_exit, ins);
13162         }
13163
13164         /*
13165          * Add seq points for IL offsets which have line number info, but wasn't generated a seq point during JITting because
13166          * the code they refer to was dead (#11880).
13167          */
13168         if (sym_seq_points) {
13169                 for (i = 0; i < header->code_size; ++i) {
13170                         if (mono_bitset_test_fast (seq_point_locs, i) && !mono_bitset_test_fast (seq_point_set_locs, i)) {
13171                                 MonoInst *ins;
13172
13173                                 NEW_SEQ_POINT (cfg, ins, i, FALSE);
13174                                 mono_add_seq_point (cfg, NULL, ins, SEQ_POINT_NATIVE_OFFSET_DEAD_CODE);
13175                         }
13176                 }
13177         }
13178
13179         cfg->ip = NULL;
13180
13181         if (cfg->method == method) {
13182                 MonoBasicBlock *bb;
13183                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13184                         bb->region = mono_find_block_region (cfg, bb->real_offset);
13185                         if (cfg->spvars)
13186                                 mono_create_spvar_for_region (cfg, bb->region);
13187                         if (cfg->verbose_level > 2)
13188                                 printf ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
13189                 }
13190         }
13191
13192         if (inline_costs < 0) {
13193                 char *mname;
13194
13195                 /* Method is too large */
13196                 mname = mono_method_full_name (method, TRUE);
13197                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
13198                 cfg->exception_message = g_strdup_printf ("Method %s is too complex.", mname);
13199                 g_free (mname);
13200         }
13201
13202         if ((cfg->verbose_level > 2) && (cfg->method == method)) 
13203                 mono_print_code (cfg, "AFTER METHOD-TO-IR");
13204
13205         goto cleanup;
13206
13207 mono_error_exit:
13208         g_assert (!mono_error_ok (&cfg->error));
13209         goto cleanup;
13210  
13211  exception_exit:
13212         g_assert (cfg->exception_type != MONO_EXCEPTION_NONE);
13213         goto cleanup;
13214
13215  unverified:
13216         set_exception_type_from_invalid_il (cfg, method, ip);
13217         goto cleanup;
13218
13219  cleanup:
13220         g_slist_free (class_inits);
13221         mono_basic_block_free (original_bb);
13222         cfg->dont_inline = g_list_remove (cfg->dont_inline, method);
13223         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
13224         if (cfg->exception_type)
13225                 return -1;
13226         else
13227                 return inline_costs;
13228 }
13229
13230 static int
13231 store_membase_reg_to_store_membase_imm (int opcode)
13232 {
13233         switch (opcode) {
13234         case OP_STORE_MEMBASE_REG:
13235                 return OP_STORE_MEMBASE_IMM;
13236         case OP_STOREI1_MEMBASE_REG:
13237                 return OP_STOREI1_MEMBASE_IMM;
13238         case OP_STOREI2_MEMBASE_REG:
13239                 return OP_STOREI2_MEMBASE_IMM;
13240         case OP_STOREI4_MEMBASE_REG:
13241                 return OP_STOREI4_MEMBASE_IMM;
13242         case OP_STOREI8_MEMBASE_REG:
13243                 return OP_STOREI8_MEMBASE_IMM;
13244         default:
13245                 g_assert_not_reached ();
13246         }
13247
13248         return -1;
13249 }               
13250
13251 int
13252 mono_op_to_op_imm (int opcode)
13253 {
13254         switch (opcode) {
13255         case OP_IADD:
13256                 return OP_IADD_IMM;
13257         case OP_ISUB:
13258                 return OP_ISUB_IMM;
13259         case OP_IDIV:
13260                 return OP_IDIV_IMM;
13261         case OP_IDIV_UN:
13262                 return OP_IDIV_UN_IMM;
13263         case OP_IREM:
13264                 return OP_IREM_IMM;
13265         case OP_IREM_UN:
13266                 return OP_IREM_UN_IMM;
13267         case OP_IMUL:
13268                 return OP_IMUL_IMM;
13269         case OP_IAND:
13270                 return OP_IAND_IMM;
13271         case OP_IOR:
13272                 return OP_IOR_IMM;
13273         case OP_IXOR:
13274                 return OP_IXOR_IMM;
13275         case OP_ISHL:
13276                 return OP_ISHL_IMM;
13277         case OP_ISHR:
13278                 return OP_ISHR_IMM;
13279         case OP_ISHR_UN:
13280                 return OP_ISHR_UN_IMM;
13281
13282         case OP_LADD:
13283                 return OP_LADD_IMM;
13284         case OP_LSUB:
13285                 return OP_LSUB_IMM;
13286         case OP_LAND:
13287                 return OP_LAND_IMM;
13288         case OP_LOR:
13289                 return OP_LOR_IMM;
13290         case OP_LXOR:
13291                 return OP_LXOR_IMM;
13292         case OP_LSHL:
13293                 return OP_LSHL_IMM;
13294         case OP_LSHR:
13295                 return OP_LSHR_IMM;
13296         case OP_LSHR_UN:
13297                 return OP_LSHR_UN_IMM;
13298 #if SIZEOF_REGISTER == 8
13299         case OP_LREM:
13300                 return OP_LREM_IMM;
13301 #endif
13302
13303         case OP_COMPARE:
13304                 return OP_COMPARE_IMM;
13305         case OP_ICOMPARE:
13306                 return OP_ICOMPARE_IMM;
13307         case OP_LCOMPARE:
13308                 return OP_LCOMPARE_IMM;
13309
13310         case OP_STORE_MEMBASE_REG:
13311                 return OP_STORE_MEMBASE_IMM;
13312         case OP_STOREI1_MEMBASE_REG:
13313                 return OP_STOREI1_MEMBASE_IMM;
13314         case OP_STOREI2_MEMBASE_REG:
13315                 return OP_STOREI2_MEMBASE_IMM;
13316         case OP_STOREI4_MEMBASE_REG:
13317                 return OP_STOREI4_MEMBASE_IMM;
13318
13319 #if defined(TARGET_X86) || defined (TARGET_AMD64)
13320         case OP_X86_PUSH:
13321                 return OP_X86_PUSH_IMM;
13322         case OP_X86_COMPARE_MEMBASE_REG:
13323                 return OP_X86_COMPARE_MEMBASE_IMM;
13324 #endif
13325 #if defined(TARGET_AMD64)
13326         case OP_AMD64_ICOMPARE_MEMBASE_REG:
13327                 return OP_AMD64_ICOMPARE_MEMBASE_IMM;
13328 #endif
13329         case OP_VOIDCALL_REG:
13330                 return OP_VOIDCALL;
13331         case OP_CALL_REG:
13332                 return OP_CALL;
13333         case OP_LCALL_REG:
13334                 return OP_LCALL;
13335         case OP_FCALL_REG:
13336                 return OP_FCALL;
13337         case OP_LOCALLOC:
13338                 return OP_LOCALLOC_IMM;
13339         }
13340
13341         return -1;
13342 }
13343
13344 static int
13345 ldind_to_load_membase (int opcode)
13346 {
13347         switch (opcode) {
13348         case CEE_LDIND_I1:
13349                 return OP_LOADI1_MEMBASE;
13350         case CEE_LDIND_U1:
13351                 return OP_LOADU1_MEMBASE;
13352         case CEE_LDIND_I2:
13353                 return OP_LOADI2_MEMBASE;
13354         case CEE_LDIND_U2:
13355                 return OP_LOADU2_MEMBASE;
13356         case CEE_LDIND_I4:
13357                 return OP_LOADI4_MEMBASE;
13358         case CEE_LDIND_U4:
13359                 return OP_LOADU4_MEMBASE;
13360         case CEE_LDIND_I:
13361                 return OP_LOAD_MEMBASE;
13362         case CEE_LDIND_REF:
13363                 return OP_LOAD_MEMBASE;
13364         case CEE_LDIND_I8:
13365                 return OP_LOADI8_MEMBASE;
13366         case CEE_LDIND_R4:
13367                 return OP_LOADR4_MEMBASE;
13368         case CEE_LDIND_R8:
13369                 return OP_LOADR8_MEMBASE;
13370         default:
13371                 g_assert_not_reached ();
13372         }
13373
13374         return -1;
13375 }
13376
13377 static int
13378 stind_to_store_membase (int opcode)
13379 {
13380         switch (opcode) {
13381         case CEE_STIND_I1:
13382                 return OP_STOREI1_MEMBASE_REG;
13383         case CEE_STIND_I2:
13384                 return OP_STOREI2_MEMBASE_REG;
13385         case CEE_STIND_I4:
13386                 return OP_STOREI4_MEMBASE_REG;
13387         case CEE_STIND_I:
13388         case CEE_STIND_REF:
13389                 return OP_STORE_MEMBASE_REG;
13390         case CEE_STIND_I8:
13391                 return OP_STOREI8_MEMBASE_REG;
13392         case CEE_STIND_R4:
13393                 return OP_STORER4_MEMBASE_REG;
13394         case CEE_STIND_R8:
13395                 return OP_STORER8_MEMBASE_REG;
13396         default:
13397                 g_assert_not_reached ();
13398         }
13399
13400         return -1;
13401 }
13402
13403 int
13404 mono_load_membase_to_load_mem (int opcode)
13405 {
13406         // FIXME: Add a MONO_ARCH_HAVE_LOAD_MEM macro
13407 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13408         switch (opcode) {
13409         case OP_LOAD_MEMBASE:
13410                 return OP_LOAD_MEM;
13411         case OP_LOADU1_MEMBASE:
13412                 return OP_LOADU1_MEM;
13413         case OP_LOADU2_MEMBASE:
13414                 return OP_LOADU2_MEM;
13415         case OP_LOADI4_MEMBASE:
13416                 return OP_LOADI4_MEM;
13417         case OP_LOADU4_MEMBASE:
13418                 return OP_LOADU4_MEM;
13419 #if SIZEOF_REGISTER == 8
13420         case OP_LOADI8_MEMBASE:
13421                 return OP_LOADI8_MEM;
13422 #endif
13423         }
13424 #endif
13425
13426         return -1;
13427 }
13428
13429 static inline int
13430 op_to_op_dest_membase (int store_opcode, int opcode)
13431 {
13432 #if defined(TARGET_X86)
13433         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG)))
13434                 return -1;
13435
13436         switch (opcode) {
13437         case OP_IADD:
13438                 return OP_X86_ADD_MEMBASE_REG;
13439         case OP_ISUB:
13440                 return OP_X86_SUB_MEMBASE_REG;
13441         case OP_IAND:
13442                 return OP_X86_AND_MEMBASE_REG;
13443         case OP_IOR:
13444                 return OP_X86_OR_MEMBASE_REG;
13445         case OP_IXOR:
13446                 return OP_X86_XOR_MEMBASE_REG;
13447         case OP_ADD_IMM:
13448         case OP_IADD_IMM:
13449                 return OP_X86_ADD_MEMBASE_IMM;
13450         case OP_SUB_IMM:
13451         case OP_ISUB_IMM:
13452                 return OP_X86_SUB_MEMBASE_IMM;
13453         case OP_AND_IMM:
13454         case OP_IAND_IMM:
13455                 return OP_X86_AND_MEMBASE_IMM;
13456         case OP_OR_IMM:
13457         case OP_IOR_IMM:
13458                 return OP_X86_OR_MEMBASE_IMM;
13459         case OP_XOR_IMM:
13460         case OP_IXOR_IMM:
13461                 return OP_X86_XOR_MEMBASE_IMM;
13462         case OP_MOVE:
13463                 return OP_NOP;
13464         }
13465 #endif
13466
13467 #if defined(TARGET_AMD64)
13468         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG) || (store_opcode == OP_STOREI8_MEMBASE_REG)))
13469                 return -1;
13470
13471         switch (opcode) {
13472         case OP_IADD:
13473                 return OP_X86_ADD_MEMBASE_REG;
13474         case OP_ISUB:
13475                 return OP_X86_SUB_MEMBASE_REG;
13476         case OP_IAND:
13477                 return OP_X86_AND_MEMBASE_REG;
13478         case OP_IOR:
13479                 return OP_X86_OR_MEMBASE_REG;
13480         case OP_IXOR:
13481                 return OP_X86_XOR_MEMBASE_REG;
13482         case OP_IADD_IMM:
13483                 return OP_X86_ADD_MEMBASE_IMM;
13484         case OP_ISUB_IMM:
13485                 return OP_X86_SUB_MEMBASE_IMM;
13486         case OP_IAND_IMM:
13487                 return OP_X86_AND_MEMBASE_IMM;
13488         case OP_IOR_IMM:
13489                 return OP_X86_OR_MEMBASE_IMM;
13490         case OP_IXOR_IMM:
13491                 return OP_X86_XOR_MEMBASE_IMM;
13492         case OP_LADD:
13493                 return OP_AMD64_ADD_MEMBASE_REG;
13494         case OP_LSUB:
13495                 return OP_AMD64_SUB_MEMBASE_REG;
13496         case OP_LAND:
13497                 return OP_AMD64_AND_MEMBASE_REG;
13498         case OP_LOR:
13499                 return OP_AMD64_OR_MEMBASE_REG;
13500         case OP_LXOR:
13501                 return OP_AMD64_XOR_MEMBASE_REG;
13502         case OP_ADD_IMM:
13503         case OP_LADD_IMM:
13504                 return OP_AMD64_ADD_MEMBASE_IMM;
13505         case OP_SUB_IMM:
13506         case OP_LSUB_IMM:
13507                 return OP_AMD64_SUB_MEMBASE_IMM;
13508         case OP_AND_IMM:
13509         case OP_LAND_IMM:
13510                 return OP_AMD64_AND_MEMBASE_IMM;
13511         case OP_OR_IMM:
13512         case OP_LOR_IMM:
13513                 return OP_AMD64_OR_MEMBASE_IMM;
13514         case OP_XOR_IMM:
13515         case OP_LXOR_IMM:
13516                 return OP_AMD64_XOR_MEMBASE_IMM;
13517         case OP_MOVE:
13518                 return OP_NOP;
13519         }
13520 #endif
13521
13522         return -1;
13523 }
13524
13525 static inline int
13526 op_to_op_store_membase (int store_opcode, int opcode)
13527 {
13528 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13529         switch (opcode) {
13530         case OP_ICEQ:
13531                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13532                         return OP_X86_SETEQ_MEMBASE;
13533         case OP_CNE:
13534                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13535                         return OP_X86_SETNE_MEMBASE;
13536         }
13537 #endif
13538
13539         return -1;
13540 }
13541
13542 static inline int
13543 op_to_op_src1_membase (MonoCompile *cfg, int load_opcode, int opcode)
13544 {
13545 #ifdef TARGET_X86
13546         /* FIXME: This has sign extension issues */
13547         /*
13548         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
13549                 return OP_X86_COMPARE_MEMBASE8_IMM;
13550         */
13551
13552         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
13553                 return -1;
13554
13555         switch (opcode) {
13556         case OP_X86_PUSH:
13557                 return OP_X86_PUSH_MEMBASE;
13558         case OP_COMPARE_IMM:
13559         case OP_ICOMPARE_IMM:
13560                 return OP_X86_COMPARE_MEMBASE_IMM;
13561         case OP_COMPARE:
13562         case OP_ICOMPARE:
13563                 return OP_X86_COMPARE_MEMBASE_REG;
13564         }
13565 #endif
13566
13567 #ifdef TARGET_AMD64
13568         /* FIXME: This has sign extension issues */
13569         /*
13570         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
13571                 return OP_X86_COMPARE_MEMBASE8_IMM;
13572         */
13573
13574         switch (opcode) {
13575         case OP_X86_PUSH:
13576                 if ((load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32) || (load_opcode == OP_LOADI8_MEMBASE))
13577                         return OP_X86_PUSH_MEMBASE;
13578                 break;
13579                 /* FIXME: This only works for 32 bit immediates
13580         case OP_COMPARE_IMM:
13581         case OP_LCOMPARE_IMM:
13582                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
13583                         return OP_AMD64_COMPARE_MEMBASE_IMM;
13584                 */
13585         case OP_ICOMPARE_IMM:
13586                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
13587                         return OP_AMD64_ICOMPARE_MEMBASE_IMM;
13588                 break;
13589         case OP_COMPARE:
13590         case OP_LCOMPARE:
13591                 if (cfg->backend->ilp32 && load_opcode == OP_LOAD_MEMBASE)
13592                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
13593                 if ((load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32) || (load_opcode == OP_LOADI8_MEMBASE))
13594                         return OP_AMD64_COMPARE_MEMBASE_REG;
13595                 break;
13596         case OP_ICOMPARE:
13597                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
13598                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
13599                 break;
13600         }
13601 #endif
13602
13603         return -1;
13604 }
13605
13606 static inline int
13607 op_to_op_src2_membase (MonoCompile *cfg, int load_opcode, int opcode)
13608 {
13609 #ifdef TARGET_X86
13610         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
13611                 return -1;
13612         
13613         switch (opcode) {
13614         case OP_COMPARE:
13615         case OP_ICOMPARE:
13616                 return OP_X86_COMPARE_REG_MEMBASE;
13617         case OP_IADD:
13618                 return OP_X86_ADD_REG_MEMBASE;
13619         case OP_ISUB:
13620                 return OP_X86_SUB_REG_MEMBASE;
13621         case OP_IAND:
13622                 return OP_X86_AND_REG_MEMBASE;
13623         case OP_IOR:
13624                 return OP_X86_OR_REG_MEMBASE;
13625         case OP_IXOR:
13626                 return OP_X86_XOR_REG_MEMBASE;
13627         }
13628 #endif
13629
13630 #ifdef TARGET_AMD64
13631         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE && cfg->backend->ilp32)) {
13632                 switch (opcode) {
13633                 case OP_ICOMPARE:
13634                         return OP_AMD64_ICOMPARE_REG_MEMBASE;
13635                 case OP_IADD:
13636                         return OP_X86_ADD_REG_MEMBASE;
13637                 case OP_ISUB:
13638                         return OP_X86_SUB_REG_MEMBASE;
13639                 case OP_IAND:
13640                         return OP_X86_AND_REG_MEMBASE;
13641                 case OP_IOR:
13642                         return OP_X86_OR_REG_MEMBASE;
13643                 case OP_IXOR:
13644                         return OP_X86_XOR_REG_MEMBASE;
13645                 }
13646         } else if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32)) {
13647                 switch (opcode) {
13648                 case OP_COMPARE:
13649                 case OP_LCOMPARE:
13650                         return OP_AMD64_COMPARE_REG_MEMBASE;
13651                 case OP_LADD:
13652                         return OP_AMD64_ADD_REG_MEMBASE;
13653                 case OP_LSUB:
13654                         return OP_AMD64_SUB_REG_MEMBASE;
13655                 case OP_LAND:
13656                         return OP_AMD64_AND_REG_MEMBASE;
13657                 case OP_LOR:
13658                         return OP_AMD64_OR_REG_MEMBASE;
13659                 case OP_LXOR:
13660                         return OP_AMD64_XOR_REG_MEMBASE;
13661                 }
13662         }
13663 #endif
13664
13665         return -1;
13666 }
13667
13668 int
13669 mono_op_to_op_imm_noemul (int opcode)
13670 {
13671         switch (opcode) {
13672 #if SIZEOF_REGISTER == 4 && !defined(MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS)
13673         case OP_LSHR:
13674         case OP_LSHL:
13675         case OP_LSHR_UN:
13676                 return -1;
13677 #endif
13678 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
13679         case OP_IDIV:
13680         case OP_IDIV_UN:
13681         case OP_IREM:
13682         case OP_IREM_UN:
13683                 return -1;
13684 #endif
13685 #if defined(MONO_ARCH_EMULATE_MUL_DIV)
13686         case OP_IMUL:
13687                 return -1;
13688 #endif
13689         default:
13690                 return mono_op_to_op_imm (opcode);
13691         }
13692 }
13693
13694 /**
13695  * mono_handle_global_vregs:
13696  *
13697  *   Make vregs used in more than one bblock 'global', i.e. allocate a variable
13698  * for them.
13699  */
13700 void
13701 mono_handle_global_vregs (MonoCompile *cfg)
13702 {
13703         gint32 *vreg_to_bb;
13704         MonoBasicBlock *bb;
13705         int i, pos;
13706
13707         vreg_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (gint32*) * cfg->next_vreg + 1);
13708
13709 #ifdef MONO_ARCH_SIMD_INTRINSICS
13710         if (cfg->uses_simd_intrinsics)
13711                 mono_simd_simplify_indirection (cfg);
13712 #endif
13713
13714         /* Find local vregs used in more than one bb */
13715         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13716                 MonoInst *ins = bb->code;       
13717                 int block_num = bb->block_num;
13718
13719                 if (cfg->verbose_level > 2)
13720                         printf ("\nHANDLE-GLOBAL-VREGS BLOCK %d:\n", bb->block_num);
13721
13722                 cfg->cbb = bb;
13723                 for (; ins; ins = ins->next) {
13724                         const char *spec = INS_INFO (ins->opcode);
13725                         int regtype = 0, regindex;
13726                         gint32 prev_bb;
13727
13728                         if (G_UNLIKELY (cfg->verbose_level > 2))
13729                                 mono_print_ins (ins);
13730
13731                         g_assert (ins->opcode >= MONO_CEE_LAST);
13732
13733                         for (regindex = 0; regindex < 4; regindex ++) {
13734                                 int vreg = 0;
13735
13736                                 if (regindex == 0) {
13737                                         regtype = spec [MONO_INST_DEST];
13738                                         if (regtype == ' ')
13739                                                 continue;
13740                                         vreg = ins->dreg;
13741                                 } else if (regindex == 1) {
13742                                         regtype = spec [MONO_INST_SRC1];
13743                                         if (regtype == ' ')
13744                                                 continue;
13745                                         vreg = ins->sreg1;
13746                                 } else if (regindex == 2) {
13747                                         regtype = spec [MONO_INST_SRC2];
13748                                         if (regtype == ' ')
13749                                                 continue;
13750                                         vreg = ins->sreg2;
13751                                 } else if (regindex == 3) {
13752                                         regtype = spec [MONO_INST_SRC3];
13753                                         if (regtype == ' ')
13754                                                 continue;
13755                                         vreg = ins->sreg3;
13756                                 }
13757
13758 #if SIZEOF_REGISTER == 4
13759                                 /* In the LLVM case, the long opcodes are not decomposed */
13760                                 if (regtype == 'l' && !COMPILE_LLVM (cfg)) {
13761                                         /*
13762                                          * Since some instructions reference the original long vreg,
13763                                          * and some reference the two component vregs, it is quite hard
13764                                          * to determine when it needs to be global. So be conservative.
13765                                          */
13766                                         if (!get_vreg_to_inst (cfg, vreg)) {
13767                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
13768
13769                                                 if (cfg->verbose_level > 2)
13770                                                         printf ("LONG VREG R%d made global.\n", vreg);
13771                                         }
13772
13773                                         /*
13774                                          * Make the component vregs volatile since the optimizations can
13775                                          * get confused otherwise.
13776                                          */
13777                                         get_vreg_to_inst (cfg, vreg + 1)->flags |= MONO_INST_VOLATILE;
13778                                         get_vreg_to_inst (cfg, vreg + 2)->flags |= MONO_INST_VOLATILE;
13779                                 }
13780 #endif
13781
13782                                 g_assert (vreg != -1);
13783
13784                                 prev_bb = vreg_to_bb [vreg];
13785                                 if (prev_bb == 0) {
13786                                         /* 0 is a valid block num */
13787                                         vreg_to_bb [vreg] = block_num + 1;
13788                                 } else if ((prev_bb != block_num + 1) && (prev_bb != -1)) {
13789                                         if (((regtype == 'i' && (vreg < MONO_MAX_IREGS))) || (regtype == 'f' && (vreg < MONO_MAX_FREGS)))
13790                                                 continue;
13791
13792                                         if (!get_vreg_to_inst (cfg, vreg)) {
13793                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
13794                                                         printf ("VREG R%d used in BB%d and BB%d made global.\n", vreg, vreg_to_bb [vreg], block_num);
13795
13796                                                 switch (regtype) {
13797                                                 case 'i':
13798                                                         if (vreg_is_ref (cfg, vreg))
13799                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL, vreg);
13800                                                         else
13801                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL, vreg);
13802                                                         break;
13803                                                 case 'l':
13804                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
13805                                                         break;
13806                                                 case 'f':
13807                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL, vreg);
13808                                                         break;
13809                                                 case 'v':
13810                                                         mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, vreg);
13811                                                         break;
13812                                                 default:
13813                                                         g_assert_not_reached ();
13814                                                 }
13815                                         }
13816
13817                                         /* Flag as having been used in more than one bb */
13818                                         vreg_to_bb [vreg] = -1;
13819                                 }
13820                         }
13821                 }
13822         }
13823
13824         /* If a variable is used in only one bblock, convert it into a local vreg */
13825         for (i = 0; i < cfg->num_varinfo; i++) {
13826                 MonoInst *var = cfg->varinfo [i];
13827                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
13828
13829                 switch (var->type) {
13830                 case STACK_I4:
13831                 case STACK_OBJ:
13832                 case STACK_PTR:
13833                 case STACK_MP:
13834                 case STACK_VTYPE:
13835 #if SIZEOF_REGISTER == 8
13836                 case STACK_I8:
13837 #endif
13838 #if !defined(TARGET_X86)
13839                 /* Enabling this screws up the fp stack on x86 */
13840                 case STACK_R8:
13841 #endif
13842                         if (mono_arch_is_soft_float ())
13843                                 break;
13844
13845                         /* Arguments are implicitly global */
13846                         /* Putting R4 vars into registers doesn't work currently */
13847                         /* The gsharedvt vars are implicitly referenced by ldaddr opcodes, but those opcodes are only generated later */
13848                         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) {
13849                                 /* 
13850                                  * Make that the variable's liveness interval doesn't contain a call, since
13851                                  * that would cause the lvreg to be spilled, making the whole optimization
13852                                  * useless.
13853                                  */
13854                                 /* This is too slow for JIT compilation */
13855 #if 0
13856                                 if (cfg->compile_aot && vreg_to_bb [var->dreg]) {
13857                                         MonoInst *ins;
13858                                         int def_index, call_index, ins_index;
13859                                         gboolean spilled = FALSE;
13860
13861                                         def_index = -1;
13862                                         call_index = -1;
13863                                         ins_index = 0;
13864                                         for (ins = vreg_to_bb [var->dreg]->code; ins; ins = ins->next) {
13865                                                 const char *spec = INS_INFO (ins->opcode);
13866
13867                                                 if ((spec [MONO_INST_DEST] != ' ') && (ins->dreg == var->dreg))
13868                                                         def_index = ins_index;
13869
13870                                                 if (((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg)) ||
13871                                                         ((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg))) {
13872                                                         if (call_index > def_index) {
13873                                                                 spilled = TRUE;
13874                                                                 break;
13875                                                         }
13876                                                 }
13877
13878                                                 if (MONO_IS_CALL (ins))
13879                                                         call_index = ins_index;
13880
13881                                                 ins_index ++;
13882                                         }
13883
13884                                         if (spilled)
13885                                                 break;
13886                                 }
13887 #endif
13888
13889                                 if (G_UNLIKELY (cfg->verbose_level > 2))
13890                                         printf ("CONVERTED R%d(%d) TO VREG.\n", var->dreg, vmv->idx);
13891                                 var->flags |= MONO_INST_IS_DEAD;
13892                                 cfg->vreg_to_inst [var->dreg] = NULL;
13893                         }
13894                         break;
13895                 }
13896         }
13897
13898         /* 
13899          * Compress the varinfo and vars tables so the liveness computation is faster and
13900          * takes up less space.
13901          */
13902         pos = 0;
13903         for (i = 0; i < cfg->num_varinfo; ++i) {
13904                 MonoInst *var = cfg->varinfo [i];
13905                 if (pos < i && cfg->locals_start == i)
13906                         cfg->locals_start = pos;
13907                 if (!(var->flags & MONO_INST_IS_DEAD)) {
13908                         if (pos < i) {
13909                                 cfg->varinfo [pos] = cfg->varinfo [i];
13910                                 cfg->varinfo [pos]->inst_c0 = pos;
13911                                 memcpy (&cfg->vars [pos], &cfg->vars [i], sizeof (MonoMethodVar));
13912                                 cfg->vars [pos].idx = pos;
13913 #if SIZEOF_REGISTER == 4
13914                                 if (cfg->varinfo [pos]->type == STACK_I8) {
13915                                         /* Modify the two component vars too */
13916                                         MonoInst *var1;
13917
13918                                         var1 = get_vreg_to_inst (cfg, cfg->varinfo [pos]->dreg + 1);
13919                                         var1->inst_c0 = pos;
13920                                         var1 = get_vreg_to_inst (cfg, cfg->varinfo [pos]->dreg + 2);
13921                                         var1->inst_c0 = pos;
13922                                 }
13923 #endif
13924                         }
13925                         pos ++;
13926                 }
13927         }
13928         cfg->num_varinfo = pos;
13929         if (cfg->locals_start > cfg->num_varinfo)
13930                 cfg->locals_start = cfg->num_varinfo;
13931 }
13932
13933 /**
13934  * mono_spill_global_vars:
13935  *
13936  *   Generate spill code for variables which are not allocated to registers, 
13937  * and replace vregs with their allocated hregs. *need_local_opts is set to TRUE if
13938  * code is generated which could be optimized by the local optimization passes.
13939  */
13940 void
13941 mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
13942 {
13943         MonoBasicBlock *bb;
13944         char spec2 [16];
13945         int orig_next_vreg;
13946         guint32 *vreg_to_lvreg;
13947         guint32 *lvregs;
13948         guint32 i, lvregs_len;
13949         gboolean dest_has_lvreg = FALSE;
13950         guint32 stacktypes [128];
13951         MonoInst **live_range_start, **live_range_end;
13952         MonoBasicBlock **live_range_start_bb, **live_range_end_bb;
13953         int *gsharedvt_vreg_to_idx = NULL;
13954
13955         *need_local_opts = FALSE;
13956
13957         memset (spec2, 0, sizeof (spec2));
13958
13959         /* FIXME: Move this function to mini.c */
13960         stacktypes ['i'] = STACK_PTR;
13961         stacktypes ['l'] = STACK_I8;
13962         stacktypes ['f'] = STACK_R8;
13963 #ifdef MONO_ARCH_SIMD_INTRINSICS
13964         stacktypes ['x'] = STACK_VTYPE;
13965 #endif
13966
13967 #if SIZEOF_REGISTER == 4
13968         /* Create MonoInsts for longs */
13969         for (i = 0; i < cfg->num_varinfo; i++) {
13970                 MonoInst *ins = cfg->varinfo [i];
13971
13972                 if ((ins->opcode != OP_REGVAR) && !(ins->flags & MONO_INST_IS_DEAD)) {
13973                         switch (ins->type) {
13974                         case STACK_R8:
13975                         case STACK_I8: {
13976                                 MonoInst *tree;
13977
13978                                 if (ins->type == STACK_R8 && !COMPILE_SOFT_FLOAT (cfg))
13979                                         break;
13980
13981                                 g_assert (ins->opcode == OP_REGOFFSET);
13982
13983                                 tree = get_vreg_to_inst (cfg, ins->dreg + 1);
13984                                 g_assert (tree);
13985                                 tree->opcode = OP_REGOFFSET;
13986                                 tree->inst_basereg = ins->inst_basereg;
13987                                 tree->inst_offset = ins->inst_offset + MINI_LS_WORD_OFFSET;
13988
13989                                 tree = get_vreg_to_inst (cfg, ins->dreg + 2);
13990                                 g_assert (tree);
13991                                 tree->opcode = OP_REGOFFSET;
13992                                 tree->inst_basereg = ins->inst_basereg;
13993                                 tree->inst_offset = ins->inst_offset + MINI_MS_WORD_OFFSET;
13994                                 break;
13995                         }
13996                         default:
13997                                 break;
13998                         }
13999                 }
14000         }
14001 #endif
14002
14003         if (cfg->compute_gc_maps) {
14004                 /* registers need liveness info even for !non refs */
14005                 for (i = 0; i < cfg->num_varinfo; i++) {
14006                         MonoInst *ins = cfg->varinfo [i];
14007
14008                         if (ins->opcode == OP_REGVAR)
14009                                 ins->flags |= MONO_INST_GC_TRACK;
14010                 }
14011         }
14012
14013         if (cfg->gsharedvt) {
14014                 gsharedvt_vreg_to_idx = mono_mempool_alloc0 (cfg->mempool, sizeof (int) * cfg->next_vreg);
14015
14016                 for (i = 0; i < cfg->num_varinfo; ++i) {
14017                         MonoInst *ins = cfg->varinfo [i];
14018                         int idx;
14019
14020                         if (mini_is_gsharedvt_variable_type (ins->inst_vtype)) {
14021                                 if (i >= cfg->locals_start) {
14022                                         /* Local */
14023                                         idx = get_gsharedvt_info_slot (cfg, ins->inst_vtype, MONO_RGCTX_INFO_LOCAL_OFFSET);
14024                                         gsharedvt_vreg_to_idx [ins->dreg] = idx + 1;
14025                                         ins->opcode = OP_GSHAREDVT_LOCAL;
14026                                         ins->inst_imm = idx;
14027                                 } else {
14028                                         /* Arg */
14029                                         gsharedvt_vreg_to_idx [ins->dreg] = -1;
14030                                         ins->opcode = OP_GSHAREDVT_ARG_REGOFFSET;
14031                                 }
14032                         }
14033                 }
14034         }
14035                 
14036         /* FIXME: widening and truncation */
14037
14038         /*
14039          * As an optimization, when a variable allocated to the stack is first loaded into 
14040          * an lvreg, we will remember the lvreg and use it the next time instead of loading
14041          * the variable again.
14042          */
14043         orig_next_vreg = cfg->next_vreg;
14044         vreg_to_lvreg = mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * cfg->next_vreg);
14045         lvregs = mono_mempool_alloc (cfg->mempool, sizeof (guint32) * 1024);
14046         lvregs_len = 0;
14047
14048         /* 
14049          * These arrays contain the first and last instructions accessing a given
14050          * variable.
14051          * Since we emit bblocks in the same order we process them here, and we
14052          * don't split live ranges, these will precisely describe the live range of
14053          * the variable, i.e. the instruction range where a valid value can be found
14054          * in the variables location.
14055          * The live range is computed using the liveness info computed by the liveness pass.
14056          * We can't use vmv->range, since that is an abstract live range, and we need
14057          * one which is instruction precise.
14058          * FIXME: Variables used in out-of-line bblocks have a hole in their live range.
14059          */
14060         /* FIXME: Only do this if debugging info is requested */
14061         live_range_start = g_new0 (MonoInst*, cfg->next_vreg);
14062         live_range_end = g_new0 (MonoInst*, cfg->next_vreg);
14063         live_range_start_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
14064         live_range_end_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
14065         
14066         /* Add spill loads/stores */
14067         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
14068                 MonoInst *ins;
14069
14070                 if (cfg->verbose_level > 2)
14071                         printf ("\nSPILL BLOCK %d:\n", bb->block_num);
14072
14073                 /* Clear vreg_to_lvreg array */
14074                 for (i = 0; i < lvregs_len; i++)
14075                         vreg_to_lvreg [lvregs [i]] = 0;
14076                 lvregs_len = 0;
14077
14078                 cfg->cbb = bb;
14079                 MONO_BB_FOR_EACH_INS (bb, ins) {
14080                         const char *spec = INS_INFO (ins->opcode);
14081                         int regtype, srcindex, sreg, tmp_reg, prev_dreg, num_sregs;
14082                         gboolean store, no_lvreg;
14083                         int sregs [MONO_MAX_SRC_REGS];
14084
14085                         if (G_UNLIKELY (cfg->verbose_level > 2))
14086                                 mono_print_ins (ins);
14087
14088                         if (ins->opcode == OP_NOP)
14089                                 continue;
14090
14091                         /* 
14092                          * We handle LDADDR here as well, since it can only be decomposed
14093                          * when variable addresses are known.
14094                          */
14095                         if (ins->opcode == OP_LDADDR) {
14096                                 MonoInst *var = ins->inst_p0;
14097
14098                                 if (var->opcode == OP_VTARG_ADDR) {
14099                                         /* Happens on SPARC/S390 where vtypes are passed by reference */
14100                                         MonoInst *vtaddr = var->inst_left;
14101                                         if (vtaddr->opcode == OP_REGVAR) {
14102                                                 ins->opcode = OP_MOVE;
14103                                                 ins->sreg1 = vtaddr->dreg;
14104                                         }
14105                                         else if (var->inst_left->opcode == OP_REGOFFSET) {
14106                                                 ins->opcode = OP_LOAD_MEMBASE;
14107                                                 ins->inst_basereg = vtaddr->inst_basereg;
14108                                                 ins->inst_offset = vtaddr->inst_offset;
14109                                         } else
14110                                                 NOT_IMPLEMENTED;
14111                                 } else if (cfg->gsharedvt && gsharedvt_vreg_to_idx [var->dreg] < 0) {
14112                                         /* gsharedvt arg passed by ref */
14113                                         g_assert (var->opcode == OP_GSHAREDVT_ARG_REGOFFSET);
14114
14115                                         ins->opcode = OP_LOAD_MEMBASE;
14116                                         ins->inst_basereg = var->inst_basereg;
14117                                         ins->inst_offset = var->inst_offset;
14118                                 } else if (cfg->gsharedvt && gsharedvt_vreg_to_idx [var->dreg]) {
14119                                         MonoInst *load, *load2, *load3;
14120                                         int idx = gsharedvt_vreg_to_idx [var->dreg] - 1;
14121                                         int reg1, reg2, reg3;
14122                                         MonoInst *info_var = cfg->gsharedvt_info_var;
14123                                         MonoInst *locals_var = cfg->gsharedvt_locals_var;
14124
14125                                         /*
14126                                          * gsharedvt local.
14127                                          * Compute the address of the local as gsharedvt_locals_var + gsharedvt_info_var->locals_offsets [idx].
14128                                          */
14129
14130                                         g_assert (var->opcode == OP_GSHAREDVT_LOCAL);
14131
14132                                         g_assert (info_var);
14133                                         g_assert (locals_var);
14134
14135                                         /* Mark the instruction used to compute the locals var as used */
14136                                         cfg->gsharedvt_locals_var_ins = NULL;
14137
14138                                         /* Load the offset */
14139                                         if (info_var->opcode == OP_REGOFFSET) {
14140                                                 reg1 = alloc_ireg (cfg);
14141                                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, reg1, info_var->inst_basereg, info_var->inst_offset);
14142                                         } else if (info_var->opcode == OP_REGVAR) {
14143                                                 load = NULL;
14144                                                 reg1 = info_var->dreg;
14145                                         } else {
14146                                                 g_assert_not_reached ();
14147                                         }
14148                                         reg2 = alloc_ireg (cfg);
14149                                         NEW_LOAD_MEMBASE (cfg, load2, OP_LOADI4_MEMBASE, reg2, reg1, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
14150                                         /* Load the locals area address */
14151                                         reg3 = alloc_ireg (cfg);
14152                                         if (locals_var->opcode == OP_REGOFFSET) {
14153                                                 NEW_LOAD_MEMBASE (cfg, load3, OP_LOAD_MEMBASE, reg3, locals_var->inst_basereg, locals_var->inst_offset);
14154                                         } else if (locals_var->opcode == OP_REGVAR) {
14155                                                 NEW_UNALU (cfg, load3, OP_MOVE, reg3, locals_var->dreg);
14156                                         } else {
14157                                                 g_assert_not_reached ();
14158                                         }
14159                                         /* Compute the address */
14160                                         ins->opcode = OP_PADD;
14161                                         ins->sreg1 = reg3;
14162                                         ins->sreg2 = reg2;
14163
14164                                         mono_bblock_insert_before_ins (bb, ins, load3);
14165                                         mono_bblock_insert_before_ins (bb, load3, load2);
14166                                         if (load)
14167                                                 mono_bblock_insert_before_ins (bb, load2, load);
14168                                 } else {
14169                                         g_assert (var->opcode == OP_REGOFFSET);
14170
14171                                         ins->opcode = OP_ADD_IMM;
14172                                         ins->sreg1 = var->inst_basereg;
14173                                         ins->inst_imm = var->inst_offset;
14174                                 }
14175
14176                                 *need_local_opts = TRUE;
14177                                 spec = INS_INFO (ins->opcode);
14178                         }
14179
14180                         if (ins->opcode < MONO_CEE_LAST) {
14181                                 mono_print_ins (ins);
14182                                 g_assert_not_reached ();
14183                         }
14184
14185                         /*
14186                          * Store opcodes have destbasereg in the dreg, but in reality, it is an
14187                          * src register.
14188                          * FIXME:
14189                          */
14190                         if (MONO_IS_STORE_MEMBASE (ins)) {
14191                                 tmp_reg = ins->dreg;
14192                                 ins->dreg = ins->sreg2;
14193                                 ins->sreg2 = tmp_reg;
14194                                 store = TRUE;
14195
14196                                 spec2 [MONO_INST_DEST] = ' ';
14197                                 spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14198                                 spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14199                                 spec2 [MONO_INST_SRC3] = ' ';
14200                                 spec = spec2;
14201                         } else if (MONO_IS_STORE_MEMINDEX (ins))
14202                                 g_assert_not_reached ();
14203                         else
14204                                 store = FALSE;
14205                         no_lvreg = FALSE;
14206
14207                         if (G_UNLIKELY (cfg->verbose_level > 2)) {
14208                                 printf ("\t %.3s %d", spec, ins->dreg);
14209                                 num_sregs = mono_inst_get_src_registers (ins, sregs);
14210                                 for (srcindex = 0; srcindex < num_sregs; ++srcindex)
14211                                         printf (" %d", sregs [srcindex]);
14212                                 printf ("\n");
14213                         }
14214
14215                         /***************/
14216                         /*    DREG     */
14217                         /***************/
14218                         regtype = spec [MONO_INST_DEST];
14219                         g_assert (((ins->dreg == -1) && (regtype == ' ')) || ((ins->dreg != -1) && (regtype != ' ')));
14220                         prev_dreg = -1;
14221
14222                         if ((ins->dreg != -1) && get_vreg_to_inst (cfg, ins->dreg)) {
14223                                 MonoInst *var = get_vreg_to_inst (cfg, ins->dreg);
14224                                 MonoInst *store_ins;
14225                                 int store_opcode;
14226                                 MonoInst *def_ins = ins;
14227                                 int dreg = ins->dreg; /* The original vreg */
14228
14229                                 store_opcode = mono_type_to_store_membase (cfg, var->inst_vtype);
14230
14231                                 if (var->opcode == OP_REGVAR) {
14232                                         ins->dreg = var->dreg;
14233                                 } 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)) {
14234                                         /* 
14235                                          * Instead of emitting a load+store, use a _membase opcode.
14236                                          */
14237                                         g_assert (var->opcode == OP_REGOFFSET);
14238                                         if (ins->opcode == OP_MOVE) {
14239                                                 NULLIFY_INS (ins);
14240                                                 def_ins = NULL;
14241                                         } else {
14242                                                 ins->opcode = op_to_op_dest_membase (store_opcode, ins->opcode);
14243                                                 ins->inst_basereg = var->inst_basereg;
14244                                                 ins->inst_offset = var->inst_offset;
14245                                                 ins->dreg = -1;
14246                                         }
14247                                         spec = INS_INFO (ins->opcode);
14248                                 } else {
14249                                         guint32 lvreg;
14250
14251                                         g_assert (var->opcode == OP_REGOFFSET);
14252
14253                                         prev_dreg = ins->dreg;
14254
14255                                         /* Invalidate any previous lvreg for this vreg */
14256                                         vreg_to_lvreg [ins->dreg] = 0;
14257
14258                                         lvreg = 0;
14259
14260                                         if (COMPILE_SOFT_FLOAT (cfg) && store_opcode == OP_STORER8_MEMBASE_REG) {
14261                                                 regtype = 'l';
14262                                                 store_opcode = OP_STOREI8_MEMBASE_REG;
14263                                         }
14264
14265                                         ins->dreg = alloc_dreg (cfg, stacktypes [regtype]);
14266
14267 #if SIZEOF_REGISTER != 8
14268                                         if (regtype == 'l') {
14269                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET, ins->dreg + 1);
14270                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14271                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET, ins->dreg + 2);
14272                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14273                                                 def_ins = store_ins;
14274                                         }
14275                                         else
14276 #endif
14277                                         {
14278                                                 g_assert (store_opcode != OP_STOREV_MEMBASE);
14279
14280                                                 /* Try to fuse the store into the instruction itself */
14281                                                 /* FIXME: Add more instructions */
14282                                                 if (!lvreg && ((ins->opcode == OP_ICONST) || ((ins->opcode == OP_I8CONST) && (ins->inst_c0 == 0)))) {
14283                                                         ins->opcode = store_membase_reg_to_store_membase_imm (store_opcode);
14284                                                         ins->inst_imm = ins->inst_c0;
14285                                                         ins->inst_destbasereg = var->inst_basereg;
14286                                                         ins->inst_offset = var->inst_offset;
14287                                                         spec = INS_INFO (ins->opcode);
14288                                                 } else if (!lvreg && ((ins->opcode == OP_MOVE) || (ins->opcode == OP_FMOVE) || (ins->opcode == OP_LMOVE) || (ins->opcode == OP_RMOVE))) {
14289                                                         ins->opcode = store_opcode;
14290                                                         ins->inst_destbasereg = var->inst_basereg;
14291                                                         ins->inst_offset = var->inst_offset;
14292
14293                                                         no_lvreg = TRUE;
14294
14295                                                         tmp_reg = ins->dreg;
14296                                                         ins->dreg = ins->sreg2;
14297                                                         ins->sreg2 = tmp_reg;
14298                                                         store = TRUE;
14299
14300                                                         spec2 [MONO_INST_DEST] = ' ';
14301                                                         spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14302                                                         spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14303                                                         spec2 [MONO_INST_SRC3] = ' ';
14304                                                         spec = spec2;
14305                                                 } else if (!lvreg && (op_to_op_store_membase (store_opcode, ins->opcode) != -1)) {
14306                                                         // FIXME: The backends expect the base reg to be in inst_basereg
14307                                                         ins->opcode = op_to_op_store_membase (store_opcode, ins->opcode);
14308                                                         ins->dreg = -1;
14309                                                         ins->inst_basereg = var->inst_basereg;
14310                                                         ins->inst_offset = var->inst_offset;
14311                                                         spec = INS_INFO (ins->opcode);
14312                                                 } else {
14313                                                         /* printf ("INS: "); mono_print_ins (ins); */
14314                                                         /* Create a store instruction */
14315                                                         NEW_STORE_MEMBASE (cfg, store_ins, store_opcode, var->inst_basereg, var->inst_offset, ins->dreg);
14316
14317                                                         /* Insert it after the instruction */
14318                                                         mono_bblock_insert_after_ins (bb, ins, store_ins);
14319
14320                                                         def_ins = store_ins;
14321
14322                                                         /* 
14323                                                          * We can't assign ins->dreg to var->dreg here, since the
14324                                                          * sregs could use it. So set a flag, and do it after
14325                                                          * the sregs.
14326                                                          */
14327                                                         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)))
14328                                                                 dest_has_lvreg = TRUE;
14329                                                 }
14330                                         }
14331                                 }
14332
14333                                 if (def_ins && !live_range_start [dreg]) {
14334                                         live_range_start [dreg] = def_ins;
14335                                         live_range_start_bb [dreg] = bb;
14336                                 }
14337
14338                                 if (cfg->compute_gc_maps && def_ins && (var->flags & MONO_INST_GC_TRACK)) {
14339                                         MonoInst *tmp;
14340
14341                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
14342                                         tmp->inst_c1 = dreg;
14343                                         mono_bblock_insert_after_ins (bb, def_ins, tmp);
14344                                 }
14345                         }
14346
14347                         /************/
14348                         /*  SREGS   */
14349                         /************/
14350                         num_sregs = mono_inst_get_src_registers (ins, sregs);
14351                         for (srcindex = 0; srcindex < 3; ++srcindex) {
14352                                 regtype = spec [MONO_INST_SRC1 + srcindex];
14353                                 sreg = sregs [srcindex];
14354
14355                                 g_assert (((sreg == -1) && (regtype == ' ')) || ((sreg != -1) && (regtype != ' ')));
14356                                 if ((sreg != -1) && get_vreg_to_inst (cfg, sreg)) {
14357                                         MonoInst *var = get_vreg_to_inst (cfg, sreg);
14358                                         MonoInst *use_ins = ins;
14359                                         MonoInst *load_ins;
14360                                         guint32 load_opcode;
14361
14362                                         if (var->opcode == OP_REGVAR) {
14363                                                 sregs [srcindex] = var->dreg;
14364                                                 //mono_inst_set_src_registers (ins, sregs);
14365                                                 live_range_end [sreg] = use_ins;
14366                                                 live_range_end_bb [sreg] = bb;
14367
14368                                                 if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14369                                                         MonoInst *tmp;
14370
14371                                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14372                                                         /* var->dreg is a hreg */
14373                                                         tmp->inst_c1 = sreg;
14374                                                         mono_bblock_insert_after_ins (bb, ins, tmp);
14375                                                 }
14376
14377                                                 continue;
14378                                         }
14379
14380                                         g_assert (var->opcode == OP_REGOFFSET);
14381                                                 
14382                                         load_opcode = mono_type_to_load_membase (cfg, var->inst_vtype);
14383
14384                                         g_assert (load_opcode != OP_LOADV_MEMBASE);
14385
14386                                         if (vreg_to_lvreg [sreg]) {
14387                                                 g_assert (vreg_to_lvreg [sreg] != -1);
14388
14389                                                 /* The variable is already loaded to an lvreg */
14390                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
14391                                                         printf ("\t\tUse lvreg R%d for R%d.\n", vreg_to_lvreg [sreg], sreg);
14392                                                 sregs [srcindex] = vreg_to_lvreg [sreg];
14393                                                 //mono_inst_set_src_registers (ins, sregs);
14394                                                 continue;
14395                                         }
14396
14397                                         /* Try to fuse the load into the instruction */
14398                                         if ((srcindex == 0) && (op_to_op_src1_membase (cfg, load_opcode, ins->opcode) != -1)) {
14399                                                 ins->opcode = op_to_op_src1_membase (cfg, load_opcode, ins->opcode);
14400                                                 sregs [0] = var->inst_basereg;
14401                                                 //mono_inst_set_src_registers (ins, sregs);
14402                                                 ins->inst_offset = var->inst_offset;
14403                                         } else if ((srcindex == 1) && (op_to_op_src2_membase (cfg, load_opcode, ins->opcode) != -1)) {
14404                                                 ins->opcode = op_to_op_src2_membase (cfg, load_opcode, ins->opcode);
14405                                                 sregs [1] = var->inst_basereg;
14406                                                 //mono_inst_set_src_registers (ins, sregs);
14407                                                 ins->inst_offset = var->inst_offset;
14408                                         } else {
14409                                                 if (MONO_IS_REAL_MOVE (ins)) {
14410                                                         ins->opcode = OP_NOP;
14411                                                         sreg = ins->dreg;
14412                                                 } else {
14413                                                         //printf ("%d ", srcindex); mono_print_ins (ins);
14414
14415                                                         sreg = alloc_dreg (cfg, stacktypes [regtype]);
14416
14417                                                         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) {
14418                                                                 if (var->dreg == prev_dreg) {
14419                                                                         /*
14420                                                                          * sreg refers to the value loaded by the load
14421                                                                          * emitted below, but we need to use ins->dreg
14422                                                                          * since it refers to the store emitted earlier.
14423                                                                          */
14424                                                                         sreg = ins->dreg;
14425                                                                 }
14426                                                                 g_assert (sreg != -1);
14427                                                                 vreg_to_lvreg [var->dreg] = sreg;
14428                                                                 g_assert (lvregs_len < 1024);
14429                                                                 lvregs [lvregs_len ++] = var->dreg;
14430                                                         }
14431                                                 }
14432
14433                                                 sregs [srcindex] = sreg;
14434                                                 //mono_inst_set_src_registers (ins, sregs);
14435
14436 #if SIZEOF_REGISTER != 8
14437                                                 if (regtype == 'l') {
14438                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 2, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET);
14439                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14440                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 1, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET);
14441                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14442                                                         use_ins = load_ins;
14443                                                 }
14444                                                 else
14445 #endif
14446                                                 {
14447 #if SIZEOF_REGISTER == 4
14448                                                         g_assert (load_opcode != OP_LOADI8_MEMBASE);
14449 #endif
14450                                                         NEW_LOAD_MEMBASE (cfg, load_ins, load_opcode, sreg, var->inst_basereg, var->inst_offset);
14451                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14452                                                         use_ins = load_ins;
14453                                                 }
14454                                         }
14455
14456                                         if (var->dreg < orig_next_vreg) {
14457                                                 live_range_end [var->dreg] = use_ins;
14458                                                 live_range_end_bb [var->dreg] = bb;
14459                                         }
14460
14461                                         if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14462                                                 MonoInst *tmp;
14463
14464                                                 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14465                                                 tmp->inst_c1 = var->dreg;
14466                                                 mono_bblock_insert_after_ins (bb, ins, tmp);
14467                                         }
14468                                 }
14469                         }
14470                         mono_inst_set_src_registers (ins, sregs);
14471
14472                         if (dest_has_lvreg) {
14473                                 g_assert (ins->dreg != -1);
14474                                 vreg_to_lvreg [prev_dreg] = ins->dreg;
14475                                 g_assert (lvregs_len < 1024);
14476                                 lvregs [lvregs_len ++] = prev_dreg;
14477                                 dest_has_lvreg = FALSE;
14478                         }
14479
14480                         if (store) {
14481                                 tmp_reg = ins->dreg;
14482                                 ins->dreg = ins->sreg2;
14483                                 ins->sreg2 = tmp_reg;
14484                         }
14485
14486                         if (MONO_IS_CALL (ins)) {
14487                                 /* Clear vreg_to_lvreg array */
14488                                 for (i = 0; i < lvregs_len; i++)
14489                                         vreg_to_lvreg [lvregs [i]] = 0;
14490                                 lvregs_len = 0;
14491                         } else if (ins->opcode == OP_NOP) {
14492                                 ins->dreg = -1;
14493                                 MONO_INST_NULLIFY_SREGS (ins);
14494                         }
14495
14496                         if (cfg->verbose_level > 2)
14497                                 mono_print_ins_index (1, ins);
14498                 }
14499
14500                 /* Extend the live range based on the liveness info */
14501                 if (cfg->compute_precise_live_ranges && bb->live_out_set && bb->code) {
14502                         for (i = 0; i < cfg->num_varinfo; i ++) {
14503                                 MonoMethodVar *vi = MONO_VARINFO (cfg, i);
14504
14505                                 if (vreg_is_volatile (cfg, vi->vreg))
14506                                         /* The liveness info is incomplete */
14507                                         continue;
14508
14509                                 if (mono_bitset_test_fast (bb->live_in_set, i) && !live_range_start [vi->vreg]) {
14510                                         /* Live from at least the first ins of this bb */
14511                                         live_range_start [vi->vreg] = bb->code;
14512                                         live_range_start_bb [vi->vreg] = bb;
14513                                 }
14514
14515                                 if (mono_bitset_test_fast (bb->live_out_set, i)) {
14516                                         /* Live at least until the last ins of this bb */
14517                                         live_range_end [vi->vreg] = bb->last_ins;
14518                                         live_range_end_bb [vi->vreg] = bb;
14519                                 }
14520                         }
14521                 }
14522         }
14523         
14524         /*
14525          * Emit LIVERANGE_START/LIVERANGE_END opcodes, the backend will implement them
14526          * by storing the current native offset into MonoMethodVar->live_range_start/end.
14527          */
14528         if (cfg->backend->have_liverange_ops && cfg->compute_precise_live_ranges && cfg->comp_done & MONO_COMP_LIVENESS) {
14529                 for (i = 0; i < cfg->num_varinfo; ++i) {
14530                         int vreg = MONO_VARINFO (cfg, i)->vreg;
14531                         MonoInst *ins;
14532
14533                         if (live_range_start [vreg]) {
14534                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_START);
14535                                 ins->inst_c0 = i;
14536                                 ins->inst_c1 = vreg;
14537                                 mono_bblock_insert_after_ins (live_range_start_bb [vreg], live_range_start [vreg], ins);
14538                         }
14539                         if (live_range_end [vreg]) {
14540                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_END);
14541                                 ins->inst_c0 = i;
14542                                 ins->inst_c1 = vreg;
14543                                 if (live_range_end [vreg] == live_range_end_bb [vreg]->last_ins)
14544                                         mono_add_ins_to_end (live_range_end_bb [vreg], ins);
14545                                 else
14546                                         mono_bblock_insert_after_ins (live_range_end_bb [vreg], live_range_end [vreg], ins);
14547                         }
14548                 }
14549         }
14550
14551         if (cfg->gsharedvt_locals_var_ins) {
14552                 /* Nullify if unused */
14553                 cfg->gsharedvt_locals_var_ins->opcode = OP_PCONST;
14554                 cfg->gsharedvt_locals_var_ins->inst_imm = 0;
14555         }
14556
14557         g_free (live_range_start);
14558         g_free (live_range_end);
14559         g_free (live_range_start_bb);
14560         g_free (live_range_end_bb);
14561 }
14562
14563 /**
14564  * FIXME:
14565  * - use 'iadd' instead of 'int_add'
14566  * - handling ovf opcodes: decompose in method_to_ir.
14567  * - unify iregs/fregs
14568  *   -> partly done, the missing parts are:
14569  *   - a more complete unification would involve unifying the hregs as well, so
14570  *     code wouldn't need if (fp) all over the place. but that would mean the hregs
14571  *     would no longer map to the machine hregs, so the code generators would need to
14572  *     be modified. Also, on ia64 for example, niregs + nfregs > 256 -> bitmasks
14573  *     wouldn't work any more. Duplicating the code in mono_local_regalloc () into
14574  *     fp/non-fp branches speeds it up by about 15%.
14575  * - use sext/zext opcodes instead of shifts
14576  * - add OP_ICALL
14577  * - get rid of TEMPLOADs if possible and use vregs instead
14578  * - clean up usage of OP_P/OP_ opcodes
14579  * - cleanup usage of DUMMY_USE
14580  * - cleanup the setting of ins->type for MonoInst's which are pushed on the 
14581  *   stack
14582  * - set the stack type and allocate a dreg in the EMIT_NEW macros
14583  * - get rid of all the <foo>2 stuff when the new JIT is ready.
14584  * - make sure handle_stack_args () is called before the branch is emitted
14585  * - when the new IR is done, get rid of all unused stuff
14586  * - COMPARE/BEQ as separate instructions or unify them ?
14587  *   - keeping them separate allows specialized compare instructions like
14588  *     compare_imm, compare_membase
14589  *   - most back ends unify fp compare+branch, fp compare+ceq
14590  * - integrate mono_save_args into inline_method
14591  * - get rid of the empty bblocks created by MONO_EMIT_NEW_BRACH_BLOCK2
14592  * - handle long shift opts on 32 bit platforms somehow: they require 
14593  *   3 sregs (2 for arg1 and 1 for arg2)
14594  * - make byref a 'normal' type.
14595  * - use vregs for bb->out_stacks if possible, handle_global_vreg will make them a
14596  *   variable if needed.
14597  * - do not start a new IL level bblock when cfg->cbb is changed by a function call
14598  *   like inline_method.
14599  * - remove inlining restrictions
14600  * - fix LNEG and enable cfold of INEG
14601  * - generalize x86 optimizations like ldelema as a peephole optimization
14602  * - add store_mem_imm for amd64
14603  * - optimize the loading of the interruption flag in the managed->native wrappers
14604  * - avoid special handling of OP_NOP in passes
14605  * - move code inserting instructions into one function/macro.
14606  * - try a coalescing phase after liveness analysis
14607  * - add float -> vreg conversion + local optimizations on !x86
14608  * - figure out how to handle decomposed branches during optimizations, ie.
14609  *   compare+branch, op_jump_table+op_br etc.
14610  * - promote RuntimeXHandles to vregs
14611  * - vtype cleanups:
14612  *   - add a NEW_VARLOADA_VREG macro
14613  * - the vtype optimizations are blocked by the LDADDR opcodes generated for 
14614  *   accessing vtype fields.
14615  * - get rid of I8CONST on 64 bit platforms
14616  * - dealing with the increase in code size due to branches created during opcode
14617  *   decomposition:
14618  *   - use extended basic blocks
14619  *     - all parts of the JIT
14620  *     - handle_global_vregs () && local regalloc
14621  *   - avoid introducing global vregs during decomposition, like 'vtable' in isinst
14622  * - sources of increase in code size:
14623  *   - vtypes
14624  *   - long compares
14625  *   - isinst and castclass
14626  *   - lvregs not allocated to global registers even if used multiple times
14627  * - call cctors outside the JIT, to make -v output more readable and JIT timings more
14628  *   meaningful.
14629  * - check for fp stack leakage in other opcodes too. (-> 'exceptions' optimization)
14630  * - add all micro optimizations from the old JIT
14631  * - put tree optimizations into the deadce pass
14632  * - decompose op_start_handler/op_endfilter/op_endfinally earlier using an arch
14633  *   specific function.
14634  * - unify the float comparison opcodes with the other comparison opcodes, i.e.
14635  *   fcompare + branchCC.
14636  * - create a helper function for allocating a stack slot, taking into account 
14637  *   MONO_CFG_HAS_SPILLUP.
14638  * - merge r68207.
14639  * - merge the ia64 switch changes.
14640  * - optimize mono_regstate2_alloc_int/float.
14641  * - fix the pessimistic handling of variables accessed in exception handler blocks.
14642  * - need to write a tree optimization pass, but the creation of trees is difficult, i.e.
14643  *   parts of the tree could be separated by other instructions, killing the tree
14644  *   arguments, or stores killing loads etc. Also, should we fold loads into other
14645  *   instructions if the result of the load is used multiple times ?
14646  * - make the REM_IMM optimization in mini-x86.c arch-independent.
14647  * - LAST MERGE: 108395.
14648  * - when returning vtypes in registers, generate IR and append it to the end of the
14649  *   last bb instead of doing it in the epilog.
14650  * - change the store opcodes so they use sreg1 instead of dreg to store the base register.
14651  */
14652
14653 /*
14654
14655 NOTES
14656 -----
14657
14658 - When to decompose opcodes:
14659   - earlier: this makes some optimizations hard to implement, since the low level IR
14660   no longer contains the neccessary information. But it is easier to do.
14661   - later: harder to implement, enables more optimizations.
14662 - Branches inside bblocks:
14663   - created when decomposing complex opcodes. 
14664     - branches to another bblock: harmless, but not tracked by the branch 
14665       optimizations, so need to branch to a label at the start of the bblock.
14666     - branches to inside the same bblock: very problematic, trips up the local
14667       reg allocator. Can be fixed by spitting the current bblock, but that is a
14668       complex operation, since some local vregs can become global vregs etc.
14669 - Local/global vregs:
14670   - local vregs: temporary vregs used inside one bblock. Assigned to hregs by the
14671     local register allocator.
14672   - global vregs: used in more than one bblock. Have an associated MonoMethodVar
14673     structure, created by mono_create_var (). Assigned to hregs or the stack by
14674     the global register allocator.
14675 - When to do optimizations like alu->alu_imm:
14676   - earlier -> saves work later on since the IR will be smaller/simpler
14677   - later -> can work on more instructions
14678 - Handling of valuetypes:
14679   - When a vtype is pushed on the stack, a new temporary is created, an 
14680     instruction computing its address (LDADDR) is emitted and pushed on
14681     the stack. Need to optimize cases when the vtype is used immediately as in
14682     argument passing, stloc etc.
14683 - Instead of the to_end stuff in the old JIT, simply call the function handling
14684   the values on the stack before emitting the last instruction of the bb.
14685 */
14686
14687 #endif /* DISABLE_JIT */