Merge pull request #3528 from BrzVlad/fix-sgen-check-before-collections
[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  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
12  */
13
14 #include <config.h>
15
16 #ifndef DISABLE_JIT
17
18 #include <signal.h>
19
20 #ifdef HAVE_UNISTD_H
21 #include <unistd.h>
22 #endif
23
24 #include <math.h>
25 #include <string.h>
26 #include <ctype.h>
27
28 #ifdef HAVE_SYS_TIME_H
29 #include <sys/time.h>
30 #endif
31
32 #ifdef HAVE_ALLOCA_H
33 #include <alloca.h>
34 #endif
35
36 #include <mono/utils/memcheck.h>
37 #include "mini.h"
38 #include <mono/metadata/abi-details.h>
39 #include <mono/metadata/assembly.h>
40 #include <mono/metadata/attrdefs.h>
41 #include <mono/metadata/loader.h>
42 #include <mono/metadata/tabledefs.h>
43 #include <mono/metadata/class.h>
44 #include <mono/metadata/object.h>
45 #include <mono/metadata/exception.h>
46 #include <mono/metadata/opcodes.h>
47 #include <mono/metadata/mono-endian.h>
48 #include <mono/metadata/tokentype.h>
49 #include <mono/metadata/tabledefs.h>
50 #include <mono/metadata/marshal.h>
51 #include <mono/metadata/debug-helpers.h>
52 #include <mono/metadata/mono-debug.h>
53 #include <mono/metadata/mono-debug-debugger.h>
54 #include <mono/metadata/gc-internals.h>
55 #include <mono/metadata/security-manager.h>
56 #include <mono/metadata/threads-types.h>
57 #include <mono/metadata/security-core-clr.h>
58 #include <mono/metadata/profiler-private.h>
59 #include <mono/metadata/profiler.h>
60 #include <mono/metadata/monitor.h>
61 #include <mono/metadata/debug-mono-symfile.h>
62 #include <mono/utils/mono-compiler.h>
63 #include <mono/utils/mono-memory-model.h>
64 #include <mono/utils/mono-error-internals.h>
65 #include <mono/metadata/mono-basic-block.h>
66 #include <mono/metadata/reflection-internals.h>
67 #include <mono/utils/mono-threads-coop.h>
68
69 #include "trace.h"
70
71 #include "ir-emit.h"
72
73 #include "jit-icalls.h"
74 #include "jit.h"
75 #include "debugger-agent.h"
76 #include "seq-points.h"
77 #include "aot-compiler.h"
78 #include "mini-llvm.h"
79
80 #define BRANCH_COST 10
81 #define INLINE_LENGTH_LIMIT 20
82
83 /* These have 'cfg' as an implicit argument */
84 #define INLINE_FAILURE(msg) do {                                                                        \
85         if ((cfg->method != cfg->current_method) && (cfg->current_method->wrapper_type == MONO_WRAPPER_NONE)) { \
86                 inline_failure (cfg, msg);                                                                              \
87                 goto exception_exit;                                                                                    \
88         } \
89         } while (0)
90 #define CHECK_CFG_EXCEPTION do {\
91                 if (cfg->exception_type != MONO_EXCEPTION_NONE) \
92                         goto exception_exit;                                            \
93         } while (0)
94 #define FIELD_ACCESS_FAILURE(method, field) do {                                        \
95                 field_access_failure ((cfg), (method), (field));                        \
96                 goto exception_exit;    \
97         } while (0)
98 #define GENERIC_SHARING_FAILURE(opcode) do {            \
99                 if (cfg->gshared) {                                                                     \
100                         gshared_failure (cfg, opcode, __FILE__, __LINE__);      \
101                         goto exception_exit;    \
102                 }                       \
103         } while (0)
104 #define GSHAREDVT_FAILURE(opcode) do {          \
105         if (cfg->gsharedvt) {                                                                                           \
106                 gsharedvt_failure (cfg, opcode, __FILE__, __LINE__);                    \
107                 goto exception_exit;                                                                                    \
108         }                                                                                                                                       \
109         } while (0)
110 #define OUT_OF_MEMORY_FAILURE do {      \
111                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);                \
112                 mono_error_set_out_of_memory (&cfg->error, "");                                 \
113                 goto exception_exit;    \
114         } while (0)
115 #define DISABLE_AOT(cfg) do { \
116                 if ((cfg)->verbose_level >= 2)                                            \
117                         printf ("AOT disabled: %s:%d\n", __FILE__, __LINE__);   \
118                 (cfg)->disable_aot = TRUE;                                                        \
119         } while (0)
120 #define LOAD_ERROR do { \
121                 break_on_unverified ();                                                         \
122                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD); \
123                 goto exception_exit;                                                                    \
124         } while (0)
125
126 #define TYPE_LOAD_ERROR(klass) do { \
127                 cfg->exception_ptr = klass; \
128                 LOAD_ERROR;                                     \
129         } while (0)
130
131 #define CHECK_CFG_ERROR do {\
132                 if (!mono_error_ok (&cfg->error)) { \
133                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);        \
134                         goto mono_error_exit; \
135                 } \
136         } while (0)
137
138 /* Determine whenever 'ins' represents a load of the 'this' argument */
139 #define MONO_CHECK_THIS(ins) (mono_method_signature (cfg->method)->hasthis && ((ins)->opcode == OP_MOVE) && ((ins)->sreg1 == cfg->args [0]->dreg))
140
141 static int ldind_to_load_membase (int opcode);
142 static int stind_to_store_membase (int opcode);
143
144 int mono_op_to_op_imm (int opcode);
145 int mono_op_to_op_imm_noemul (int opcode);
146
147 MONO_API MonoInst* mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig, MonoInst **args);
148
149 static int inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
150                                                   guchar *ip, guint real_offset, gboolean inline_always);
151 static MonoInst*
152 emit_llvmonly_virtual_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used, MonoInst **sp);
153
154 /* helper methods signatures */
155 static MonoMethodSignature *helper_sig_domain_get;
156 static MonoMethodSignature *helper_sig_rgctx_lazy_fetch_trampoline;
157 static MonoMethodSignature *helper_sig_llvmonly_imt_thunk;
158
159
160 /* type loading helpers */
161 static GENERATE_GET_CLASS_WITH_CACHE (runtime_helpers, System.Runtime.CompilerServices, RuntimeHelpers)
162 static GENERATE_TRY_GET_CLASS_WITH_CACHE (debuggable_attribute, System.Diagnostics, DebuggableAttribute)
163
164 /*
165  * Instruction metadata
166  */
167 #ifdef MINI_OP
168 #undef MINI_OP
169 #endif
170 #ifdef MINI_OP3
171 #undef MINI_OP3
172 #endif
173 #define MINI_OP(a,b,dest,src1,src2) dest, src1, src2, ' ',
174 #define MINI_OP3(a,b,dest,src1,src2,src3) dest, src1, src2, src3,
175 #define NONE ' '
176 #define IREG 'i'
177 #define FREG 'f'
178 #define VREG 'v'
179 #define XREG 'x'
180 #if SIZEOF_REGISTER == 8 && SIZEOF_REGISTER == SIZEOF_VOID_P
181 #define LREG IREG
182 #else
183 #define LREG 'l'
184 #endif
185 /* keep in sync with the enum in mini.h */
186 const char
187 ins_info[] = {
188 #include "mini-ops.h"
189 };
190 #undef MINI_OP
191 #undef MINI_OP3
192
193 #define MINI_OP(a,b,dest,src1,src2) ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0)),
194 #define MINI_OP3(a,b,dest,src1,src2,src3) ((src3) != NONE ? 3 : ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0))),
195 /* 
196  * This should contain the index of the last sreg + 1. This is not the same
197  * as the number of sregs for opcodes like IA64_CMP_EQ_IMM.
198  */
199 const gint8 ins_sreg_counts[] = {
200 #include "mini-ops.h"
201 };
202 #undef MINI_OP
203 #undef MINI_OP3
204
205 #define MONO_INIT_VARINFO(vi,id) do { \
206         (vi)->range.first_use.pos.bid = 0xffff; \
207         (vi)->reg = -1; \
208         (vi)->idx = (id); \
209 } while (0)
210
211 guint32
212 mono_alloc_ireg (MonoCompile *cfg)
213 {
214         return alloc_ireg (cfg);
215 }
216
217 guint32
218 mono_alloc_lreg (MonoCompile *cfg)
219 {
220         return alloc_lreg (cfg);
221 }
222
223 guint32
224 mono_alloc_freg (MonoCompile *cfg)
225 {
226         return alloc_freg (cfg);
227 }
228
229 guint32
230 mono_alloc_preg (MonoCompile *cfg)
231 {
232         return alloc_preg (cfg);
233 }
234
235 guint32
236 mono_alloc_dreg (MonoCompile *cfg, MonoStackType stack_type)
237 {
238         return alloc_dreg (cfg, stack_type);
239 }
240
241 /*
242  * mono_alloc_ireg_ref:
243  *
244  *   Allocate an IREG, and mark it as holding a GC ref.
245  */
246 guint32
247 mono_alloc_ireg_ref (MonoCompile *cfg)
248 {
249         return alloc_ireg_ref (cfg);
250 }
251
252 /*
253  * mono_alloc_ireg_mp:
254  *
255  *   Allocate an IREG, and mark it as holding a managed pointer.
256  */
257 guint32
258 mono_alloc_ireg_mp (MonoCompile *cfg)
259 {
260         return alloc_ireg_mp (cfg);
261 }
262
263 /*
264  * mono_alloc_ireg_copy:
265  *
266  *   Allocate an IREG with the same GC type as VREG.
267  */
268 guint32
269 mono_alloc_ireg_copy (MonoCompile *cfg, guint32 vreg)
270 {
271         if (vreg_is_ref (cfg, vreg))
272                 return alloc_ireg_ref (cfg);
273         else if (vreg_is_mp (cfg, vreg))
274                 return alloc_ireg_mp (cfg);
275         else
276                 return alloc_ireg (cfg);
277 }
278
279 guint
280 mono_type_to_regmove (MonoCompile *cfg, MonoType *type)
281 {
282         if (type->byref)
283                 return OP_MOVE;
284
285         type = mini_get_underlying_type (type);
286 handle_enum:
287         switch (type->type) {
288         case MONO_TYPE_I1:
289         case MONO_TYPE_U1:
290                 return OP_MOVE;
291         case MONO_TYPE_I2:
292         case MONO_TYPE_U2:
293                 return OP_MOVE;
294         case MONO_TYPE_I4:
295         case MONO_TYPE_U4:
296                 return OP_MOVE;
297         case MONO_TYPE_I:
298         case MONO_TYPE_U:
299         case MONO_TYPE_PTR:
300         case MONO_TYPE_FNPTR:
301                 return OP_MOVE;
302         case MONO_TYPE_CLASS:
303         case MONO_TYPE_STRING:
304         case MONO_TYPE_OBJECT:
305         case MONO_TYPE_SZARRAY:
306         case MONO_TYPE_ARRAY:    
307                 return OP_MOVE;
308         case MONO_TYPE_I8:
309         case MONO_TYPE_U8:
310 #if SIZEOF_REGISTER == 8
311                 return OP_MOVE;
312 #else
313                 return OP_LMOVE;
314 #endif
315         case MONO_TYPE_R4:
316                 return cfg->r4fp ? OP_RMOVE : OP_FMOVE;
317         case MONO_TYPE_R8:
318                 return OP_FMOVE;
319         case MONO_TYPE_VALUETYPE:
320                 if (type->data.klass->enumtype) {
321                         type = mono_class_enum_basetype (type->data.klass);
322                         goto handle_enum;
323                 }
324                 if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (type)))
325                         return OP_XMOVE;
326                 return OP_VMOVE;
327         case MONO_TYPE_TYPEDBYREF:
328                 return OP_VMOVE;
329         case MONO_TYPE_GENERICINST:
330                 type = &type->data.generic_class->container_class->byval_arg;
331                 goto handle_enum;
332         case MONO_TYPE_VAR:
333         case MONO_TYPE_MVAR:
334                 g_assert (cfg->gshared);
335                 if (mini_type_var_is_vt (type))
336                         return OP_VMOVE;
337                 else
338                         return mono_type_to_regmove (cfg, mini_get_underlying_type (type));
339         default:
340                 g_error ("unknown type 0x%02x in type_to_regstore", type->type);
341         }
342         return -1;
343 }
344
345 void
346 mono_print_bb (MonoBasicBlock *bb, const char *msg)
347 {
348         int i;
349         MonoInst *tree;
350
351         printf ("\n%s %d: [IN: ", msg, bb->block_num);
352         for (i = 0; i < bb->in_count; ++i)
353                 printf (" BB%d(%d)", bb->in_bb [i]->block_num, bb->in_bb [i]->dfn);
354         printf (", OUT: ");
355         for (i = 0; i < bb->out_count; ++i)
356                 printf (" BB%d(%d)", bb->out_bb [i]->block_num, bb->out_bb [i]->dfn);
357         printf (" ]\n");
358         for (tree = bb->code; tree; tree = tree->next)
359                 mono_print_ins_index (-1, tree);
360 }
361
362 void
363 mono_create_helper_signatures (void)
364 {
365         helper_sig_domain_get = mono_create_icall_signature ("ptr");
366         helper_sig_rgctx_lazy_fetch_trampoline = mono_create_icall_signature ("ptr ptr");
367         helper_sig_llvmonly_imt_thunk = mono_create_icall_signature ("ptr ptr ptr");
368 }
369
370 static MONO_NEVER_INLINE void
371 break_on_unverified (void)
372 {
373         if (mini_get_debug_options ()->break_on_unverified)
374                 G_BREAKPOINT ();
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_MONO_ERROR);
383         mono_error_set_generic_error (&cfg->error, "System", "FieldAccessException", "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), (MonoStackType)(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), (MonoStackType)(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 = (MonoBasicBlock **)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 = (MonoBasicBlock **)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 = (MonoBasicBlock **)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 gboolean
665 ip_in_finally_clause (MonoCompile *cfg, int offset)
666 {
667         MonoMethodHeader *header = cfg->header;
668         MonoExceptionClause *clause;
669         int i;
670
671         for (i = 0; i < header->num_clauses; ++i) {
672                 clause = &header->clauses [i];
673                 if (clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY && clause->flags != MONO_EXCEPTION_CLAUSE_FAULT)
674                         continue;
675
676                 if (MONO_OFFSET_IN_HANDLER (clause, offset))
677                         return TRUE;
678         }
679         return FALSE;
680 }
681
682 static GList*
683 mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *target, int type)
684 {
685         MonoMethodHeader *header = cfg->header;
686         MonoExceptionClause *clause;
687         int i;
688         GList *res = NULL;
689
690         for (i = 0; i < header->num_clauses; ++i) {
691                 clause = &header->clauses [i];
692                 if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) && 
693                     (!MONO_OFFSET_IN_CLAUSE (clause, (target - header->code)))) {
694                         if (clause->flags == type)
695                                 res = g_list_append (res, clause);
696                 }
697         }
698         return res;
699 }
700
701 static void
702 mono_create_spvar_for_region (MonoCompile *cfg, int region)
703 {
704         MonoInst *var;
705
706         var = (MonoInst *)g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
707         if (var)
708                 return;
709
710         var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
711         /* prevent it from being register allocated */
712         var->flags |= MONO_INST_VOLATILE;
713
714         g_hash_table_insert (cfg->spvars, GINT_TO_POINTER (region), var);
715 }
716
717 MonoInst *
718 mono_find_exvar_for_offset (MonoCompile *cfg, int offset)
719 {
720         return (MonoInst *)g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
721 }
722
723 static MonoInst*
724 mono_create_exvar_for_offset (MonoCompile *cfg, int offset)
725 {
726         MonoInst *var;
727
728         var = (MonoInst *)g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
729         if (var)
730                 return var;
731
732         var = mono_compile_create_var (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL);
733         /* prevent it from being register allocated */
734         var->flags |= MONO_INST_VOLATILE;
735
736         g_hash_table_insert (cfg->exvars, GINT_TO_POINTER (offset), var);
737
738         return var;
739 }
740
741 /*
742  * Returns the type used in the eval stack when @type is loaded.
743  * FIXME: return a MonoType/MonoClass for the byref and VALUETYPE cases.
744  */
745 void
746 type_to_eval_stack_type (MonoCompile *cfg, MonoType *type, MonoInst *inst)
747 {
748         MonoClass *klass;
749
750         type = mini_get_underlying_type (type);
751         inst->klass = klass = mono_class_from_mono_type (type);
752         if (type->byref) {
753                 inst->type = STACK_MP;
754                 return;
755         }
756
757 handle_enum:
758         switch (type->type) {
759         case MONO_TYPE_VOID:
760                 inst->type = STACK_INV;
761                 return;
762         case MONO_TYPE_I1:
763         case MONO_TYPE_U1:
764         case MONO_TYPE_I2:
765         case MONO_TYPE_U2:
766         case MONO_TYPE_I4:
767         case MONO_TYPE_U4:
768                 inst->type = STACK_I4;
769                 return;
770         case MONO_TYPE_I:
771         case MONO_TYPE_U:
772         case MONO_TYPE_PTR:
773         case MONO_TYPE_FNPTR:
774                 inst->type = STACK_PTR;
775                 return;
776         case MONO_TYPE_CLASS:
777         case MONO_TYPE_STRING:
778         case MONO_TYPE_OBJECT:
779         case MONO_TYPE_SZARRAY:
780         case MONO_TYPE_ARRAY:    
781                 inst->type = STACK_OBJ;
782                 return;
783         case MONO_TYPE_I8:
784         case MONO_TYPE_U8:
785                 inst->type = STACK_I8;
786                 return;
787         case MONO_TYPE_R4:
788                 inst->type = cfg->r4_stack_type;
789                 break;
790         case MONO_TYPE_R8:
791                 inst->type = STACK_R8;
792                 return;
793         case MONO_TYPE_VALUETYPE:
794                 if (type->data.klass->enumtype) {
795                         type = mono_class_enum_basetype (type->data.klass);
796                         goto handle_enum;
797                 } else {
798                         inst->klass = klass;
799                         inst->type = STACK_VTYPE;
800                         return;
801                 }
802         case MONO_TYPE_TYPEDBYREF:
803                 inst->klass = mono_defaults.typed_reference_class;
804                 inst->type = STACK_VTYPE;
805                 return;
806         case MONO_TYPE_GENERICINST:
807                 type = &type->data.generic_class->container_class->byval_arg;
808                 goto handle_enum;
809         case MONO_TYPE_VAR:
810         case MONO_TYPE_MVAR:
811                 g_assert (cfg->gshared);
812                 if (mini_is_gsharedvt_type (type)) {
813                         g_assert (cfg->gsharedvt);
814                         inst->type = STACK_VTYPE;
815                 } else {
816                         type_to_eval_stack_type (cfg, mini_get_underlying_type (type), inst);
817                 }
818                 return;
819         default:
820                 g_error ("unknown type 0x%02x in eval stack type", type->type);
821         }
822 }
823
824 /*
825  * The following tables are used to quickly validate the IL code in type_from_op ().
826  */
827 static const char
828 bin_num_table [STACK_MAX] [STACK_MAX] = {
829         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
830         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
831         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
832         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
833         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8,  STACK_INV, STACK_INV, STACK_INV, STACK_R8},
834         {STACK_INV, STACK_MP,  STACK_INV, STACK_MP,  STACK_INV, STACK_PTR, 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_R8, STACK_INV, STACK_INV, STACK_INV, STACK_R4}
838 };
839
840 static const char 
841 neg_table [] = {
842         STACK_INV, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_INV, STACK_INV, STACK_INV, STACK_R4
843 };
844
845 /* reduce the size of this table */
846 static const char
847 bin_int_table [STACK_MAX] [STACK_MAX] = {
848         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
849         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
850         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
851         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
852         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
853         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
854         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
855         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
856 };
857
858 static const char
859 bin_comp_table [STACK_MAX] [STACK_MAX] = {
860 /*      Inv i  L  p  F  &  O  vt r4 */
861         {0},
862         {0, 1, 0, 1, 0, 0, 0, 0}, /* i, int32 */
863         {0, 0, 1, 0, 0, 0, 0, 0}, /* L, int64 */
864         {0, 1, 0, 1, 0, 2, 4, 0}, /* p, ptr */
865         {0, 0, 0, 0, 1, 0, 0, 0, 1}, /* F, R8 */
866         {0, 0, 0, 2, 0, 1, 0, 0}, /* &, managed pointer */
867         {0, 0, 0, 4, 0, 0, 3, 0}, /* O, reference */
868         {0, 0, 0, 0, 0, 0, 0, 0}, /* vt value type */
869         {0, 0, 0, 0, 1, 0, 0, 0, 1}, /* r, r4 */
870 };
871
872 /* reduce the size of this table */
873 static const char
874 shift_table [STACK_MAX] [STACK_MAX] = {
875         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
876         {STACK_INV, STACK_I4,  STACK_INV, STACK_I4,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
877         {STACK_INV, STACK_I8,  STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
878         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
879         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
880         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
881         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
882         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
883 };
884
885 /*
886  * Tables to map from the non-specific opcode to the matching
887  * type-specific opcode.
888  */
889 /* handles from CEE_ADD to CEE_SHR_UN (CEE_REM_UN for floats) */
890 static const guint16
891 binops_op_map [STACK_MAX] = {
892         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
893 };
894
895 /* handles from CEE_NEG to CEE_CONV_U8 */
896 static const guint16
897 unops_op_map [STACK_MAX] = {
898         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
899 };
900
901 /* handles from CEE_CONV_U2 to CEE_SUB_OVF_UN */
902 static const guint16
903 ovfops_op_map [STACK_MAX] = {
904         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
905 };
906
907 /* handles from CEE_CONV_OVF_I1_UN to CEE_CONV_OVF_U_UN */
908 static const guint16
909 ovf2ops_op_map [STACK_MAX] = {
910         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
911 };
912
913 /* handles from CEE_CONV_OVF_I1 to CEE_CONV_OVF_U8 */
914 static const guint16
915 ovf3ops_op_map [STACK_MAX] = {
916         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
917 };
918
919 /* handles from CEE_BEQ to CEE_BLT_UN */
920 static const guint16
921 beqops_op_map [STACK_MAX] = {
922         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
923 };
924
925 /* handles from CEE_CEQ to CEE_CLT_UN */
926 static const guint16
927 ceqops_op_map [STACK_MAX] = {
928         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
929 };
930
931 /*
932  * Sets ins->type (the type on the eval stack) according to the
933  * type of the opcode and the arguments to it.
934  * Invalid IL code is marked by setting ins->type to the invalid value STACK_INV.
935  *
936  * FIXME: this function sets ins->type unconditionally in some cases, but
937  * it should set it to invalid for some types (a conv.x on an object)
938  */
939 static void
940 type_from_op (MonoCompile *cfg, MonoInst *ins, MonoInst *src1, MonoInst *src2)
941 {
942         switch (ins->opcode) {
943         /* binops */
944         case CEE_ADD:
945         case CEE_SUB:
946         case CEE_MUL:
947         case CEE_DIV:
948         case CEE_REM:
949                 /* FIXME: check unverifiable args for STACK_MP */
950                 ins->type = bin_num_table [src1->type] [src2->type];
951                 ins->opcode += binops_op_map [ins->type];
952                 break;
953         case CEE_DIV_UN:
954         case CEE_REM_UN:
955         case CEE_AND:
956         case CEE_OR:
957         case CEE_XOR:
958                 ins->type = bin_int_table [src1->type] [src2->type];
959                 ins->opcode += binops_op_map [ins->type];
960                 break;
961         case CEE_SHL:
962         case CEE_SHR:
963         case CEE_SHR_UN:
964                 ins->type = shift_table [src1->type] [src2->type];
965                 ins->opcode += binops_op_map [ins->type];
966                 break;
967         case OP_COMPARE:
968         case OP_LCOMPARE:
969         case OP_ICOMPARE:
970                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
971                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
972                         ins->opcode = OP_LCOMPARE;
973                 else if (src1->type == STACK_R4)
974                         ins->opcode = OP_RCOMPARE;
975                 else if (src1->type == STACK_R8)
976                         ins->opcode = OP_FCOMPARE;
977                 else
978                         ins->opcode = OP_ICOMPARE;
979                 break;
980         case OP_ICOMPARE_IMM:
981                 ins->type = bin_comp_table [src1->type] [src1->type] ? STACK_I4 : STACK_INV;
982                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
983                         ins->opcode = OP_LCOMPARE_IMM;          
984                 break;
985         case CEE_BEQ:
986         case CEE_BGE:
987         case CEE_BGT:
988         case CEE_BLE:
989         case CEE_BLT:
990         case CEE_BNE_UN:
991         case CEE_BGE_UN:
992         case CEE_BGT_UN:
993         case CEE_BLE_UN:
994         case CEE_BLT_UN:
995                 ins->opcode += beqops_op_map [src1->type];
996                 break;
997         case OP_CEQ:
998                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
999                 ins->opcode += ceqops_op_map [src1->type];
1000                 break;
1001         case OP_CGT:
1002         case OP_CGT_UN:
1003         case OP_CLT:
1004         case OP_CLT_UN:
1005                 ins->type = (bin_comp_table [src1->type] [src2->type] & 1) ? STACK_I4: STACK_INV;
1006                 ins->opcode += ceqops_op_map [src1->type];
1007                 break;
1008         /* unops */
1009         case CEE_NEG:
1010                 ins->type = neg_table [src1->type];
1011                 ins->opcode += unops_op_map [ins->type];
1012                 break;
1013         case CEE_NOT:
1014                 if (src1->type >= STACK_I4 && src1->type <= STACK_PTR)
1015                         ins->type = src1->type;
1016                 else
1017                         ins->type = STACK_INV;
1018                 ins->opcode += unops_op_map [ins->type];
1019                 break;
1020         case CEE_CONV_I1:
1021         case CEE_CONV_I2:
1022         case CEE_CONV_I4:
1023         case CEE_CONV_U4:
1024                 ins->type = STACK_I4;
1025                 ins->opcode += unops_op_map [src1->type];
1026                 break;
1027         case CEE_CONV_R_UN:
1028                 ins->type = STACK_R8;
1029                 switch (src1->type) {
1030                 case STACK_I4:
1031                 case STACK_PTR:
1032                         ins->opcode = OP_ICONV_TO_R_UN;
1033                         break;
1034                 case STACK_I8:
1035                         ins->opcode = OP_LCONV_TO_R_UN; 
1036                         break;
1037                 }
1038                 break;
1039         case CEE_CONV_OVF_I1:
1040         case CEE_CONV_OVF_U1:
1041         case CEE_CONV_OVF_I2:
1042         case CEE_CONV_OVF_U2:
1043         case CEE_CONV_OVF_I4:
1044         case CEE_CONV_OVF_U4:
1045                 ins->type = STACK_I4;
1046                 ins->opcode += ovf3ops_op_map [src1->type];
1047                 break;
1048         case CEE_CONV_OVF_I_UN:
1049         case CEE_CONV_OVF_U_UN:
1050                 ins->type = STACK_PTR;
1051                 ins->opcode += ovf2ops_op_map [src1->type];
1052                 break;
1053         case CEE_CONV_OVF_I1_UN:
1054         case CEE_CONV_OVF_I2_UN:
1055         case CEE_CONV_OVF_I4_UN:
1056         case CEE_CONV_OVF_U1_UN:
1057         case CEE_CONV_OVF_U2_UN:
1058         case CEE_CONV_OVF_U4_UN:
1059                 ins->type = STACK_I4;
1060                 ins->opcode += ovf2ops_op_map [src1->type];
1061                 break;
1062         case CEE_CONV_U:
1063                 ins->type = STACK_PTR;
1064                 switch (src1->type) {
1065                 case STACK_I4:
1066                         ins->opcode = OP_ICONV_TO_U;
1067                         break;
1068                 case STACK_PTR:
1069                 case STACK_MP:
1070 #if SIZEOF_VOID_P == 8
1071                         ins->opcode = OP_LCONV_TO_U;
1072 #else
1073                         ins->opcode = OP_MOVE;
1074 #endif
1075                         break;
1076                 case STACK_I8:
1077                         ins->opcode = OP_LCONV_TO_U;
1078                         break;
1079                 case STACK_R8:
1080                         ins->opcode = OP_FCONV_TO_U;
1081                         break;
1082                 }
1083                 break;
1084         case CEE_CONV_I8:
1085         case CEE_CONV_U8:
1086                 ins->type = STACK_I8;
1087                 ins->opcode += unops_op_map [src1->type];
1088                 break;
1089         case CEE_CONV_OVF_I8:
1090         case CEE_CONV_OVF_U8:
1091                 ins->type = STACK_I8;
1092                 ins->opcode += ovf3ops_op_map [src1->type];
1093                 break;
1094         case CEE_CONV_OVF_U8_UN:
1095         case CEE_CONV_OVF_I8_UN:
1096                 ins->type = STACK_I8;
1097                 ins->opcode += ovf2ops_op_map [src1->type];
1098                 break;
1099         case CEE_CONV_R4:
1100                 ins->type = cfg->r4_stack_type;
1101                 ins->opcode += unops_op_map [src1->type];
1102                 break;
1103         case CEE_CONV_R8:
1104                 ins->type = STACK_R8;
1105                 ins->opcode += unops_op_map [src1->type];
1106                 break;
1107         case OP_CKFINITE:
1108                 ins->type = STACK_R8;           
1109                 break;
1110         case CEE_CONV_U2:
1111         case CEE_CONV_U1:
1112                 ins->type = STACK_I4;
1113                 ins->opcode += ovfops_op_map [src1->type];
1114                 break;
1115         case CEE_CONV_I:
1116         case CEE_CONV_OVF_I:
1117         case CEE_CONV_OVF_U:
1118                 ins->type = STACK_PTR;
1119                 ins->opcode += ovfops_op_map [src1->type];
1120                 break;
1121         case CEE_ADD_OVF:
1122         case CEE_ADD_OVF_UN:
1123         case CEE_MUL_OVF:
1124         case CEE_MUL_OVF_UN:
1125         case CEE_SUB_OVF:
1126         case CEE_SUB_OVF_UN:
1127                 ins->type = bin_num_table [src1->type] [src2->type];
1128                 ins->opcode += ovfops_op_map [src1->type];
1129                 if (ins->type == STACK_R8)
1130                         ins->type = STACK_INV;
1131                 break;
1132         case OP_LOAD_MEMBASE:
1133                 ins->type = STACK_PTR;
1134                 break;
1135         case OP_LOADI1_MEMBASE:
1136         case OP_LOADU1_MEMBASE:
1137         case OP_LOADI2_MEMBASE:
1138         case OP_LOADU2_MEMBASE:
1139         case OP_LOADI4_MEMBASE:
1140         case OP_LOADU4_MEMBASE:
1141                 ins->type = STACK_PTR;
1142                 break;
1143         case OP_LOADI8_MEMBASE:
1144                 ins->type = STACK_I8;
1145                 break;
1146         case OP_LOADR4_MEMBASE:
1147                 ins->type = cfg->r4_stack_type;
1148                 break;
1149         case OP_LOADR8_MEMBASE:
1150                 ins->type = STACK_R8;
1151                 break;
1152         default:
1153                 g_error ("opcode 0x%04x not handled in type from op", ins->opcode);
1154                 break;
1155         }
1156
1157         if (ins->type == STACK_MP)
1158                 ins->klass = mono_defaults.object_class;
1159 }
1160
1161 static const char 
1162 ldind_type [] = {
1163         STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_R8, STACK_OBJ
1164 };
1165
1166 #if 0
1167
1168 static const char
1169 param_table [STACK_MAX] [STACK_MAX] = {
1170         {0},
1171 };
1172
1173 static int
1174 check_values_to_signature (MonoInst *args, MonoType *this_ins, MonoMethodSignature *sig)
1175 {
1176         int i;
1177
1178         if (sig->hasthis) {
1179                 switch (args->type) {
1180                 case STACK_I4:
1181                 case STACK_I8:
1182                 case STACK_R8:
1183                 case STACK_VTYPE:
1184                 case STACK_INV:
1185                         return 0;
1186                 }
1187                 args++;
1188         }
1189         for (i = 0; i < sig->param_count; ++i) {
1190                 switch (args [i].type) {
1191                 case STACK_INV:
1192                         return 0;
1193                 case STACK_MP:
1194                         if (!sig->params [i]->byref)
1195                                 return 0;
1196                         continue;
1197                 case STACK_OBJ:
1198                         if (sig->params [i]->byref)
1199                                 return 0;
1200                         switch (sig->params [i]->type) {
1201                         case MONO_TYPE_CLASS:
1202                         case MONO_TYPE_STRING:
1203                         case MONO_TYPE_OBJECT:
1204                         case MONO_TYPE_SZARRAY:
1205                         case MONO_TYPE_ARRAY:
1206                                 break;
1207                         default:
1208                                 return 0;
1209                         }
1210                         continue;
1211                 case STACK_R8:
1212                         if (sig->params [i]->byref)
1213                                 return 0;
1214                         if (sig->params [i]->type != MONO_TYPE_R4 && sig->params [i]->type != MONO_TYPE_R8)
1215                                 return 0;
1216                         continue;
1217                 case STACK_PTR:
1218                 case STACK_I4:
1219                 case STACK_I8:
1220                 case STACK_VTYPE:
1221                         break;
1222                 }
1223                 /*if (!param_table [args [i].type] [sig->params [i]->type])
1224                         return 0;*/
1225         }
1226         return 1;
1227 }
1228 #endif
1229
1230 /*
1231  * When we need a pointer to the current domain many times in a method, we
1232  * call mono_domain_get() once and we store the result in a local variable.
1233  * This function returns the variable that represents the MonoDomain*.
1234  */
1235 inline static MonoInst *
1236 mono_get_domainvar (MonoCompile *cfg)
1237 {
1238         if (!cfg->domainvar)
1239                 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1240         return cfg->domainvar;
1241 }
1242
1243 /*
1244  * The got_var contains the address of the Global Offset Table when AOT 
1245  * compiling.
1246  */
1247 MonoInst *
1248 mono_get_got_var (MonoCompile *cfg)
1249 {
1250         if (!cfg->compile_aot || !cfg->backend->need_got_var)
1251                 return NULL;
1252         if (!cfg->got_var) {
1253                 cfg->got_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1254         }
1255         return cfg->got_var;
1256 }
1257
1258 static MonoInst *
1259 mono_get_vtable_var (MonoCompile *cfg)
1260 {
1261         g_assert (cfg->gshared);
1262
1263         if (!cfg->rgctx_var) {
1264                 cfg->rgctx_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1265                 /* force the var to be stack allocated */
1266                 cfg->rgctx_var->flags |= MONO_INST_VOLATILE;
1267         }
1268
1269         return cfg->rgctx_var;
1270 }
1271
1272 static MonoType*
1273 type_from_stack_type (MonoInst *ins) {
1274         switch (ins->type) {
1275         case STACK_I4: return &mono_defaults.int32_class->byval_arg;
1276         case STACK_I8: return &mono_defaults.int64_class->byval_arg;
1277         case STACK_PTR: return &mono_defaults.int_class->byval_arg;
1278         case STACK_R4: return &mono_defaults.single_class->byval_arg;
1279         case STACK_R8: return &mono_defaults.double_class->byval_arg;
1280         case STACK_MP:
1281                 return &ins->klass->this_arg;
1282         case STACK_OBJ: return &mono_defaults.object_class->byval_arg;
1283         case STACK_VTYPE: return &ins->klass->byval_arg;
1284         default:
1285                 g_error ("stack type %d to monotype not handled\n", ins->type);
1286         }
1287         return NULL;
1288 }
1289
1290 static G_GNUC_UNUSED int
1291 type_to_stack_type (MonoCompile *cfg, MonoType *t)
1292 {
1293         t = mono_type_get_underlying_type (t);
1294         switch (t->type) {
1295         case MONO_TYPE_I1:
1296         case MONO_TYPE_U1:
1297         case MONO_TYPE_I2:
1298         case MONO_TYPE_U2:
1299         case MONO_TYPE_I4:
1300         case MONO_TYPE_U4:
1301                 return STACK_I4;
1302         case MONO_TYPE_I:
1303         case MONO_TYPE_U:
1304         case MONO_TYPE_PTR:
1305         case MONO_TYPE_FNPTR:
1306                 return STACK_PTR;
1307         case MONO_TYPE_CLASS:
1308         case MONO_TYPE_STRING:
1309         case MONO_TYPE_OBJECT:
1310         case MONO_TYPE_SZARRAY:
1311         case MONO_TYPE_ARRAY:    
1312                 return STACK_OBJ;
1313         case MONO_TYPE_I8:
1314         case MONO_TYPE_U8:
1315                 return STACK_I8;
1316         case MONO_TYPE_R4:
1317                 return cfg->r4_stack_type;
1318         case MONO_TYPE_R8:
1319                 return STACK_R8;
1320         case MONO_TYPE_VALUETYPE:
1321         case MONO_TYPE_TYPEDBYREF:
1322                 return STACK_VTYPE;
1323         case MONO_TYPE_GENERICINST:
1324                 if (mono_type_generic_inst_is_valuetype (t))
1325                         return STACK_VTYPE;
1326                 else
1327                         return STACK_OBJ;
1328                 break;
1329         default:
1330                 g_assert_not_reached ();
1331         }
1332
1333         return -1;
1334 }
1335
1336 static MonoClass*
1337 array_access_to_klass (int opcode)
1338 {
1339         switch (opcode) {
1340         case CEE_LDELEM_U1:
1341                 return mono_defaults.byte_class;
1342         case CEE_LDELEM_U2:
1343                 return mono_defaults.uint16_class;
1344         case CEE_LDELEM_I:
1345         case CEE_STELEM_I:
1346                 return mono_defaults.int_class;
1347         case CEE_LDELEM_I1:
1348         case CEE_STELEM_I1:
1349                 return mono_defaults.sbyte_class;
1350         case CEE_LDELEM_I2:
1351         case CEE_STELEM_I2:
1352                 return mono_defaults.int16_class;
1353         case CEE_LDELEM_I4:
1354         case CEE_STELEM_I4:
1355                 return mono_defaults.int32_class;
1356         case CEE_LDELEM_U4:
1357                 return mono_defaults.uint32_class;
1358         case CEE_LDELEM_I8:
1359         case CEE_STELEM_I8:
1360                 return mono_defaults.int64_class;
1361         case CEE_LDELEM_R4:
1362         case CEE_STELEM_R4:
1363                 return mono_defaults.single_class;
1364         case CEE_LDELEM_R8:
1365         case CEE_STELEM_R8:
1366                 return mono_defaults.double_class;
1367         case CEE_LDELEM_REF:
1368         case CEE_STELEM_REF:
1369                 return mono_defaults.object_class;
1370         default:
1371                 g_assert_not_reached ();
1372         }
1373         return NULL;
1374 }
1375
1376 /*
1377  * We try to share variables when possible
1378  */
1379 static MonoInst *
1380 mono_compile_get_interface_var (MonoCompile *cfg, int slot, MonoInst *ins)
1381 {
1382         MonoInst *res;
1383         int pos, vnum;
1384
1385         /* inlining can result in deeper stacks */ 
1386         if (slot >= cfg->header->max_stack)
1387                 return mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1388
1389         pos = ins->type - 1 + slot * STACK_MAX;
1390
1391         switch (ins->type) {
1392         case STACK_I4:
1393         case STACK_I8:
1394         case STACK_R8:
1395         case STACK_PTR:
1396         case STACK_MP:
1397         case STACK_OBJ:
1398                 if ((vnum = cfg->intvars [pos]))
1399                         return cfg->varinfo [vnum];
1400                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1401                 cfg->intvars [pos] = res->inst_c0;
1402                 break;
1403         default:
1404                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1405         }
1406         return res;
1407 }
1408
1409 static void
1410 mono_save_token_info (MonoCompile *cfg, MonoImage *image, guint32 token, gpointer key)
1411 {
1412         /* 
1413          * Don't use this if a generic_context is set, since that means AOT can't
1414          * look up the method using just the image+token.
1415          * table == 0 means this is a reference made from a wrapper.
1416          */
1417         if (cfg->compile_aot && !cfg->generic_context && (mono_metadata_token_table (token) > 0)) {
1418                 MonoJumpInfoToken *jump_info_token = (MonoJumpInfoToken *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoToken));
1419                 jump_info_token->image = image;
1420                 jump_info_token->token = token;
1421                 g_hash_table_insert (cfg->token_info_hash, key, jump_info_token);
1422         }
1423 }
1424
1425 /*
1426  * This function is called to handle items that are left on the evaluation stack
1427  * at basic block boundaries. What happens is that we save the values to local variables
1428  * and we reload them later when first entering the target basic block (with the
1429  * handle_loaded_temps () function).
1430  * A single joint point will use the same variables (stored in the array bb->out_stack or
1431  * bb->in_stack, if the basic block is before or after the joint point).
1432  *
1433  * This function needs to be called _before_ emitting the last instruction of
1434  * the bb (i.e. before emitting a branch).
1435  * If the stack merge fails at a join point, cfg->unverifiable is set.
1436  */
1437 static void
1438 handle_stack_args (MonoCompile *cfg, MonoInst **sp, int count)
1439 {
1440         int i, bindex;
1441         MonoBasicBlock *bb = cfg->cbb;
1442         MonoBasicBlock *outb;
1443         MonoInst *inst, **locals;
1444         gboolean found;
1445
1446         if (!count)
1447                 return;
1448         if (cfg->verbose_level > 3)
1449                 printf ("%d item(s) on exit from B%d\n", count, bb->block_num);
1450         if (!bb->out_scount) {
1451                 bb->out_scount = count;
1452                 //printf ("bblock %d has out:", bb->block_num);
1453                 found = FALSE;
1454                 for (i = 0; i < bb->out_count; ++i) {
1455                         outb = bb->out_bb [i];
1456                         /* exception handlers are linked, but they should not be considered for stack args */
1457                         if (outb->flags & BB_EXCEPTION_HANDLER)
1458                                 continue;
1459                         //printf (" %d", outb->block_num);
1460                         if (outb->in_stack) {
1461                                 found = TRUE;
1462                                 bb->out_stack = outb->in_stack;
1463                                 break;
1464                         }
1465                 }
1466                 //printf ("\n");
1467                 if (!found) {
1468                         bb->out_stack = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * count);
1469                         for (i = 0; i < count; ++i) {
1470                                 /* 
1471                                  * try to reuse temps already allocated for this purpouse, if they occupy the same
1472                                  * stack slot and if they are of the same type.
1473                                  * This won't cause conflicts since if 'local' is used to 
1474                                  * store one of the values in the in_stack of a bblock, then
1475                                  * the same variable will be used for the same outgoing stack 
1476                                  * slot as well. 
1477                                  * This doesn't work when inlining methods, since the bblocks
1478                                  * in the inlined methods do not inherit their in_stack from
1479                                  * the bblock they are inlined to. See bug #58863 for an
1480                                  * example.
1481                                  */
1482                                 if (cfg->inlined_method)
1483                                         bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
1484                                 else
1485                                         bb->out_stack [i] = mono_compile_get_interface_var (cfg, i, sp [i]);
1486                         }
1487                 }
1488         }
1489
1490         for (i = 0; i < bb->out_count; ++i) {
1491                 outb = bb->out_bb [i];
1492                 /* exception handlers are linked, but they should not be considered for stack args */
1493                 if (outb->flags & BB_EXCEPTION_HANDLER)
1494                         continue;
1495                 if (outb->in_scount) {
1496                         if (outb->in_scount != bb->out_scount) {
1497                                 cfg->unverifiable = TRUE;
1498                                 return;
1499                         }
1500                         continue; /* check they are the same locals */
1501                 }
1502                 outb->in_scount = count;
1503                 outb->in_stack = bb->out_stack;
1504         }
1505
1506         locals = bb->out_stack;
1507         cfg->cbb = bb;
1508         for (i = 0; i < count; ++i) {
1509                 EMIT_NEW_TEMPSTORE (cfg, inst, locals [i]->inst_c0, sp [i]);
1510                 inst->cil_code = sp [i]->cil_code;
1511                 sp [i] = locals [i];
1512                 if (cfg->verbose_level > 3)
1513                         printf ("storing %d to temp %d\n", i, (int)locals [i]->inst_c0);
1514         }
1515
1516         /*
1517          * It is possible that the out bblocks already have in_stack assigned, and
1518          * the in_stacks differ. In this case, we will store to all the different 
1519          * in_stacks.
1520          */
1521
1522         found = TRUE;
1523         bindex = 0;
1524         while (found) {
1525                 /* Find a bblock which has a different in_stack */
1526                 found = FALSE;
1527                 while (bindex < bb->out_count) {
1528                         outb = bb->out_bb [bindex];
1529                         /* exception handlers are linked, but they should not be considered for stack args */
1530                         if (outb->flags & BB_EXCEPTION_HANDLER) {
1531                                 bindex++;
1532                                 continue;
1533                         }
1534                         if (outb->in_stack != locals) {
1535                                 for (i = 0; i < count; ++i) {
1536                                         EMIT_NEW_TEMPSTORE (cfg, inst, outb->in_stack [i]->inst_c0, sp [i]);
1537                                         inst->cil_code = sp [i]->cil_code;
1538                                         sp [i] = locals [i];
1539                                         if (cfg->verbose_level > 3)
1540                                                 printf ("storing %d to temp %d\n", i, (int)outb->in_stack [i]->inst_c0);
1541                                 }
1542                                 locals = outb->in_stack;
1543                                 found = TRUE;
1544                                 break;
1545                         }
1546                         bindex ++;
1547                 }
1548         }
1549 }
1550
1551 static MonoInst*
1552 emit_runtime_constant (MonoCompile *cfg, MonoJumpInfoType patch_type, gpointer data)
1553 {
1554         MonoInst *ins;
1555
1556         if (cfg->compile_aot) {
1557                 EMIT_NEW_AOTCONST (cfg, ins, patch_type, data);
1558         } else {
1559                 MonoJumpInfo ji;
1560                 gpointer target;
1561                 MonoError error;
1562
1563                 ji.type = patch_type;
1564                 ji.data.target = data;
1565                 target = mono_resolve_patch_target (NULL, cfg->domain, NULL, &ji, FALSE, &error);
1566                 mono_error_assert_ok (&error);
1567
1568                 EMIT_NEW_PCONST (cfg, ins, target);
1569         }
1570         return ins;
1571 }
1572
1573 static void
1574 mini_emit_interface_bitmap_check (MonoCompile *cfg, int intf_bit_reg, int base_reg, int offset, MonoClass *klass)
1575 {
1576         int ibitmap_reg = alloc_preg (cfg);
1577 #ifdef COMPRESSED_INTERFACE_BITMAP
1578         MonoInst *args [2];
1579         MonoInst *res, *ins;
1580         NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, ibitmap_reg, base_reg, offset);
1581         MONO_ADD_INS (cfg->cbb, ins);
1582         args [0] = ins;
1583         args [1] = emit_runtime_constant (cfg, MONO_PATCH_INFO_IID, klass);
1584         res = mono_emit_jit_icall (cfg, mono_class_interface_match, args);
1585         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, intf_bit_reg, res->dreg);
1586 #else
1587         int ibitmap_byte_reg = alloc_preg (cfg);
1588
1589         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, ibitmap_reg, base_reg, offset);
1590
1591         if (cfg->compile_aot) {
1592                 int iid_reg = alloc_preg (cfg);
1593                 int shifted_iid_reg = alloc_preg (cfg);
1594                 int ibitmap_byte_address_reg = alloc_preg (cfg);
1595                 int masked_iid_reg = alloc_preg (cfg);
1596                 int iid_one_bit_reg = alloc_preg (cfg);
1597                 int iid_bit_reg = alloc_preg (cfg);
1598                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1599                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, shifted_iid_reg, iid_reg, 3);
1600                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, ibitmap_byte_address_reg, ibitmap_reg, shifted_iid_reg);
1601                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, ibitmap_byte_reg, ibitmap_byte_address_reg, 0);
1602                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, masked_iid_reg, iid_reg, 7);
1603                 MONO_EMIT_NEW_ICONST (cfg, iid_one_bit_reg, 1);
1604                 MONO_EMIT_NEW_BIALU (cfg, OP_ISHL, iid_bit_reg, iid_one_bit_reg, masked_iid_reg);
1605                 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, intf_bit_reg, ibitmap_byte_reg, iid_bit_reg);
1606         } else {
1607                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, ibitmap_byte_reg, ibitmap_reg, klass->interface_id >> 3);
1608                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, intf_bit_reg, ibitmap_byte_reg, 1 << (klass->interface_id & 7));
1609         }
1610 #endif
1611 }
1612
1613 /* 
1614  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoClass
1615  * stored in "klass_reg" implements the interface "klass".
1616  */
1617 static void
1618 mini_emit_load_intf_bit_reg_class (MonoCompile *cfg, int intf_bit_reg, int klass_reg, MonoClass *klass)
1619 {
1620         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, interface_bitmap), klass);
1621 }
1622
1623 /* 
1624  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoVTable
1625  * stored in "vtable_reg" implements the interface "klass".
1626  */
1627 static void
1628 mini_emit_load_intf_bit_reg_vtable (MonoCompile *cfg, int intf_bit_reg, int vtable_reg, MonoClass *klass)
1629 {
1630         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, interface_bitmap), klass);
1631 }
1632
1633 /* 
1634  * Emit code which checks whenever the interface id of @klass is smaller than
1635  * than the value given by max_iid_reg.
1636 */
1637 static void
1638 mini_emit_max_iid_check (MonoCompile *cfg, int max_iid_reg, MonoClass *klass,
1639                                                  MonoBasicBlock *false_target)
1640 {
1641         if (cfg->compile_aot) {
1642                 int iid_reg = alloc_preg (cfg);
1643                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1644                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, max_iid_reg, iid_reg);
1645         }
1646         else
1647                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, max_iid_reg, klass->interface_id);
1648         if (false_target)
1649                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1650         else
1651                 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1652 }
1653
1654 /* Same as above, but obtains max_iid from a vtable */
1655 static void
1656 mini_emit_max_iid_check_vtable (MonoCompile *cfg, int vtable_reg, MonoClass *klass,
1657                                                                  MonoBasicBlock *false_target)
1658 {
1659         int max_iid_reg = alloc_preg (cfg);
1660                 
1661         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, max_interface_id));
1662         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1663 }
1664
1665 /* Same as above, but obtains max_iid from a klass */
1666 static void
1667 mini_emit_max_iid_check_class (MonoCompile *cfg, int klass_reg, MonoClass *klass,
1668                                                                  MonoBasicBlock *false_target)
1669 {
1670         int max_iid_reg = alloc_preg (cfg);
1671
1672         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, max_interface_id));
1673         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1674 }
1675
1676 static void
1677 mini_emit_isninst_cast_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_ins, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1678 {
1679         int idepth_reg = alloc_preg (cfg);
1680         int stypes_reg = alloc_preg (cfg);
1681         int stype = alloc_preg (cfg);
1682
1683         mono_class_setup_supertypes (klass);
1684
1685         if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1686                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth));
1687                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1688                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1689         }
1690         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes));
1691         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1692         if (klass_ins) {
1693                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, klass_ins->dreg);
1694         } else if (cfg->compile_aot) {
1695                 int const_reg = alloc_preg (cfg);
1696                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1697                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, const_reg);
1698         } else {
1699                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, stype, klass);
1700         }
1701         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, true_target);
1702 }
1703
1704 static void
1705 mini_emit_isninst_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1706 {
1707         mini_emit_isninst_cast_inst (cfg, klass_reg, klass, NULL, false_target, true_target);
1708 }
1709
1710 static void
1711 mini_emit_iface_cast (MonoCompile *cfg, int vtable_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1712 {
1713         int intf_reg = alloc_preg (cfg);
1714
1715         mini_emit_max_iid_check_vtable (cfg, vtable_reg, klass, false_target);
1716         mini_emit_load_intf_bit_reg_vtable (cfg, intf_reg, vtable_reg, klass);
1717         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_reg, 0);
1718         if (true_target)
1719                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1720         else
1721                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");               
1722 }
1723
1724 /*
1725  * Variant of the above that takes a register to the class, not the vtable.
1726  */
1727 static void
1728 mini_emit_iface_class_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1729 {
1730         int intf_bit_reg = alloc_preg (cfg);
1731
1732         mini_emit_max_iid_check_class (cfg, klass_reg, klass, false_target);
1733         mini_emit_load_intf_bit_reg_class (cfg, intf_bit_reg, klass_reg, klass);
1734         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_bit_reg, 0);
1735         if (true_target)
1736                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1737         else
1738                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
1739 }
1740
1741 static inline void
1742 mini_emit_class_check_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_inst)
1743 {
1744         if (klass_inst) {
1745                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_inst->dreg);
1746         } else {
1747                 MonoInst *ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, klass);
1748                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, ins->dreg);
1749         }
1750         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1751 }
1752
1753 static inline void
1754 mini_emit_class_check (MonoCompile *cfg, int klass_reg, MonoClass *klass)
1755 {
1756         mini_emit_class_check_inst (cfg, klass_reg, klass, NULL);
1757 }
1758
1759 static inline void
1760 mini_emit_class_check_branch (MonoCompile *cfg, int klass_reg, MonoClass *klass, int branch_op, MonoBasicBlock *target)
1761 {
1762         if (cfg->compile_aot) {
1763                 int const_reg = alloc_preg (cfg);
1764                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1765                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, const_reg);
1766         } else {
1767                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
1768         }
1769         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, branch_op, target);
1770 }
1771
1772 static void
1773 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null);
1774         
1775 static void
1776 mini_emit_castclass_inst (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoInst *klass_inst, MonoBasicBlock *object_is_null)
1777 {
1778         if (klass->rank) {
1779                 int rank_reg = alloc_preg (cfg);
1780                 int eclass_reg = alloc_preg (cfg);
1781
1782                 g_assert (!klass_inst);
1783                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, rank));
1784                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
1785                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1786                 //              MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
1787                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
1788                 if (klass->cast_class == mono_defaults.object_class) {
1789                         int parent_reg = alloc_preg (cfg);
1790                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
1791                         mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, object_is_null);
1792                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1793                 } else if (klass->cast_class == mono_defaults.enum_class->parent) {
1794                         mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, object_is_null);
1795                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1796                 } else if (klass->cast_class == mono_defaults.enum_class) {
1797                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1798                 } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1799                         mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, NULL, NULL);
1800                 } else {
1801                         // Pass -1 as obj_reg to skip the check below for arrays of arrays
1802                         mini_emit_castclass (cfg, -1, eclass_reg, klass->cast_class, object_is_null);
1803                 }
1804
1805                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY) && (obj_reg != -1)) {
1806                         /* Check that the object is a vector too */
1807                         int bounds_reg = alloc_preg (cfg);
1808                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
1809                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
1810                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1811                 }
1812         } else {
1813                 int idepth_reg = alloc_preg (cfg);
1814                 int stypes_reg = alloc_preg (cfg);
1815                 int stype = alloc_preg (cfg);
1816
1817                 mono_class_setup_supertypes (klass);
1818
1819                 if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1820                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth));
1821                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1822                         MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1823                 }
1824                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes));
1825                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1826                 mini_emit_class_check_inst (cfg, stype, klass, klass_inst);
1827         }
1828 }
1829
1830 static void
1831 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null)
1832 {
1833         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, NULL, object_is_null);
1834 }
1835
1836 static void 
1837 mini_emit_memset (MonoCompile *cfg, int destreg, int offset, int size, int val, int align)
1838 {
1839         int val_reg;
1840
1841         g_assert (val == 0);
1842
1843         if (align == 0)
1844                 align = 4;
1845
1846         if ((size <= SIZEOF_REGISTER) && (size <= align)) {
1847                 switch (size) {
1848                 case 1:
1849                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, destreg, offset, val);
1850                         return;
1851                 case 2:
1852                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI2_MEMBASE_IMM, destreg, offset, val);
1853                         return;
1854                 case 4:
1855                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI4_MEMBASE_IMM, destreg, offset, val);
1856                         return;
1857 #if SIZEOF_REGISTER == 8
1858                 case 8:
1859                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI8_MEMBASE_IMM, destreg, offset, val);
1860                         return;
1861 #endif
1862                 }
1863         }
1864
1865         val_reg = alloc_preg (cfg);
1866
1867         if (SIZEOF_REGISTER == 8)
1868                 MONO_EMIT_NEW_I8CONST (cfg, val_reg, val);
1869         else
1870                 MONO_EMIT_NEW_ICONST (cfg, val_reg, val);
1871
1872         if (align < 4) {
1873                 /* This could be optimized further if neccesary */
1874                 while (size >= 1) {
1875                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1876                         offset += 1;
1877                         size -= 1;
1878                 }
1879                 return;
1880         }       
1881
1882         if (!cfg->backend->no_unaligned_access && SIZEOF_REGISTER == 8) {
1883                 if (offset % 8) {
1884                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1885                         offset += 4;
1886                         size -= 4;
1887                 }
1888                 while (size >= 8) {
1889                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, offset, val_reg);
1890                         offset += 8;
1891                         size -= 8;
1892                 }
1893         }       
1894
1895         while (size >= 4) {
1896                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1897                 offset += 4;
1898                 size -= 4;
1899         }
1900         while (size >= 2) {
1901                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, val_reg);
1902                 offset += 2;
1903                 size -= 2;
1904         }
1905         while (size >= 1) {
1906                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1907                 offset += 1;
1908                 size -= 1;
1909         }
1910 }
1911
1912 void 
1913 mini_emit_memcpy (MonoCompile *cfg, int destreg, int doffset, int srcreg, int soffset, int size, int align)
1914 {
1915         int cur_reg;
1916
1917         if (align == 0)
1918                 align = 4;
1919
1920         /*FIXME arbitrary hack to avoid unbound code expansion.*/
1921         g_assert (size < 10000);
1922
1923         if (align < 4) {
1924                 /* This could be optimized further if neccesary */
1925                 while (size >= 1) {
1926                         cur_reg = alloc_preg (cfg);
1927                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1928                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1929                         doffset += 1;
1930                         soffset += 1;
1931                         size -= 1;
1932                 }
1933         }
1934
1935         if (!cfg->backend->no_unaligned_access && SIZEOF_REGISTER == 8) {
1936                 while (size >= 8) {
1937                         cur_reg = alloc_preg (cfg);
1938                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI8_MEMBASE, cur_reg, srcreg, soffset);
1939                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, doffset, cur_reg);
1940                         doffset += 8;
1941                         soffset += 8;
1942                         size -= 8;
1943                 }
1944         }       
1945
1946         while (size >= 4) {
1947                 cur_reg = alloc_preg (cfg);
1948                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, cur_reg, srcreg, soffset);
1949                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, doffset, cur_reg);
1950                 doffset += 4;
1951                 soffset += 4;
1952                 size -= 4;
1953         }
1954         while (size >= 2) {
1955                 cur_reg = alloc_preg (cfg);
1956                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, cur_reg, srcreg, soffset);
1957                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, doffset, cur_reg);
1958                 doffset += 2;
1959                 soffset += 2;
1960                 size -= 2;
1961         }
1962         while (size >= 1) {
1963                 cur_reg = alloc_preg (cfg);
1964                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1965                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1966                 doffset += 1;
1967                 soffset += 1;
1968                 size -= 1;
1969         }
1970 }
1971
1972 static void
1973 emit_tls_set (MonoCompile *cfg, int sreg1, MonoTlsKey tls_key)
1974 {
1975         MonoInst *ins, *c;
1976
1977         if (cfg->compile_aot) {
1978                 EMIT_NEW_TLS_OFFSETCONST (cfg, c, tls_key);
1979                 MONO_INST_NEW (cfg, ins, OP_TLS_SET_REG);
1980                 ins->sreg1 = sreg1;
1981                 ins->sreg2 = c->dreg;
1982                 MONO_ADD_INS (cfg->cbb, ins);
1983         } else {
1984                 MONO_INST_NEW (cfg, ins, OP_TLS_SET);
1985                 ins->sreg1 = sreg1;
1986                 ins->inst_offset = mini_get_tls_offset (tls_key);
1987                 MONO_ADD_INS (cfg->cbb, ins);
1988         }
1989 }
1990
1991 /*
1992  * emit_push_lmf:
1993  *
1994  *   Emit IR to push the current LMF onto the LMF stack.
1995  */
1996 static void
1997 emit_push_lmf (MonoCompile *cfg)
1998 {
1999         /*
2000          * Emit IR to push the LMF:
2001          * lmf_addr = <lmf_addr from tls>
2002          * lmf->lmf_addr = lmf_addr
2003          * lmf->prev_lmf = *lmf_addr
2004          * *lmf_addr = lmf
2005          */
2006         int lmf_reg, prev_lmf_reg;
2007         MonoInst *ins, *lmf_ins;
2008
2009         if (!cfg->lmf_ir)
2010                 return;
2011
2012         if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
2013                 /* Load current lmf */
2014                 lmf_ins = mono_get_lmf_intrinsic (cfg);
2015                 g_assert (lmf_ins);
2016                 MONO_ADD_INS (cfg->cbb, lmf_ins);
2017                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2018                 lmf_reg = ins->dreg;
2019                 /* Save previous_lmf */
2020                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), lmf_ins->dreg);
2021                 /* Set new LMF */
2022                 emit_tls_set (cfg, lmf_reg, TLS_KEY_LMF);
2023         } else {
2024                 /*
2025                  * Store lmf_addr in a variable, so it can be allocated to a global register.
2026                  */
2027                 if (!cfg->lmf_addr_var)
2028                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2029
2030 #ifdef HOST_WIN32
2031                 ins = mono_get_jit_tls_intrinsic (cfg);
2032                 if (ins) {
2033                         int jit_tls_dreg = ins->dreg;
2034
2035                         MONO_ADD_INS (cfg->cbb, ins);
2036                         lmf_reg = alloc_preg (cfg);
2037                         EMIT_NEW_BIALU_IMM (cfg, lmf_ins, OP_PADD_IMM, lmf_reg, jit_tls_dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, lmf));
2038                 } else {
2039                         lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
2040                 }
2041 #else
2042                 lmf_ins = mono_get_lmf_addr_intrinsic (cfg);
2043                 if (lmf_ins) {
2044                         MONO_ADD_INS (cfg->cbb, lmf_ins);
2045                 } else {
2046 #ifdef TARGET_IOS
2047                         MonoInst *args [16], *jit_tls_ins, *ins;
2048
2049                         /* Inline mono_get_lmf_addr () */
2050                         /* jit_tls = pthread_getspecific (mono_jit_tls_id); lmf_addr = &jit_tls->lmf; */
2051
2052                         /* Load mono_jit_tls_id */
2053                         if (cfg->compile_aot)
2054                                 EMIT_NEW_AOTCONST (cfg, args [0], MONO_PATCH_INFO_JIT_TLS_ID, NULL);
2055                         else
2056                                 EMIT_NEW_ICONST (cfg, args [0], mono_jit_tls_id);
2057                         /* call pthread_getspecific () */
2058                         jit_tls_ins = mono_emit_jit_icall (cfg, pthread_getspecific, args);
2059                         /* lmf_addr = &jit_tls->lmf */
2060                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, cfg->lmf_addr_var->dreg, jit_tls_ins->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, lmf));
2061                         lmf_ins = ins;
2062 #else
2063                         lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
2064 #endif
2065                 }
2066 #endif
2067                 lmf_ins->dreg = cfg->lmf_addr_var->dreg;
2068
2069                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2070                 lmf_reg = ins->dreg;
2071
2072                 prev_lmf_reg = alloc_preg (cfg);
2073                 /* Save previous_lmf */
2074                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, cfg->lmf_addr_var->dreg, 0);
2075                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), prev_lmf_reg);
2076                 /* Set new lmf */
2077                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, cfg->lmf_addr_var->dreg, 0, lmf_reg);
2078         }
2079 }
2080
2081 /*
2082  * emit_pop_lmf:
2083  *
2084  *   Emit IR to pop the current LMF from the LMF stack.
2085  */
2086 static void
2087 emit_pop_lmf (MonoCompile *cfg)
2088 {
2089         int lmf_reg, lmf_addr_reg, prev_lmf_reg;
2090         MonoInst *ins;
2091
2092         if (!cfg->lmf_ir)
2093                 return;
2094
2095         EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2096         lmf_reg = ins->dreg;
2097
2098         if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
2099                 /* Load previous_lmf */
2100                 prev_lmf_reg = alloc_preg (cfg);
2101                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
2102                 /* Set new LMF */
2103                 emit_tls_set (cfg, prev_lmf_reg, TLS_KEY_LMF);
2104         } else {
2105                 /*
2106                  * Emit IR to pop the LMF:
2107                  * *(lmf->lmf_addr) = lmf->prev_lmf
2108                  */
2109                 /* This could be called before emit_push_lmf () */
2110                 if (!cfg->lmf_addr_var)
2111                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2112                 lmf_addr_reg = cfg->lmf_addr_var->dreg;
2113
2114                 prev_lmf_reg = alloc_preg (cfg);
2115                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
2116                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_addr_reg, 0, prev_lmf_reg);
2117         }
2118 }
2119
2120 static void
2121 emit_instrumentation_call (MonoCompile *cfg, void *func)
2122 {
2123         MonoInst *iargs [1];
2124
2125         /*
2126          * Avoid instrumenting inlined methods since it can
2127          * distort profiling results.
2128          */
2129         if (cfg->method != cfg->current_method)
2130                 return;
2131
2132         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE) {
2133                 EMIT_NEW_METHODCONST (cfg, iargs [0], cfg->method);
2134                 mono_emit_jit_icall (cfg, func, iargs);
2135         }
2136 }
2137
2138 static int
2139 ret_type_to_call_opcode (MonoCompile *cfg, MonoType *type, int calli, int virt)
2140 {
2141 handle_enum:
2142         type = mini_get_underlying_type (type);
2143         switch (type->type) {
2144         case MONO_TYPE_VOID:
2145                 return calli? OP_VOIDCALL_REG: virt? OP_VOIDCALL_MEMBASE: OP_VOIDCALL;
2146         case MONO_TYPE_I1:
2147         case MONO_TYPE_U1:
2148         case MONO_TYPE_I2:
2149         case MONO_TYPE_U2:
2150         case MONO_TYPE_I4:
2151         case MONO_TYPE_U4:
2152                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2153         case MONO_TYPE_I:
2154         case MONO_TYPE_U:
2155         case MONO_TYPE_PTR:
2156         case MONO_TYPE_FNPTR:
2157                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2158         case MONO_TYPE_CLASS:
2159         case MONO_TYPE_STRING:
2160         case MONO_TYPE_OBJECT:
2161         case MONO_TYPE_SZARRAY:
2162         case MONO_TYPE_ARRAY:    
2163                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2164         case MONO_TYPE_I8:
2165         case MONO_TYPE_U8:
2166                 return calli? OP_LCALL_REG: virt? OP_LCALL_MEMBASE: OP_LCALL;
2167         case MONO_TYPE_R4:
2168                 if (cfg->r4fp)
2169                         return calli? OP_RCALL_REG: virt? OP_RCALL_MEMBASE: OP_RCALL;
2170                 else
2171                         return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
2172         case MONO_TYPE_R8:
2173                 return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
2174         case MONO_TYPE_VALUETYPE:
2175                 if (type->data.klass->enumtype) {
2176                         type = mono_class_enum_basetype (type->data.klass);
2177                         goto handle_enum;
2178                 } else
2179                         return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2180         case MONO_TYPE_TYPEDBYREF:
2181                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2182         case MONO_TYPE_GENERICINST:
2183                 type = &type->data.generic_class->container_class->byval_arg;
2184                 goto handle_enum;
2185         case MONO_TYPE_VAR:
2186         case MONO_TYPE_MVAR:
2187                 /* gsharedvt */
2188                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2189         default:
2190                 g_error ("unknown type 0x%02x in ret_type_to_call_opcode", type->type);
2191         }
2192         return -1;
2193 }
2194
2195 //XXX this ignores if t is byref
2196 #define MONO_TYPE_IS_PRIMITIVE_SCALAR(t) ((((((t)->type >= MONO_TYPE_BOOLEAN && (t)->type <= MONO_TYPE_U8) || ((t)->type >= MONO_TYPE_I && (t)->type <= MONO_TYPE_U)))))
2197
2198 /*
2199  * target_type_is_incompatible:
2200  * @cfg: MonoCompile context
2201  *
2202  * Check that the item @arg on the evaluation stack can be stored
2203  * in the target type (can be a local, or field, etc).
2204  * The cfg arg can be used to check if we need verification or just
2205  * validity checks.
2206  *
2207  * Returns: non-0 value if arg can't be stored on a target.
2208  */
2209 static int
2210 target_type_is_incompatible (MonoCompile *cfg, MonoType *target, MonoInst *arg)
2211 {
2212         MonoType *simple_type;
2213         MonoClass *klass;
2214
2215         if (target->byref) {
2216                 /* FIXME: check that the pointed to types match */
2217                 if (arg->type == STACK_MP) {
2218                         /* This is needed to handle gshared types + ldaddr. We lower the types so we can handle enums and other typedef-like types. */
2219                         MonoClass *target_class_lowered = mono_class_from_mono_type (mini_get_underlying_type (&mono_class_from_mono_type (target)->byval_arg));
2220                         MonoClass *source_class_lowered = mono_class_from_mono_type (mini_get_underlying_type (&arg->klass->byval_arg));
2221
2222                         /* if the target is native int& or same type */
2223                         if (target->type == MONO_TYPE_I || target_class_lowered == source_class_lowered)
2224                                 return 0;
2225
2226                         /* Both are primitive type byrefs and the source points to a larger type that the destination */
2227                         if (MONO_TYPE_IS_PRIMITIVE_SCALAR (&target_class_lowered->byval_arg) && MONO_TYPE_IS_PRIMITIVE_SCALAR (&source_class_lowered->byval_arg) &&
2228                                 mono_class_instance_size (target_class_lowered) <= mono_class_instance_size (source_class_lowered))
2229                                 return 0;
2230                         return 1;
2231                 }
2232                 if (arg->type == STACK_PTR)
2233                         return 0;
2234                 return 1;
2235         }
2236
2237         simple_type = mini_get_underlying_type (target);
2238         switch (simple_type->type) {
2239         case MONO_TYPE_VOID:
2240                 return 1;
2241         case MONO_TYPE_I1:
2242         case MONO_TYPE_U1:
2243         case MONO_TYPE_I2:
2244         case MONO_TYPE_U2:
2245         case MONO_TYPE_I4:
2246         case MONO_TYPE_U4:
2247                 if (arg->type != STACK_I4 && arg->type != STACK_PTR)
2248                         return 1;
2249                 return 0;
2250         case MONO_TYPE_PTR:
2251                 /* STACK_MP is needed when setting pinned locals */
2252                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2253                         return 1;
2254                 return 0;
2255         case MONO_TYPE_I:
2256         case MONO_TYPE_U:
2257         case MONO_TYPE_FNPTR:
2258                 /* 
2259                  * Some opcodes like ldloca returns 'transient pointers' which can be stored in
2260                  * in native int. (#688008).
2261                  */
2262                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2263                         return 1;
2264                 return 0;
2265         case MONO_TYPE_CLASS:
2266         case MONO_TYPE_STRING:
2267         case MONO_TYPE_OBJECT:
2268         case MONO_TYPE_SZARRAY:
2269         case MONO_TYPE_ARRAY:    
2270                 if (arg->type != STACK_OBJ)
2271                         return 1;
2272                 /* FIXME: check type compatibility */
2273                 return 0;
2274         case MONO_TYPE_I8:
2275         case MONO_TYPE_U8:
2276                 if (arg->type != STACK_I8)
2277                         return 1;
2278                 return 0;
2279         case MONO_TYPE_R4:
2280                 if (arg->type != cfg->r4_stack_type)
2281                         return 1;
2282                 return 0;
2283         case MONO_TYPE_R8:
2284                 if (arg->type != STACK_R8)
2285                         return 1;
2286                 return 0;
2287         case MONO_TYPE_VALUETYPE:
2288                 if (arg->type != STACK_VTYPE)
2289                         return 1;
2290                 klass = mono_class_from_mono_type (simple_type);
2291                 if (klass != arg->klass)
2292                         return 1;
2293                 return 0;
2294         case MONO_TYPE_TYPEDBYREF:
2295                 if (arg->type != STACK_VTYPE)
2296                         return 1;
2297                 klass = mono_class_from_mono_type (simple_type);
2298                 if (klass != arg->klass)
2299                         return 1;
2300                 return 0;
2301         case MONO_TYPE_GENERICINST:
2302                 if (mono_type_generic_inst_is_valuetype (simple_type)) {
2303                         MonoClass *target_class;
2304                         if (arg->type != STACK_VTYPE)
2305                                 return 1;
2306                         klass = mono_class_from_mono_type (simple_type);
2307                         target_class = mono_class_from_mono_type (target);
2308                         /* The second cases is needed when doing partial sharing */
2309                         if (klass != arg->klass && target_class != arg->klass && target_class != mono_class_from_mono_type (mini_get_underlying_type (&arg->klass->byval_arg)))
2310                                 return 1;
2311                         return 0;
2312                 } else {
2313                         if (arg->type != STACK_OBJ)
2314                                 return 1;
2315                         /* FIXME: check type compatibility */
2316                         return 0;
2317                 }
2318         case MONO_TYPE_VAR:
2319         case MONO_TYPE_MVAR:
2320                 g_assert (cfg->gshared);
2321                 if (mini_type_var_is_vt (simple_type)) {
2322                         if (arg->type != STACK_VTYPE)
2323                                 return 1;
2324                 } else {
2325                         if (arg->type != STACK_OBJ)
2326                                 return 1;
2327                 }
2328                 return 0;
2329         default:
2330                 g_error ("unknown type 0x%02x in target_type_is_incompatible", simple_type->type);
2331         }
2332         return 1;
2333 }
2334
2335 /*
2336  * Prepare arguments for passing to a function call.
2337  * Return a non-zero value if the arguments can't be passed to the given
2338  * signature.
2339  * The type checks are not yet complete and some conversions may need
2340  * casts on 32 or 64 bit architectures.
2341  *
2342  * FIXME: implement this using target_type_is_incompatible ()
2343  */
2344 static int
2345 check_call_signature (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args)
2346 {
2347         MonoType *simple_type;
2348         int i;
2349
2350         if (sig->hasthis) {
2351                 if (args [0]->type != STACK_OBJ && args [0]->type != STACK_MP && args [0]->type != STACK_PTR)
2352                         return 1;
2353                 args++;
2354         }
2355         for (i = 0; i < sig->param_count; ++i) {
2356                 if (sig->params [i]->byref) {
2357                         if (args [i]->type != STACK_MP && args [i]->type != STACK_PTR)
2358                                 return 1;
2359                         continue;
2360                 }
2361                 simple_type = mini_get_underlying_type (sig->params [i]);
2362 handle_enum:
2363                 switch (simple_type->type) {
2364                 case MONO_TYPE_VOID:
2365                         return 1;
2366                         continue;
2367                 case MONO_TYPE_I1:
2368                 case MONO_TYPE_U1:
2369                 case MONO_TYPE_I2:
2370                 case MONO_TYPE_U2:
2371                 case MONO_TYPE_I4:
2372                 case MONO_TYPE_U4:
2373                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR)
2374                                 return 1;
2375                         continue;
2376                 case MONO_TYPE_I:
2377                 case MONO_TYPE_U:
2378                 case MONO_TYPE_PTR:
2379                 case MONO_TYPE_FNPTR:
2380                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR && args [i]->type != STACK_MP && args [i]->type != STACK_OBJ)
2381                                 return 1;
2382                         continue;
2383                 case MONO_TYPE_CLASS:
2384                 case MONO_TYPE_STRING:
2385                 case MONO_TYPE_OBJECT:
2386                 case MONO_TYPE_SZARRAY:
2387                 case MONO_TYPE_ARRAY:    
2388                         if (args [i]->type != STACK_OBJ)
2389                                 return 1;
2390                         continue;
2391                 case MONO_TYPE_I8:
2392                 case MONO_TYPE_U8:
2393                         if (args [i]->type != STACK_I8)
2394                                 return 1;
2395                         continue;
2396                 case MONO_TYPE_R4:
2397                         if (args [i]->type != cfg->r4_stack_type)
2398                                 return 1;
2399                         continue;
2400                 case MONO_TYPE_R8:
2401                         if (args [i]->type != STACK_R8)
2402                                 return 1;
2403                         continue;
2404                 case MONO_TYPE_VALUETYPE:
2405                         if (simple_type->data.klass->enumtype) {
2406                                 simple_type = mono_class_enum_basetype (simple_type->data.klass);
2407                                 goto handle_enum;
2408                         }
2409                         if (args [i]->type != STACK_VTYPE)
2410                                 return 1;
2411                         continue;
2412                 case MONO_TYPE_TYPEDBYREF:
2413                         if (args [i]->type != STACK_VTYPE)
2414                                 return 1;
2415                         continue;
2416                 case MONO_TYPE_GENERICINST:
2417                         simple_type = &simple_type->data.generic_class->container_class->byval_arg;
2418                         goto handle_enum;
2419                 case MONO_TYPE_VAR:
2420                 case MONO_TYPE_MVAR:
2421                         /* gsharedvt */
2422                         if (args [i]->type != STACK_VTYPE)
2423                                 return 1;
2424                         continue;
2425                 default:
2426                         g_error ("unknown type 0x%02x in check_call_signature",
2427                                  simple_type->type);
2428                 }
2429         }
2430         return 0;
2431 }
2432
2433 static int
2434 callvirt_to_call (int opcode)
2435 {
2436         switch (opcode) {
2437         case OP_CALL_MEMBASE:
2438                 return OP_CALL;
2439         case OP_VOIDCALL_MEMBASE:
2440                 return OP_VOIDCALL;
2441         case OP_FCALL_MEMBASE:
2442                 return OP_FCALL;
2443         case OP_RCALL_MEMBASE:
2444                 return OP_RCALL;
2445         case OP_VCALL_MEMBASE:
2446                 return OP_VCALL;
2447         case OP_LCALL_MEMBASE:
2448                 return OP_LCALL;
2449         default:
2450                 g_assert_not_reached ();
2451         }
2452
2453         return -1;
2454 }
2455
2456 static int
2457 callvirt_to_call_reg (int opcode)
2458 {
2459         switch (opcode) {
2460         case OP_CALL_MEMBASE:
2461                 return OP_CALL_REG;
2462         case OP_VOIDCALL_MEMBASE:
2463                 return OP_VOIDCALL_REG;
2464         case OP_FCALL_MEMBASE:
2465                 return OP_FCALL_REG;
2466         case OP_RCALL_MEMBASE:
2467                 return OP_RCALL_REG;
2468         case OP_VCALL_MEMBASE:
2469                 return OP_VCALL_REG;
2470         case OP_LCALL_MEMBASE:
2471                 return OP_LCALL_REG;
2472         default:
2473                 g_assert_not_reached ();
2474         }
2475
2476         return -1;
2477 }
2478
2479 /* Either METHOD or IMT_ARG needs to be set */
2480 static void
2481 emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoMethod *method, MonoInst *imt_arg)
2482 {
2483         int method_reg;
2484
2485         if (COMPILE_LLVM (cfg)) {
2486                 if (imt_arg) {
2487                         method_reg = alloc_preg (cfg);
2488                         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2489                 } else {
2490                         MonoInst *ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_METHODCONST, method);
2491                         method_reg = ins->dreg;
2492                 }
2493
2494 #ifdef ENABLE_LLVM
2495                 call->imt_arg_reg = method_reg;
2496 #endif
2497                 mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2498                 return;
2499         }
2500
2501         if (imt_arg) {
2502                 method_reg = alloc_preg (cfg);
2503                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2504         } else {
2505                 MonoInst *ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_METHODCONST, method);
2506                 method_reg = ins->dreg;
2507         }
2508
2509         mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2510 }
2511
2512 static MonoJumpInfo *
2513 mono_patch_info_new (MonoMemPool *mp, int ip, MonoJumpInfoType type, gconstpointer target)
2514 {
2515         MonoJumpInfo *ji = (MonoJumpInfo *)mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
2516
2517         ji->ip.i = ip;
2518         ji->type = type;
2519         ji->data.target = target;
2520
2521         return ji;
2522 }
2523
2524 static int
2525 mini_class_check_context_used (MonoCompile *cfg, MonoClass *klass)
2526 {
2527         if (cfg->gshared)
2528                 return mono_class_check_context_used (klass);
2529         else
2530                 return 0;
2531 }
2532
2533 static int
2534 mini_method_check_context_used (MonoCompile *cfg, MonoMethod *method)
2535 {
2536         if (cfg->gshared)
2537                 return mono_method_check_context_used (method);
2538         else
2539                 return 0;
2540 }
2541
2542 /*
2543  * check_method_sharing:
2544  *
2545  *   Check whenever the vtable or an mrgctx needs to be passed when calling CMETHOD.
2546  */
2547 static void
2548 check_method_sharing (MonoCompile *cfg, MonoMethod *cmethod, gboolean *out_pass_vtable, gboolean *out_pass_mrgctx)
2549 {
2550         gboolean pass_vtable = FALSE;
2551         gboolean pass_mrgctx = FALSE;
2552
2553         if (((cmethod->flags & METHOD_ATTRIBUTE_STATIC) || cmethod->klass->valuetype) &&
2554                 (cmethod->klass->generic_class || cmethod->klass->generic_container)) {
2555                 gboolean sharable = FALSE;
2556
2557                 if (mono_method_is_generic_sharable_full (cmethod, TRUE, TRUE, TRUE))
2558                         sharable = TRUE;
2559
2560                 /*
2561                  * Pass vtable iff target method might
2562                  * be shared, which means that sharing
2563                  * is enabled for its class and its
2564                  * context is sharable (and it's not a
2565                  * generic method).
2566                  */
2567                 if (sharable && !(mini_method_get_context (cmethod) && mini_method_get_context (cmethod)->method_inst))
2568                         pass_vtable = TRUE;
2569         }
2570
2571         if (mini_method_get_context (cmethod) &&
2572                 mini_method_get_context (cmethod)->method_inst) {
2573                 g_assert (!pass_vtable);
2574
2575                 if (mono_method_is_generic_sharable_full (cmethod, TRUE, TRUE, TRUE)) {
2576                         pass_mrgctx = TRUE;
2577                 } else {
2578                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (mono_method_signature (cmethod)))
2579                                 pass_mrgctx = TRUE;
2580                 }
2581         }
2582
2583         if (out_pass_vtable)
2584                 *out_pass_vtable = pass_vtable;
2585         if (out_pass_mrgctx)
2586                 *out_pass_mrgctx = pass_mrgctx;
2587 }
2588
2589 inline static MonoCallInst *
2590 mono_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig, 
2591                                          MonoInst **args, int calli, int virtual_, int tail, int rgctx, int unbox_trampoline)
2592 {
2593         MonoType *sig_ret;
2594         MonoCallInst *call;
2595 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2596         int i;
2597 #endif
2598
2599         if (cfg->llvm_only)
2600                 tail = FALSE;
2601
2602         if (tail) {
2603                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
2604
2605                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
2606         } else
2607                 MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (cfg, sig->ret, calli, virtual_));
2608
2609         call->args = args;
2610         call->signature = sig;
2611         call->rgctx_reg = rgctx;
2612         sig_ret = mini_get_underlying_type (sig->ret);
2613
2614         type_to_eval_stack_type ((cfg), sig_ret, &call->inst);
2615
2616         if (tail) {
2617                 if (mini_type_is_vtype (sig_ret)) {
2618                         call->vret_var = cfg->vret_addr;
2619                         //g_assert_not_reached ();
2620                 }
2621         } else if (mini_type_is_vtype (sig_ret)) {
2622                 MonoInst *temp = mono_compile_create_var (cfg, sig_ret, OP_LOCAL);
2623                 MonoInst *loada;
2624
2625                 temp->backend.is_pinvoke = sig->pinvoke;
2626
2627                 /*
2628                  * We use a new opcode OP_OUTARG_VTRETADDR instead of LDADDR for emitting the
2629                  * address of return value to increase optimization opportunities.
2630                  * Before vtype decomposition, the dreg of the call ins itself represents the
2631                  * fact the call modifies the return value. After decomposition, the call will
2632                  * be transformed into one of the OP_VOIDCALL opcodes, and the VTRETADDR opcode
2633                  * will be transformed into an LDADDR.
2634                  */
2635                 MONO_INST_NEW (cfg, loada, OP_OUTARG_VTRETADDR);
2636                 loada->dreg = alloc_preg (cfg);
2637                 loada->inst_p0 = temp;
2638                 /* We reference the call too since call->dreg could change during optimization */
2639                 loada->inst_p1 = call;
2640                 MONO_ADD_INS (cfg->cbb, loada);
2641
2642                 call->inst.dreg = temp->dreg;
2643
2644                 call->vret_var = loada;
2645         } else if (!MONO_TYPE_IS_VOID (sig_ret))
2646                 call->inst.dreg = alloc_dreg (cfg, (MonoStackType)call->inst.type);
2647
2648 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2649         if (COMPILE_SOFT_FLOAT (cfg)) {
2650                 /* 
2651                  * If the call has a float argument, we would need to do an r8->r4 conversion using 
2652                  * an icall, but that cannot be done during the call sequence since it would clobber
2653                  * the call registers + the stack. So we do it before emitting the call.
2654                  */
2655                 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2656                         MonoType *t;
2657                         MonoInst *in = call->args [i];
2658
2659                         if (i >= sig->hasthis)
2660                                 t = sig->params [i - sig->hasthis];
2661                         else
2662                                 t = &mono_defaults.int_class->byval_arg;
2663                         t = mono_type_get_underlying_type (t);
2664
2665                         if (!t->byref && t->type == MONO_TYPE_R4) {
2666                                 MonoInst *iargs [1];
2667                                 MonoInst *conv;
2668
2669                                 iargs [0] = in;
2670                                 conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
2671
2672                                 /* The result will be in an int vreg */
2673                                 call->args [i] = conv;
2674                         }
2675                 }
2676         }
2677 #endif
2678
2679         call->need_unbox_trampoline = unbox_trampoline;
2680
2681 #ifdef ENABLE_LLVM
2682         if (COMPILE_LLVM (cfg))
2683                 mono_llvm_emit_call (cfg, call);
2684         else
2685                 mono_arch_emit_call (cfg, call);
2686 #else
2687         mono_arch_emit_call (cfg, call);
2688 #endif
2689
2690         cfg->param_area = MAX (cfg->param_area, call->stack_usage);
2691         cfg->flags |= MONO_CFG_HAS_CALLS;
2692         
2693         return call;
2694 }
2695
2696 static void
2697 set_rgctx_arg (MonoCompile *cfg, MonoCallInst *call, int rgctx_reg, MonoInst *rgctx_arg)
2698 {
2699         mono_call_inst_add_outarg_reg (cfg, call, rgctx_reg, MONO_ARCH_RGCTX_REG, FALSE);
2700         cfg->uses_rgctx_reg = TRUE;
2701         call->rgctx_reg = TRUE;
2702 #ifdef ENABLE_LLVM
2703         call->rgctx_arg_reg = rgctx_reg;
2704 #endif
2705 }       
2706
2707 inline static MonoInst*
2708 mono_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr, MonoInst *imt_arg, MonoInst *rgctx_arg)
2709 {
2710         MonoCallInst *call;
2711         MonoInst *ins;
2712         int rgctx_reg = -1;
2713         gboolean check_sp = FALSE;
2714
2715         if (cfg->check_pinvoke_callconv && cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
2716                 WrapperInfo *info = mono_marshal_get_wrapper_info (cfg->method);
2717
2718                 if (info && info->subtype == WRAPPER_SUBTYPE_PINVOKE)
2719                         check_sp = TRUE;
2720         }
2721
2722         if (rgctx_arg) {
2723                 rgctx_reg = mono_alloc_preg (cfg);
2724                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2725         }
2726
2727         if (check_sp) {
2728                 if (!cfg->stack_inbalance_var)
2729                         cfg->stack_inbalance_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2730
2731                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2732                 ins->dreg = cfg->stack_inbalance_var->dreg;
2733                 MONO_ADD_INS (cfg->cbb, ins);
2734         }
2735
2736         call = mono_emit_call_args (cfg, sig, args, TRUE, FALSE, FALSE, rgctx_arg ? TRUE : FALSE, FALSE);
2737
2738         call->inst.sreg1 = addr->dreg;
2739
2740         if (imt_arg)
2741                 emit_imt_argument (cfg, call, NULL, imt_arg);
2742
2743         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2744
2745         if (check_sp) {
2746                 int sp_reg;
2747
2748                 sp_reg = mono_alloc_preg (cfg);
2749
2750                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2751                 ins->dreg = sp_reg;
2752                 MONO_ADD_INS (cfg->cbb, ins);
2753
2754                 /* Restore the stack so we don't crash when throwing the exception */
2755                 MONO_INST_NEW (cfg, ins, OP_SET_SP);
2756                 ins->sreg1 = cfg->stack_inbalance_var->dreg;
2757                 MONO_ADD_INS (cfg->cbb, ins);
2758
2759                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, cfg->stack_inbalance_var->dreg, sp_reg);
2760                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ExecutionEngineException");
2761         }
2762
2763         if (rgctx_arg)
2764                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2765
2766         return (MonoInst*)call;
2767 }
2768
2769 static MonoInst*
2770 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2771
2772 static MonoInst*
2773 emit_get_rgctx_method (MonoCompile *cfg, int context_used, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type);
2774 static MonoInst*
2775 emit_get_rgctx_klass (MonoCompile *cfg, int context_used, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2776
2777 static MonoInst*
2778 mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSignature *sig, gboolean tail,
2779                                                         MonoInst **args, MonoInst *this_ins, MonoInst *imt_arg, MonoInst *rgctx_arg)
2780 {
2781 #ifndef DISABLE_REMOTING
2782         gboolean might_be_remote = FALSE;
2783 #endif
2784         gboolean virtual_ = this_ins != NULL;
2785         gboolean enable_for_aot = TRUE;
2786         int context_used;
2787         MonoCallInst *call;
2788         MonoInst *call_target = NULL;
2789         int rgctx_reg = 0;
2790         gboolean need_unbox_trampoline;
2791
2792         if (!sig)
2793                 sig = mono_method_signature (method);
2794
2795         if (cfg->llvm_only && (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE))
2796                 g_assert_not_reached ();
2797
2798         if (rgctx_arg) {
2799                 rgctx_reg = mono_alloc_preg (cfg);
2800                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2801         }
2802
2803         if (method->string_ctor) {
2804                 /* Create the real signature */
2805                 /* FIXME: Cache these */
2806                 MonoMethodSignature *ctor_sig = mono_metadata_signature_dup_mempool (cfg->mempool, sig);
2807                 ctor_sig->ret = &mono_defaults.string_class->byval_arg;
2808
2809                 sig = ctor_sig;
2810         }
2811
2812         context_used = mini_method_check_context_used (cfg, method);
2813
2814 #ifndef DISABLE_REMOTING
2815         might_be_remote = this_ins && sig->hasthis &&
2816                 (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) &&
2817                 !(method->flags & METHOD_ATTRIBUTE_VIRTUAL) && (!MONO_CHECK_THIS (this_ins) || context_used);
2818
2819         if (might_be_remote && context_used) {
2820                 MonoInst *addr;
2821
2822                 g_assert (cfg->gshared);
2823
2824                 addr = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK);
2825
2826                 return mono_emit_calli (cfg, sig, args, addr, NULL, NULL);
2827         }
2828 #endif
2829
2830         if (cfg->llvm_only && !call_target && virtual_ && (method->flags & METHOD_ATTRIBUTE_VIRTUAL))
2831                 return emit_llvmonly_virtual_call (cfg, method, sig, 0, args);
2832
2833         need_unbox_trampoline = method->klass == mono_defaults.object_class || (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE);
2834
2835         call = mono_emit_call_args (cfg, sig, args, FALSE, virtual_, tail, rgctx_arg ? TRUE : FALSE, need_unbox_trampoline);
2836
2837 #ifndef DISABLE_REMOTING
2838         if (might_be_remote)
2839                 call->method = mono_marshal_get_remoting_invoke_with_check (method);
2840         else
2841 #endif
2842                 call->method = method;
2843         call->inst.flags |= MONO_INST_HAS_METHOD;
2844         call->inst.inst_left = this_ins;
2845         call->tail_call = tail;
2846
2847         if (virtual_) {
2848                 int vtable_reg, slot_reg, this_reg;
2849                 int offset;
2850
2851                 this_reg = this_ins->dreg;
2852
2853                 if (!cfg->llvm_only && (method->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (method->name, "Invoke")) {
2854                         MonoInst *dummy_use;
2855
2856                         MONO_EMIT_NULL_CHECK (cfg, this_reg);
2857
2858                         /* Make a call to delegate->invoke_impl */
2859                         call->inst.inst_basereg = this_reg;
2860                         call->inst.inst_offset = MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl);
2861                         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2862
2863                         /* We must emit a dummy use here because the delegate trampoline will
2864                         replace the 'this' argument with the delegate target making this activation
2865                         no longer a root for the delegate.
2866                         This is an issue for delegates that target collectible code such as dynamic
2867                         methods of GC'able assemblies.
2868
2869                         For a test case look into #667921.
2870
2871                         FIXME: a dummy use is not the best way to do it as the local register allocator
2872                         will put it on a caller save register and spil it around the call. 
2873                         Ideally, we would either put it on a callee save register or only do the store part.  
2874                          */
2875                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, args [0]);
2876
2877                         return (MonoInst*)call;
2878                 }
2879
2880                 if ((!cfg->compile_aot || enable_for_aot) && 
2881                         (!(method->flags & METHOD_ATTRIBUTE_VIRTUAL) || 
2882                          (MONO_METHOD_IS_FINAL (method) &&
2883                           method->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)) &&
2884                         !(mono_class_is_marshalbyref (method->klass) && context_used)) {
2885                         /* 
2886                          * the method is not virtual, we just need to ensure this is not null
2887                          * and then we can call the method directly.
2888                          */
2889 #ifndef DISABLE_REMOTING
2890                         if (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) {
2891                                 /* 
2892                                  * The check above ensures method is not gshared, this is needed since
2893                                  * gshared methods can't have wrappers.
2894                                  */
2895                                 method = call->method = mono_marshal_get_remoting_invoke_with_check (method);
2896                         }
2897 #endif
2898
2899                         if (!method->string_ctor)
2900                                 MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2901
2902                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2903                 } else if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && MONO_METHOD_IS_FINAL (method)) {
2904                         /*
2905                          * the method is virtual, but we can statically dispatch since either
2906                          * it's class or the method itself are sealed.
2907                          * But first we need to ensure it's not a null reference.
2908                          */
2909                         MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2910
2911                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2912                 } else if (call_target) {
2913                         vtable_reg = alloc_preg (cfg);
2914                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
2915
2916                         call->inst.opcode = callvirt_to_call_reg (call->inst.opcode);
2917                         call->inst.sreg1 = call_target->dreg;
2918                         call->inst.flags &= !MONO_INST_HAS_METHOD;
2919                 } else {
2920                         vtable_reg = alloc_preg (cfg);
2921                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
2922                         if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2923                                 guint32 imt_slot = mono_method_get_imt_slot (method);
2924                                 emit_imt_argument (cfg, call, call->method, imt_arg);
2925                                 slot_reg = vtable_reg;
2926                                 offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
2927                         } else {
2928                                 slot_reg = vtable_reg;
2929                                 offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) +
2930                                         ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
2931                                 if (imt_arg) {
2932                                         g_assert (mono_method_signature (method)->generic_param_count);
2933                                         emit_imt_argument (cfg, call, call->method, imt_arg);
2934                                 }
2935                         }
2936
2937                         call->inst.sreg1 = slot_reg;
2938                         call->inst.inst_offset = offset;
2939                         call->is_virtual = TRUE;
2940                 }
2941         }
2942
2943         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2944
2945         if (rgctx_arg)
2946                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2947
2948         return (MonoInst*)call;
2949 }
2950
2951 MonoInst*
2952 mono_emit_method_call (MonoCompile *cfg, MonoMethod *method, MonoInst **args, MonoInst *this_ins)
2953 {
2954         return mono_emit_method_call_full (cfg, method, mono_method_signature (method), FALSE, args, this_ins, NULL, NULL);
2955 }
2956
2957 MonoInst*
2958 mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig,
2959                                            MonoInst **args)
2960 {
2961         MonoCallInst *call;
2962
2963         g_assert (sig);
2964
2965         call = mono_emit_call_args (cfg, sig, args, FALSE, FALSE, FALSE, FALSE, FALSE);
2966         call->fptr = func;
2967
2968         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2969
2970         return (MonoInst*)call;
2971 }
2972
2973 MonoInst*
2974 mono_emit_jit_icall (MonoCompile *cfg, gconstpointer func, MonoInst **args)
2975 {
2976         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (func);
2977
2978         g_assert (info);
2979
2980         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
2981 }
2982
2983 /*
2984  * mono_emit_abs_call:
2985  *
2986  *   Emit a call to the runtime function described by PATCH_TYPE and DATA.
2987  */
2988 inline static MonoInst*
2989 mono_emit_abs_call (MonoCompile *cfg, MonoJumpInfoType patch_type, gconstpointer data, 
2990                                         MonoMethodSignature *sig, MonoInst **args)
2991 {
2992         MonoJumpInfo *ji = mono_patch_info_new (cfg->mempool, 0, patch_type, data);
2993         MonoInst *ins;
2994
2995         /* 
2996          * We pass ji as the call address, the PATCH_INFO_ABS resolving code will
2997          * handle it.
2998          */
2999         if (cfg->abs_patches == NULL)
3000                 cfg->abs_patches = g_hash_table_new (NULL, NULL);
3001         g_hash_table_insert (cfg->abs_patches, ji, ji);
3002         ins = mono_emit_native_call (cfg, ji, sig, args);
3003         ((MonoCallInst*)ins)->fptr_is_patch = TRUE;
3004         return ins;
3005 }
3006
3007 static MonoMethodSignature*
3008 sig_to_rgctx_sig (MonoMethodSignature *sig)
3009 {
3010         // FIXME: memory allocation
3011         MonoMethodSignature *res;
3012         int i;
3013
3014         res = (MonoMethodSignature *)g_malloc (MONO_SIZEOF_METHOD_SIGNATURE + (sig->param_count + 1) * sizeof (MonoType*));
3015         memcpy (res, sig, MONO_SIZEOF_METHOD_SIGNATURE);
3016         res->param_count = sig->param_count + 1;
3017         for (i = 0; i < sig->param_count; ++i)
3018                 res->params [i] = sig->params [i];
3019         res->params [sig->param_count] = &mono_defaults.int_class->this_arg;
3020         return res;
3021 }
3022
3023 /* Make an indirect call to FSIG passing an additional argument */
3024 static MonoInst*
3025 emit_extra_arg_calli (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **orig_args, int arg_reg, MonoInst *call_target)
3026 {
3027         MonoMethodSignature *csig;
3028         MonoInst *args_buf [16];
3029         MonoInst **args;
3030         int i, pindex, tmp_reg;
3031
3032         /* Make a call with an rgctx/extra arg */
3033         if (fsig->param_count + 2 < 16)
3034                 args = args_buf;
3035         else
3036                 args = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (fsig->param_count + 2));
3037         pindex = 0;
3038         if (fsig->hasthis)
3039                 args [pindex ++] = orig_args [0];
3040         for (i = 0; i < fsig->param_count; ++i)
3041                 args [pindex ++] = orig_args [fsig->hasthis + i];
3042         tmp_reg = alloc_preg (cfg);
3043         EMIT_NEW_UNALU (cfg, args [pindex], OP_MOVE, tmp_reg, arg_reg);
3044         csig = sig_to_rgctx_sig (fsig);
3045         return mono_emit_calli (cfg, csig, args, call_target, NULL, NULL);
3046 }
3047
3048 /* Emit an indirect call to the function descriptor ADDR */
3049 static MonoInst*
3050 emit_llvmonly_calli (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, MonoInst *addr)
3051 {
3052         int addr_reg, arg_reg;
3053         MonoInst *call_target;
3054
3055         g_assert (cfg->llvm_only);
3056
3057         /*
3058          * addr points to a <addr, arg> pair, load both of them, and
3059          * make a call to addr, passing arg as an extra arg.
3060          */
3061         addr_reg = alloc_preg (cfg);
3062         EMIT_NEW_LOAD_MEMBASE (cfg, call_target, OP_LOAD_MEMBASE, addr_reg, addr->dreg, 0);
3063         arg_reg = alloc_preg (cfg);
3064         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, arg_reg, addr->dreg, sizeof (gpointer));
3065
3066         return emit_extra_arg_calli (cfg, fsig, args, arg_reg, call_target);
3067 }
3068
3069 static gboolean
3070 direct_icalls_enabled (MonoCompile *cfg)
3071 {
3072         /* LLVM on amd64 can't handle calls to non-32 bit addresses */
3073 #ifdef TARGET_AMD64
3074         if (cfg->compile_llvm && !cfg->llvm_only)
3075                 return FALSE;
3076 #endif
3077         if (cfg->gen_sdb_seq_points || cfg->disable_direct_icalls)
3078                 return FALSE;
3079         return TRUE;
3080 }
3081
3082 MonoInst*
3083 mono_emit_jit_icall_by_info (MonoCompile *cfg, int il_offset, MonoJitICallInfo *info, MonoInst **args)
3084 {
3085         /*
3086          * Call the jit icall without a wrapper if possible.
3087          * The wrapper is needed for the following reasons:
3088          * - to handle exceptions thrown using mono_raise_exceptions () from the
3089          *   icall function. The EH code needs the lmf frame pushed by the
3090          *   wrapper to be able to unwind back to managed code.
3091          * - to be able to do stack walks for asynchronously suspended
3092          *   threads when debugging.
3093          */
3094         if (info->no_raise && direct_icalls_enabled (cfg)) {
3095                 char *name;
3096                 int costs;
3097
3098                 if (!info->wrapper_method) {
3099                         name = g_strdup_printf ("__icall_wrapper_%s", info->name);
3100                         info->wrapper_method = mono_marshal_get_icall_wrapper (info->sig, name, info->func, TRUE);
3101                         g_free (name);
3102                         mono_memory_barrier ();
3103                 }
3104
3105                 /*
3106                  * Inline the wrapper method, which is basically a call to the C icall, and
3107                  * an exception check.
3108                  */
3109                 costs = inline_method (cfg, info->wrapper_method, NULL,
3110                                                            args, NULL, il_offset, TRUE);
3111                 g_assert (costs > 0);
3112                 g_assert (!MONO_TYPE_IS_VOID (info->sig->ret));
3113
3114                 return args [0];
3115         } else {
3116                 return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
3117         }
3118 }
3119  
3120 static MonoInst*
3121 mono_emit_widen_call_res (MonoCompile *cfg, MonoInst *ins, MonoMethodSignature *fsig)
3122 {
3123         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
3124                 if ((fsig->pinvoke || LLVM_ENABLED) && !fsig->ret->byref) {
3125                         int widen_op = -1;
3126
3127                         /* 
3128                          * Native code might return non register sized integers 
3129                          * without initializing the upper bits.
3130                          */
3131                         switch (mono_type_to_load_membase (cfg, fsig->ret)) {
3132                         case OP_LOADI1_MEMBASE:
3133                                 widen_op = OP_ICONV_TO_I1;
3134                                 break;
3135                         case OP_LOADU1_MEMBASE:
3136                                 widen_op = OP_ICONV_TO_U1;
3137                                 break;
3138                         case OP_LOADI2_MEMBASE:
3139                                 widen_op = OP_ICONV_TO_I2;
3140                                 break;
3141                         case OP_LOADU2_MEMBASE:
3142                                 widen_op = OP_ICONV_TO_U2;
3143                                 break;
3144                         default:
3145                                 break;
3146                         }
3147
3148                         if (widen_op != -1) {
3149                                 int dreg = alloc_preg (cfg);
3150                                 MonoInst *widen;
3151
3152                                 EMIT_NEW_UNALU (cfg, widen, widen_op, dreg, ins->dreg);
3153                                 widen->type = ins->type;
3154                                 ins = widen;
3155                         }
3156                 }
3157         }
3158
3159         return ins;
3160 }
3161
3162
3163 static void
3164 emit_method_access_failure (MonoCompile *cfg, MonoMethod *method, MonoMethod *cil_method)
3165 {
3166         MonoInst *args [16];
3167
3168         args [0] = emit_get_rgctx_method (cfg, mono_method_check_context_used (method), method, MONO_RGCTX_INFO_METHOD);
3169         args [1] = emit_get_rgctx_method (cfg, mono_method_check_context_used (cil_method), cil_method, MONO_RGCTX_INFO_METHOD);
3170
3171         mono_emit_jit_icall (cfg, mono_throw_method_access, args);
3172 }
3173
3174 static MonoMethod*
3175 get_memcpy_method (void)
3176 {
3177         static MonoMethod *memcpy_method = NULL;
3178         if (!memcpy_method) {
3179                 memcpy_method = mono_class_get_method_from_name (mono_defaults.string_class, "memcpy", 3);
3180                 if (!memcpy_method)
3181                         g_error ("Old corlib found. Install a new one");
3182         }
3183         return memcpy_method;
3184 }
3185
3186 static void
3187 create_write_barrier_bitmap (MonoCompile *cfg, MonoClass *klass, unsigned *wb_bitmap, int offset)
3188 {
3189         MonoClassField *field;
3190         gpointer iter = NULL;
3191
3192         while ((field = mono_class_get_fields (klass, &iter))) {
3193                 int foffset;
3194
3195                 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
3196                         continue;
3197                 foffset = klass->valuetype ? field->offset - sizeof (MonoObject): field->offset;
3198                 if (mini_type_is_reference (mono_field_get_type (field))) {
3199                         g_assert ((foffset % SIZEOF_VOID_P) == 0);
3200                         *wb_bitmap |= 1 << ((offset + foffset) / SIZEOF_VOID_P);
3201                 } else {
3202                         MonoClass *field_class = mono_class_from_mono_type (field->type);
3203                         if (field_class->has_references)
3204                                 create_write_barrier_bitmap (cfg, field_class, wb_bitmap, offset + foffset);
3205                 }
3206         }
3207 }
3208
3209 static void
3210 emit_write_barrier (MonoCompile *cfg, MonoInst *ptr, MonoInst *value)
3211 {
3212         int card_table_shift_bits;
3213         gpointer card_table_mask;
3214         guint8 *card_table;
3215         MonoInst *dummy_use;
3216         int nursery_shift_bits;
3217         size_t nursery_size;
3218
3219         if (!cfg->gen_write_barriers)
3220                 return;
3221
3222         card_table = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
3223
3224         mono_gc_get_nursery (&nursery_shift_bits, &nursery_size);
3225
3226         if (cfg->backend->have_card_table_wb && !cfg->compile_aot && card_table && nursery_shift_bits > 0 && !COMPILE_LLVM (cfg)) {
3227                 MonoInst *wbarrier;
3228
3229                 MONO_INST_NEW (cfg, wbarrier, OP_CARD_TABLE_WBARRIER);
3230                 wbarrier->sreg1 = ptr->dreg;
3231                 wbarrier->sreg2 = value->dreg;
3232                 MONO_ADD_INS (cfg->cbb, wbarrier);
3233         } else if (card_table && !cfg->compile_aot && !mono_gc_card_table_nursery_check ()) {
3234                 int offset_reg = alloc_preg (cfg);
3235                 int card_reg;
3236                 MonoInst *ins;
3237
3238                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, offset_reg, ptr->dreg, card_table_shift_bits);
3239                 if (card_table_mask)
3240                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, offset_reg, offset_reg, card_table_mask);
3241
3242                 /*We can't use PADD_IMM since the cardtable might end up in high addresses and amd64 doesn't support
3243                  * IMM's larger than 32bits.
3244                  */
3245                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR, NULL);
3246                 card_reg = ins->dreg;
3247
3248                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, offset_reg, offset_reg, card_reg);
3249                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, offset_reg, 0, 1);
3250         } else {
3251                 MonoMethod *write_barrier = mono_gc_get_write_barrier ();
3252                 mono_emit_method_call (cfg, write_barrier, &ptr, NULL);
3253         }
3254
3255         EMIT_NEW_DUMMY_USE (cfg, dummy_use, value);
3256 }
3257
3258 static gboolean
3259 mono_emit_wb_aware_memcpy (MonoCompile *cfg, MonoClass *klass, MonoInst *iargs[4], int size, int align)
3260 {
3261         int dest_ptr_reg, tmp_reg, destreg, srcreg, offset;
3262         unsigned need_wb = 0;
3263
3264         if (align == 0)
3265                 align = 4;
3266
3267         /*types with references can't have alignment smaller than sizeof(void*) */
3268         if (align < SIZEOF_VOID_P)
3269                 return FALSE;
3270
3271         /*This value cannot be bigger than 32 due to the way we calculate the required wb bitmap.*/
3272         if (size > 32 * SIZEOF_VOID_P)
3273                 return FALSE;
3274
3275         create_write_barrier_bitmap (cfg, klass, &need_wb, 0);
3276
3277         /* We don't unroll more than 5 stores to avoid code bloat. */
3278         if (size > 5 * SIZEOF_VOID_P) {
3279                 /*This is harmless and simplify mono_gc_wbarrier_value_copy_bitmap */
3280                 size += (SIZEOF_VOID_P - 1);
3281                 size &= ~(SIZEOF_VOID_P - 1);
3282
3283                 EMIT_NEW_ICONST (cfg, iargs [2], size);
3284                 EMIT_NEW_ICONST (cfg, iargs [3], need_wb);
3285                 mono_emit_jit_icall (cfg, mono_gc_wbarrier_value_copy_bitmap, iargs);
3286                 return TRUE;
3287         }
3288
3289         destreg = iargs [0]->dreg;
3290         srcreg = iargs [1]->dreg;
3291         offset = 0;
3292
3293         dest_ptr_reg = alloc_preg (cfg);
3294         tmp_reg = alloc_preg (cfg);
3295
3296         /*tmp = dreg*/
3297         EMIT_NEW_UNALU (cfg, iargs [0], OP_MOVE, dest_ptr_reg, destreg);
3298
3299         while (size >= SIZEOF_VOID_P) {
3300                 MonoInst *load_inst;
3301                 MONO_INST_NEW (cfg, load_inst, OP_LOAD_MEMBASE);
3302                 load_inst->dreg = tmp_reg;
3303                 load_inst->inst_basereg = srcreg;
3304                 load_inst->inst_offset = offset;
3305                 MONO_ADD_INS (cfg->cbb, load_inst);
3306
3307                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, dest_ptr_reg, 0, tmp_reg);
3308
3309                 if (need_wb & 0x1)
3310                         emit_write_barrier (cfg, iargs [0], load_inst);
3311
3312                 offset += SIZEOF_VOID_P;
3313                 size -= SIZEOF_VOID_P;
3314                 need_wb >>= 1;
3315
3316                 /*tmp += sizeof (void*)*/
3317                 if (size >= SIZEOF_VOID_P) {
3318                         NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, dest_ptr_reg, dest_ptr_reg, SIZEOF_VOID_P);
3319                         MONO_ADD_INS (cfg->cbb, iargs [0]);
3320                 }
3321         }
3322
3323         /* Those cannot be references since size < sizeof (void*) */
3324         while (size >= 4) {
3325                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tmp_reg, srcreg, offset);
3326                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, tmp_reg);
3327                 offset += 4;
3328                 size -= 4;
3329         }
3330
3331         while (size >= 2) {
3332                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmp_reg, srcreg, offset);
3333                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, tmp_reg);
3334                 offset += 2;
3335                 size -= 2;
3336         }
3337
3338         while (size >= 1) {
3339                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmp_reg, srcreg, offset);
3340                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, tmp_reg);
3341                 offset += 1;
3342                 size -= 1;
3343         }
3344
3345         return TRUE;
3346 }
3347
3348 /*
3349  * Emit code to copy a valuetype of type @klass whose address is stored in
3350  * @src->dreg to memory whose address is stored at @dest->dreg.
3351  */
3352 void
3353 mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native)
3354 {
3355         MonoInst *iargs [4];
3356         int n;
3357         guint32 align = 0;
3358         MonoMethod *memcpy_method;
3359         MonoInst *size_ins = NULL;
3360         MonoInst *memcpy_ins = NULL;
3361
3362         g_assert (klass);
3363         if (cfg->gshared)
3364                 klass = mono_class_from_mono_type (mini_get_underlying_type (&klass->byval_arg));
3365
3366         /*
3367          * This check breaks with spilled vars... need to handle it during verification anyway.
3368          * g_assert (klass && klass == src->klass && klass == dest->klass);
3369          */
3370
3371         if (mini_is_gsharedvt_klass (klass)) {
3372                 g_assert (!native);
3373                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3374                 memcpy_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_MEMCPY);
3375         }
3376
3377         if (native)
3378                 n = mono_class_native_size (klass, &align);
3379         else
3380                 n = mono_class_value_size (klass, &align);
3381
3382         /* if native is true there should be no references in the struct */
3383         if (cfg->gen_write_barriers && (klass->has_references || size_ins) && !native) {
3384                 /* Avoid barriers when storing to the stack */
3385                 if (!((dest->opcode == OP_ADD_IMM && dest->sreg1 == cfg->frame_reg) ||
3386                           (dest->opcode == OP_LDADDR))) {
3387                         int context_used;
3388
3389                         iargs [0] = dest;
3390                         iargs [1] = src;
3391
3392                         context_used = mini_class_check_context_used (cfg, klass);
3393
3394                         /* It's ok to intrinsify under gsharing since shared code types are layout stable. */
3395                         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && mono_emit_wb_aware_memcpy (cfg, klass, iargs, n, align)) {
3396                                 return;
3397                         } else if (context_used) {
3398                                 iargs [2] = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3399                         }  else {
3400                                 iargs [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, klass);
3401                                 if (!cfg->compile_aot)
3402                                         mono_class_compute_gc_descriptor (klass);
3403                         }
3404
3405                         if (size_ins)
3406                                 mono_emit_jit_icall (cfg, mono_gsharedvt_value_copy, iargs);
3407                         else
3408                                 mono_emit_jit_icall (cfg, mono_value_copy, iargs);
3409                         return;
3410                 }
3411         }
3412
3413         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 8) {
3414                 /* FIXME: Optimize the case when src/dest is OP_LDADDR */
3415                 mini_emit_memcpy (cfg, dest->dreg, 0, src->dreg, 0, n, align);
3416         } else {
3417                 iargs [0] = dest;
3418                 iargs [1] = src;
3419                 if (size_ins)
3420                         iargs [2] = size_ins;
3421                 else
3422                         EMIT_NEW_ICONST (cfg, iargs [2], n);
3423                 
3424                 memcpy_method = get_memcpy_method ();
3425                 if (memcpy_ins)
3426                         mono_emit_calli (cfg, mono_method_signature (memcpy_method), iargs, memcpy_ins, NULL, NULL);
3427                 else
3428                         mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
3429         }
3430 }
3431
3432 static MonoMethod*
3433 get_memset_method (void)
3434 {
3435         static MonoMethod *memset_method = NULL;
3436         if (!memset_method) {
3437                 memset_method = mono_class_get_method_from_name (mono_defaults.string_class, "memset", 3);
3438                 if (!memset_method)
3439                         g_error ("Old corlib found. Install a new one");
3440         }
3441         return memset_method;
3442 }
3443
3444 void
3445 mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass)
3446 {
3447         MonoInst *iargs [3];
3448         int n;
3449         guint32 align;
3450         MonoMethod *memset_method;
3451         MonoInst *size_ins = NULL;
3452         MonoInst *bzero_ins = NULL;
3453         static MonoMethod *bzero_method;
3454
3455         /* FIXME: Optimize this for the case when dest is an LDADDR */
3456         mono_class_init (klass);
3457         if (mini_is_gsharedvt_klass (klass)) {
3458                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3459                 bzero_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_BZERO);
3460                 if (!bzero_method)
3461                         bzero_method = mono_class_get_method_from_name (mono_defaults.string_class, "bzero_aligned_1", 2);
3462                 g_assert (bzero_method);
3463                 iargs [0] = dest;
3464                 iargs [1] = size_ins;
3465                 mono_emit_calli (cfg, mono_method_signature (bzero_method), iargs, bzero_ins, NULL, NULL);
3466                 return;
3467         }
3468
3469         klass = mono_class_from_mono_type (mini_get_underlying_type (&klass->byval_arg));
3470
3471         n = mono_class_value_size (klass, &align);
3472
3473         if (n <= sizeof (gpointer) * 8) {
3474                 mini_emit_memset (cfg, dest->dreg, 0, n, 0, align);
3475         }
3476         else {
3477                 memset_method = get_memset_method ();
3478                 iargs [0] = dest;
3479                 EMIT_NEW_ICONST (cfg, iargs [1], 0);
3480                 EMIT_NEW_ICONST (cfg, iargs [2], n);
3481                 mono_emit_method_call (cfg, memset_method, iargs, NULL);
3482         }
3483 }
3484
3485 /*
3486  * emit_get_rgctx:
3487  *
3488  *   Emit IR to return either the this pointer for instance method,
3489  * or the mrgctx for static methods.
3490  */
3491 static MonoInst*
3492 emit_get_rgctx (MonoCompile *cfg, MonoMethod *method, int context_used)
3493 {
3494         MonoInst *this_ins = NULL;
3495
3496         g_assert (cfg->gshared);
3497
3498         if (!(method->flags & METHOD_ATTRIBUTE_STATIC) &&
3499                         !(context_used & MONO_GENERIC_CONTEXT_USED_METHOD) &&
3500                         !method->klass->valuetype)
3501                 EMIT_NEW_ARGLOAD (cfg, this_ins, 0);
3502
3503         if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD) {
3504                 MonoInst *mrgctx_loc, *mrgctx_var;
3505
3506                 g_assert (!this_ins);
3507                 g_assert (method->is_inflated && mono_method_get_context (method)->method_inst);
3508
3509                 mrgctx_loc = mono_get_vtable_var (cfg);
3510                 EMIT_NEW_TEMPLOAD (cfg, mrgctx_var, mrgctx_loc->inst_c0);
3511
3512                 return mrgctx_var;
3513         } else if (method->flags & METHOD_ATTRIBUTE_STATIC || method->klass->valuetype) {
3514                 MonoInst *vtable_loc, *vtable_var;
3515
3516                 g_assert (!this_ins);
3517
3518                 vtable_loc = mono_get_vtable_var (cfg);
3519                 EMIT_NEW_TEMPLOAD (cfg, vtable_var, vtable_loc->inst_c0);
3520
3521                 if (method->is_inflated && mono_method_get_context (method)->method_inst) {
3522                         MonoInst *mrgctx_var = vtable_var;
3523                         int vtable_reg;
3524
3525                         vtable_reg = alloc_preg (cfg);
3526                         EMIT_NEW_LOAD_MEMBASE (cfg, vtable_var, OP_LOAD_MEMBASE, vtable_reg, mrgctx_var->dreg, MONO_STRUCT_OFFSET (MonoMethodRuntimeGenericContext, class_vtable));
3527                         vtable_var->type = STACK_PTR;
3528                 }
3529
3530                 return vtable_var;
3531         } else {
3532                 MonoInst *ins;
3533                 int vtable_reg;
3534         
3535                 vtable_reg = alloc_preg (cfg);
3536                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, vtable_reg, this_ins->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3537                 return ins;
3538         }
3539 }
3540
3541 static MonoJumpInfoRgctxEntry *
3542 mono_patch_info_rgctx_entry_new (MonoMemPool *mp, MonoMethod *method, gboolean in_mrgctx, MonoJumpInfoType patch_type, gconstpointer patch_data, MonoRgctxInfoType info_type)
3543 {
3544         MonoJumpInfoRgctxEntry *res = (MonoJumpInfoRgctxEntry *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoRgctxEntry));
3545         res->method = method;
3546         res->in_mrgctx = in_mrgctx;
3547         res->data = (MonoJumpInfo *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo));
3548         res->data->type = patch_type;
3549         res->data->data.target = patch_data;
3550         res->info_type = info_type;
3551
3552         return res;
3553 }
3554
3555 static inline MonoInst*
3556 emit_rgctx_fetch_inline (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
3557 {
3558         MonoInst *args [16];
3559         MonoInst *call;
3560
3561         // FIXME: No fastpath since the slot is not a compile time constant
3562         args [0] = rgctx;
3563         EMIT_NEW_AOTCONST (cfg, args [1], MONO_PATCH_INFO_RGCTX_SLOT_INDEX, entry);
3564         if (entry->in_mrgctx)
3565                 call = mono_emit_jit_icall (cfg, mono_fill_method_rgctx, args);
3566         else
3567                 call = mono_emit_jit_icall (cfg, mono_fill_class_rgctx, args);
3568         return call;
3569 #if 0
3570         /*
3571          * FIXME: This can be called during decompose, which is a problem since it creates
3572          * new bblocks.
3573          * Also, the fastpath doesn't work since the slot number is dynamically allocated.
3574          */
3575         int i, slot, depth, index, rgctx_reg, val_reg, res_reg;
3576         gboolean mrgctx;
3577         MonoBasicBlock *is_null_bb, *end_bb;
3578         MonoInst *res, *ins, *call;
3579         MonoInst *args[16];
3580
3581         slot = mini_get_rgctx_entry_slot (entry);
3582
3583         mrgctx = MONO_RGCTX_SLOT_IS_MRGCTX (slot);
3584         index = MONO_RGCTX_SLOT_INDEX (slot);
3585         if (mrgctx)
3586                 index += MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
3587         for (depth = 0; ; ++depth) {
3588                 int size = mono_class_rgctx_get_array_size (depth, mrgctx);
3589
3590                 if (index < size - 1)
3591                         break;
3592                 index -= size - 1;
3593         }
3594
3595         NEW_BBLOCK (cfg, end_bb);
3596         NEW_BBLOCK (cfg, is_null_bb);
3597
3598         if (mrgctx) {
3599                 rgctx_reg = rgctx->dreg;
3600         } else {
3601                 rgctx_reg = alloc_preg (cfg);
3602
3603                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, rgctx_reg, rgctx->dreg, MONO_STRUCT_OFFSET (MonoVTable, runtime_generic_context));
3604                 // FIXME: Avoid this check by allocating the table when the vtable is created etc.
3605                 NEW_BBLOCK (cfg, is_null_bb);
3606
3607                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rgctx_reg, 0);
3608                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3609         }
3610
3611         for (i = 0; i < depth; ++i) {
3612                 int array_reg = alloc_preg (cfg);
3613
3614                 /* load ptr to next array */
3615                 if (mrgctx && i == 0)
3616                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, rgctx_reg, MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT);
3617                 else
3618                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, rgctx_reg, 0);
3619                 rgctx_reg = array_reg;
3620                 /* is the ptr null? */
3621                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rgctx_reg, 0);
3622                 /* if yes, jump to actual trampoline */
3623                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3624         }
3625
3626         /* fetch slot */
3627         val_reg = alloc_preg (cfg);
3628         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, val_reg, rgctx_reg, (index + 1) * sizeof (gpointer));
3629         /* is the slot null? */
3630         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, val_reg, 0);
3631         /* if yes, jump to actual trampoline */
3632         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3633
3634         /* Fastpath */
3635         res_reg = alloc_preg (cfg);
3636         MONO_INST_NEW (cfg, ins, OP_MOVE);
3637         ins->dreg = res_reg;
3638         ins->sreg1 = val_reg;
3639         MONO_ADD_INS (cfg->cbb, ins);
3640         res = ins;
3641         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3642
3643         /* Slowpath */
3644         MONO_START_BB (cfg, is_null_bb);
3645         args [0] = rgctx;
3646         EMIT_NEW_ICONST (cfg, args [1], index);
3647         if (mrgctx)
3648                 call = mono_emit_jit_icall (cfg, mono_fill_method_rgctx, args);
3649         else
3650                 call = mono_emit_jit_icall (cfg, mono_fill_class_rgctx, args);
3651         MONO_INST_NEW (cfg, ins, OP_MOVE);
3652         ins->dreg = res_reg;
3653         ins->sreg1 = call->dreg;
3654         MONO_ADD_INS (cfg->cbb, ins);
3655         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3656
3657         MONO_START_BB (cfg, end_bb);
3658
3659         return res;
3660 #endif
3661 }
3662
3663 /*
3664  * emit_rgctx_fetch:
3665  *
3666  *   Emit IR to load the value of the rgctx entry ENTRY from the rgctx
3667  * given by RGCTX.
3668  */
3669 static inline MonoInst*
3670 emit_rgctx_fetch (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
3671 {
3672         if (cfg->llvm_only)
3673                 return emit_rgctx_fetch_inline (cfg, rgctx, entry);
3674         else
3675                 return mono_emit_abs_call (cfg, MONO_PATCH_INFO_RGCTX_FETCH, entry, helper_sig_rgctx_lazy_fetch_trampoline, &rgctx);
3676 }
3677
3678 static MonoInst*
3679 emit_get_rgctx_klass (MonoCompile *cfg, int context_used,
3680                                           MonoClass *klass, MonoRgctxInfoType rgctx_type)
3681 {
3682         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);
3683         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3684
3685         return emit_rgctx_fetch (cfg, rgctx, entry);
3686 }
3687
3688 static MonoInst*
3689 emit_get_rgctx_sig (MonoCompile *cfg, int context_used,
3690                                         MonoMethodSignature *sig, MonoRgctxInfoType rgctx_type)
3691 {
3692         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);
3693         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3694
3695         return emit_rgctx_fetch (cfg, rgctx, entry);
3696 }
3697
3698 static MonoInst*
3699 emit_get_rgctx_gsharedvt_call (MonoCompile *cfg, int context_used,
3700                                                            MonoMethodSignature *sig, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3701 {
3702         MonoJumpInfoGSharedVtCall *call_info;
3703         MonoJumpInfoRgctxEntry *entry;
3704         MonoInst *rgctx;
3705
3706         call_info = (MonoJumpInfoGSharedVtCall *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoGSharedVtCall));
3707         call_info->sig = sig;
3708         call_info->method = cmethod;
3709
3710         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);
3711         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3712
3713         return emit_rgctx_fetch (cfg, rgctx, entry);
3714 }
3715
3716 /*
3717  * emit_get_rgctx_virt_method:
3718  *
3719  *   Return data for method VIRT_METHOD for a receiver of type KLASS.
3720  */
3721 static MonoInst*
3722 emit_get_rgctx_virt_method (MonoCompile *cfg, int context_used,
3723                                                         MonoClass *klass, MonoMethod *virt_method, MonoRgctxInfoType rgctx_type)
3724 {
3725         MonoJumpInfoVirtMethod *info;
3726         MonoJumpInfoRgctxEntry *entry;
3727         MonoInst *rgctx;
3728
3729         info = (MonoJumpInfoVirtMethod *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoVirtMethod));
3730         info->klass = klass;
3731         info->method = virt_method;
3732
3733         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);
3734         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3735
3736         return emit_rgctx_fetch (cfg, rgctx, entry);
3737 }
3738
3739 static MonoInst*
3740 emit_get_rgctx_gsharedvt_method (MonoCompile *cfg, int context_used,
3741                                                                  MonoMethod *cmethod, MonoGSharedVtMethodInfo *info)
3742 {
3743         MonoJumpInfoRgctxEntry *entry;
3744         MonoInst *rgctx;
3745
3746         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);
3747         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3748
3749         return emit_rgctx_fetch (cfg, rgctx, entry);
3750 }
3751
3752 /*
3753  * emit_get_rgctx_method:
3754  *
3755  *   Emit IR to load the property RGCTX_TYPE of CMETHOD. If context_used is 0, emit
3756  * normal constants, else emit a load from the rgctx.
3757  */
3758 static MonoInst*
3759 emit_get_rgctx_method (MonoCompile *cfg, int context_used,
3760                                            MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3761 {
3762         if (!context_used) {
3763                 MonoInst *ins;
3764
3765                 switch (rgctx_type) {
3766                 case MONO_RGCTX_INFO_METHOD:
3767                         EMIT_NEW_METHODCONST (cfg, ins, cmethod);
3768                         return ins;
3769                 case MONO_RGCTX_INFO_METHOD_RGCTX:
3770                         EMIT_NEW_METHOD_RGCTX_CONST (cfg, ins, cmethod);
3771                         return ins;
3772                 default:
3773                         g_assert_not_reached ();
3774                 }
3775         } else {
3776                 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);
3777                 MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3778
3779                 return emit_rgctx_fetch (cfg, rgctx, entry);
3780         }
3781 }
3782
3783 static MonoInst*
3784 emit_get_rgctx_field (MonoCompile *cfg, int context_used,
3785                                           MonoClassField *field, MonoRgctxInfoType rgctx_type)
3786 {
3787         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);
3788         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3789
3790         return emit_rgctx_fetch (cfg, rgctx, entry);
3791 }
3792
3793 static int
3794 get_gsharedvt_info_slot (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3795 {
3796         MonoGSharedVtMethodInfo *info = cfg->gsharedvt_info;
3797         MonoRuntimeGenericContextInfoTemplate *template_;
3798         int i, idx;
3799
3800         g_assert (info);
3801
3802         for (i = 0; i < info->num_entries; ++i) {
3803                 MonoRuntimeGenericContextInfoTemplate *otemplate = &info->entries [i];
3804
3805                 if (otemplate->info_type == rgctx_type && otemplate->data == data && rgctx_type != MONO_RGCTX_INFO_LOCAL_OFFSET)
3806                         return i;
3807         }
3808
3809         if (info->num_entries == info->count_entries) {
3810                 MonoRuntimeGenericContextInfoTemplate *new_entries;
3811                 int new_count_entries = info->count_entries ? info->count_entries * 2 : 16;
3812
3813                 new_entries = (MonoRuntimeGenericContextInfoTemplate *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * new_count_entries);
3814
3815                 memcpy (new_entries, info->entries, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
3816                 info->entries = new_entries;
3817                 info->count_entries = new_count_entries;
3818         }
3819
3820         idx = info->num_entries;
3821         template_ = &info->entries [idx];
3822         template_->info_type = rgctx_type;
3823         template_->data = data;
3824
3825         info->num_entries ++;
3826
3827         return idx;
3828 }
3829
3830 /*
3831  * emit_get_gsharedvt_info:
3832  *
3833  *   This is similar to emit_get_rgctx_.., but loads the data from the gsharedvt info var instead of calling an rgctx fetch trampoline.
3834  */
3835 static MonoInst*
3836 emit_get_gsharedvt_info (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3837 {
3838         MonoInst *ins;
3839         int idx, dreg;
3840
3841         idx = get_gsharedvt_info_slot (cfg, data, rgctx_type);
3842         /* Load info->entries [idx] */
3843         dreg = alloc_preg (cfg);
3844         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, cfg->gsharedvt_info_var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
3845
3846         return ins;
3847 }
3848
3849 static MonoInst*
3850 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type)
3851 {
3852         return emit_get_gsharedvt_info (cfg, &klass->byval_arg, rgctx_type);
3853 }
3854
3855 /*
3856  * On return the caller must check @klass for load errors.
3857  */
3858 static void
3859 emit_class_init (MonoCompile *cfg, MonoClass *klass)
3860 {
3861         MonoInst *vtable_arg;
3862         int context_used;
3863
3864         context_used = mini_class_check_context_used (cfg, klass);
3865
3866         if (context_used) {
3867                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
3868                                                                                    klass, MONO_RGCTX_INFO_VTABLE);
3869         } else {
3870                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
3871
3872                 if (!vtable)
3873                         return;
3874                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
3875         }
3876
3877         if (!COMPILE_LLVM (cfg) && cfg->backend->have_op_generic_class_init) {
3878                 MonoInst *ins;
3879
3880                 /*
3881                  * Using an opcode instead of emitting IR here allows the hiding of the call inside the opcode,
3882                  * so this doesn't have to clobber any regs and it doesn't break basic blocks.
3883                  */
3884                 MONO_INST_NEW (cfg, ins, OP_GENERIC_CLASS_INIT);
3885                 ins->sreg1 = vtable_arg->dreg;
3886                 MONO_ADD_INS (cfg->cbb, ins);
3887         } else {
3888                 static int byte_offset = -1;
3889                 static guint8 bitmask;
3890                 int bits_reg, inited_reg;
3891                 MonoBasicBlock *inited_bb;
3892                 MonoInst *args [16];
3893
3894                 if (byte_offset < 0)
3895                         mono_marshal_find_bitfield_offset (MonoVTable, initialized, &byte_offset, &bitmask);
3896
3897                 bits_reg = alloc_ireg (cfg);
3898                 inited_reg = alloc_ireg (cfg);
3899
3900                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, bits_reg, vtable_arg->dreg, byte_offset);
3901                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, inited_reg, bits_reg, bitmask);
3902
3903                 NEW_BBLOCK (cfg, inited_bb);
3904
3905                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, inited_reg, 0);
3906                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, inited_bb);
3907
3908                 args [0] = vtable_arg;
3909                 mono_emit_jit_icall (cfg, mono_generic_class_init, args);
3910
3911                 MONO_START_BB (cfg, inited_bb);
3912         }
3913 }
3914
3915 static void
3916 emit_seq_point (MonoCompile *cfg, MonoMethod *method, guint8* ip, gboolean intr_loc, gboolean nonempty_stack)
3917 {
3918         MonoInst *ins;
3919
3920         if (cfg->gen_seq_points && cfg->method == method) {
3921                 NEW_SEQ_POINT (cfg, ins, ip - cfg->header->code, intr_loc);
3922                 if (nonempty_stack)
3923                         ins->flags |= MONO_INST_NONEMPTY_STACK;
3924                 MONO_ADD_INS (cfg->cbb, ins);
3925         }
3926 }
3927
3928 static void
3929 save_cast_details (MonoCompile *cfg, MonoClass *klass, int obj_reg, gboolean null_check)
3930 {
3931         if (mini_get_debug_options ()->better_cast_details) {
3932                 int vtable_reg = alloc_preg (cfg);
3933                 int klass_reg = alloc_preg (cfg);
3934                 MonoBasicBlock *is_null_bb = NULL;
3935                 MonoInst *tls_get;
3936                 int to_klass_reg, context_used;
3937
3938                 if (null_check) {
3939                         NEW_BBLOCK (cfg, is_null_bb);
3940
3941                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
3942                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3943                 }
3944
3945                 tls_get = mono_get_jit_tls_intrinsic (cfg);
3946                 if (!tls_get) {
3947                         fprintf (stderr, "error: --debug=casts not supported on this platform.\n.");
3948                         exit (1);
3949                 }
3950
3951                 MONO_ADD_INS (cfg->cbb, tls_get);
3952                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3953                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3954
3955                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), klass_reg);
3956
3957                 context_used = mini_class_check_context_used (cfg, klass);
3958                 if (context_used) {
3959                         MonoInst *class_ins;
3960
3961                         class_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3962                         to_klass_reg = class_ins->dreg;
3963                 } else {
3964                         to_klass_reg = alloc_preg (cfg);
3965                         MONO_EMIT_NEW_CLASSCONST (cfg, to_klass_reg, klass);
3966                 }
3967                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_to), to_klass_reg);
3968
3969                 if (null_check)
3970                         MONO_START_BB (cfg, is_null_bb);
3971         }
3972 }
3973
3974 static void
3975 reset_cast_details (MonoCompile *cfg)
3976 {
3977         /* Reset the variables holding the cast details */
3978         if (mini_get_debug_options ()->better_cast_details) {
3979                 MonoInst *tls_get = mono_get_jit_tls_intrinsic (cfg);
3980
3981                 MONO_ADD_INS (cfg->cbb, tls_get);
3982                 /* It is enough to reset the from field */
3983                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), 0);
3984         }
3985 }
3986
3987 /*
3988  * On return the caller must check @array_class for load errors
3989  */
3990 static void
3991 mini_emit_check_array_type (MonoCompile *cfg, MonoInst *obj, MonoClass *array_class)
3992 {
3993         int vtable_reg = alloc_preg (cfg);
3994         int context_used;
3995
3996         context_used = mini_class_check_context_used (cfg, array_class);
3997
3998         save_cast_details (cfg, array_class, obj->dreg, FALSE);
3999
4000         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4001
4002         if (cfg->opt & MONO_OPT_SHARED) {
4003                 int class_reg = alloc_preg (cfg);
4004                 MonoInst *ins;
4005
4006                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, class_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4007                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, array_class);
4008                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, class_reg, ins->dreg);
4009         } else if (context_used) {
4010                 MonoInst *vtable_ins;
4011
4012                 vtable_ins = emit_get_rgctx_klass (cfg, context_used, array_class, MONO_RGCTX_INFO_VTABLE);
4013                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vtable_ins->dreg);
4014         } else {
4015                 if (cfg->compile_aot) {
4016                         int vt_reg;
4017                         MonoVTable *vtable;
4018
4019                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
4020                                 return;
4021                         vt_reg = alloc_preg (cfg);
4022                         MONO_EMIT_NEW_VTABLECONST (cfg, vt_reg, vtable);
4023                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vt_reg);
4024                 } else {
4025                         MonoVTable *vtable;
4026                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
4027                                 return;
4028                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vtable);
4029                 }
4030         }
4031         
4032         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ArrayTypeMismatchException");
4033
4034         reset_cast_details (cfg);
4035 }
4036
4037 /**
4038  * Handles unbox of a Nullable<T>. If context_used is non zero, then shared 
4039  * generic code is generated.
4040  */
4041 static MonoInst*
4042 handle_unbox_nullable (MonoCompile* cfg, MonoInst* val, MonoClass* klass, int context_used)
4043 {
4044         MonoMethod* method = mono_class_get_method_from_name (klass, "Unbox", 1);
4045
4046         if (context_used) {
4047                 MonoInst *rgctx, *addr;
4048
4049                 /* FIXME: What if the class is shared?  We might not
4050                    have to get the address of the method from the
4051                    RGCTX. */
4052                 addr = emit_get_rgctx_method (cfg, context_used, method,
4053                                                                           MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
4054                 if (cfg->llvm_only) {
4055                         cfg->signatures = g_slist_prepend_mempool (cfg->mempool, cfg->signatures, mono_method_signature (method));
4056                         return emit_llvmonly_calli (cfg, mono_method_signature (method), &val, addr);
4057                 } else {
4058                         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
4059
4060                         return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
4061                 }
4062         } else {
4063                 gboolean pass_vtable, pass_mrgctx;
4064                 MonoInst *rgctx_arg = NULL;
4065
4066                 check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
4067                 g_assert (!pass_mrgctx);
4068
4069                 if (pass_vtable) {
4070                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
4071
4072                         g_assert (vtable);
4073                         EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
4074                 }
4075
4076                 return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
4077         }
4078 }
4079
4080 static MonoInst*
4081 handle_unbox (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, int context_used)
4082 {
4083         MonoInst *add;
4084         int obj_reg;
4085         int vtable_reg = alloc_dreg (cfg ,STACK_PTR);
4086         int klass_reg = alloc_dreg (cfg ,STACK_PTR);
4087         int eclass_reg = alloc_dreg (cfg ,STACK_PTR);
4088         int rank_reg = alloc_dreg (cfg ,STACK_I4);
4089
4090         obj_reg = sp [0]->dreg;
4091         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4092         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
4093
4094         /* FIXME: generics */
4095         g_assert (klass->rank == 0);
4096                         
4097         // Check rank == 0
4098         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, 0);
4099         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4100
4101         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4102         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, element_class));
4103
4104         if (context_used) {
4105                 MonoInst *element_class;
4106
4107                 /* This assertion is from the unboxcast insn */
4108                 g_assert (klass->rank == 0);
4109
4110                 element_class = emit_get_rgctx_klass (cfg, context_used,
4111                                 klass, MONO_RGCTX_INFO_ELEMENT_KLASS);
4112
4113                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, eclass_reg, element_class->dreg);
4114                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4115         } else {
4116                 save_cast_details (cfg, klass->element_class, obj_reg, FALSE);
4117                 mini_emit_class_check (cfg, eclass_reg, klass->element_class);
4118                 reset_cast_details (cfg);
4119         }
4120
4121         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), obj_reg, sizeof (MonoObject));
4122         MONO_ADD_INS (cfg->cbb, add);
4123         add->type = STACK_MP;
4124         add->klass = klass;
4125
4126         return add;
4127 }
4128
4129 static MonoInst*
4130 handle_unbox_gsharedvt (MonoCompile *cfg, MonoClass *klass, MonoInst *obj)
4131 {
4132         MonoInst *addr, *klass_inst, *is_ref, *args[16];
4133         MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
4134         MonoInst *ins;
4135         int dreg, addr_reg;
4136
4137         klass_inst = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_KLASS);
4138
4139         /* obj */
4140         args [0] = obj;
4141
4142         /* klass */
4143         args [1] = klass_inst;
4144
4145         /* CASTCLASS */
4146         obj = mono_emit_jit_icall (cfg, mono_object_castclass_unbox, args);
4147
4148         NEW_BBLOCK (cfg, is_ref_bb);
4149         NEW_BBLOCK (cfg, is_nullable_bb);
4150         NEW_BBLOCK (cfg, end_bb);
4151         is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
4152         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
4153         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
4154
4155         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
4156         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
4157
4158         /* This will contain either the address of the unboxed vtype, or an address of the temporary where the ref is stored */
4159         addr_reg = alloc_dreg (cfg, STACK_MP);
4160
4161         /* Non-ref case */
4162         /* UNBOX */
4163         NEW_BIALU_IMM (cfg, addr, OP_ADD_IMM, addr_reg, obj->dreg, sizeof (MonoObject));
4164         MONO_ADD_INS (cfg->cbb, addr);
4165
4166         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4167
4168         /* Ref case */
4169         MONO_START_BB (cfg, is_ref_bb);
4170
4171         /* Save the ref to a temporary */
4172         dreg = alloc_ireg (cfg);
4173         EMIT_NEW_VARLOADA_VREG (cfg, addr, dreg, &klass->byval_arg);
4174         addr->dreg = addr_reg;
4175         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, obj->dreg);
4176         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4177
4178         /* Nullable case */
4179         MONO_START_BB (cfg, is_nullable_bb);
4180
4181         {
4182                 MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX);
4183                 MonoInst *unbox_call;
4184                 MonoMethodSignature *unbox_sig;
4185
4186                 unbox_sig = (MonoMethodSignature *)mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
4187                 unbox_sig->ret = &klass->byval_arg;
4188                 unbox_sig->param_count = 1;
4189                 unbox_sig->params [0] = &mono_defaults.object_class->byval_arg;
4190
4191                 if (cfg->llvm_only)
4192                         unbox_call = emit_llvmonly_calli (cfg, unbox_sig, &obj, addr);
4193                 else
4194                         unbox_call = mono_emit_calli (cfg, unbox_sig, &obj, addr, NULL, NULL);
4195
4196                 EMIT_NEW_VARLOADA_VREG (cfg, addr, unbox_call->dreg, &klass->byval_arg);
4197                 addr->dreg = addr_reg;
4198         }
4199
4200         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4201
4202         /* End */
4203         MONO_START_BB (cfg, end_bb);
4204
4205         /* LDOBJ */
4206         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr_reg, 0);
4207
4208         return ins;
4209 }
4210
4211 /*
4212  * Returns NULL and set the cfg exception on error.
4213  */
4214 static MonoInst*
4215 handle_alloc (MonoCompile *cfg, MonoClass *klass, gboolean for_box, int context_used)
4216 {
4217         MonoInst *iargs [2];
4218         void *alloc_ftn;
4219
4220         if (context_used) {
4221                 MonoInst *data;
4222                 MonoRgctxInfoType rgctx_info;
4223                 MonoInst *iargs [2];
4224                 gboolean known_instance_size = !mini_is_gsharedvt_klass (klass);
4225
4226                 MonoMethod *managed_alloc = mono_gc_get_managed_allocator (klass, for_box, known_instance_size);
4227
4228                 if (cfg->opt & MONO_OPT_SHARED)
4229                         rgctx_info = MONO_RGCTX_INFO_KLASS;
4230                 else
4231                         rgctx_info = MONO_RGCTX_INFO_VTABLE;
4232                 data = emit_get_rgctx_klass (cfg, context_used, klass, rgctx_info);
4233
4234                 if (cfg->opt & MONO_OPT_SHARED) {
4235                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
4236                         iargs [1] = data;
4237                         alloc_ftn = ves_icall_object_new;
4238                 } else {
4239                         iargs [0] = data;
4240                         alloc_ftn = ves_icall_object_new_specific;
4241                 }
4242
4243                 if (managed_alloc && !(cfg->opt & MONO_OPT_SHARED)) {
4244                         if (known_instance_size) {
4245                                 int size = mono_class_instance_size (klass);
4246                                 if (size < sizeof (MonoObject))
4247                                         g_error ("Invalid size %d for class %s", size, mono_type_get_full_name (klass));
4248
4249                                 EMIT_NEW_ICONST (cfg, iargs [1], size);
4250                         }
4251                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
4252                 }
4253
4254                 return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
4255         }
4256
4257         if (cfg->opt & MONO_OPT_SHARED) {
4258                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
4259                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
4260
4261                 alloc_ftn = ves_icall_object_new;
4262         } else if (cfg->compile_aot && cfg->cbb->out_of_line && klass->type_token && klass->image == mono_defaults.corlib && !klass->generic_class) {
4263                 /* This happens often in argument checking code, eg. throw new FooException... */
4264                 /* Avoid relocations and save some space by calling a helper function specialized to mscorlib */
4265                 EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (klass->type_token));
4266                 return mono_emit_jit_icall (cfg, mono_helper_newobj_mscorlib, iargs);
4267         } else {
4268                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
4269                 MonoMethod *managed_alloc = NULL;
4270                 gboolean pass_lw;
4271
4272                 if (!vtable) {
4273                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4274                         cfg->exception_ptr = klass;
4275                         return NULL;
4276                 }
4277
4278                 managed_alloc = mono_gc_get_managed_allocator (klass, for_box, TRUE);
4279
4280                 if (managed_alloc) {
4281                         int size = mono_class_instance_size (klass);
4282                         if (size < sizeof (MonoObject))
4283                                 g_error ("Invalid size %d for class %s", size, mono_type_get_full_name (klass));
4284
4285                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
4286                         EMIT_NEW_ICONST (cfg, iargs [1], size);
4287                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
4288                 }
4289                 alloc_ftn = mono_class_get_allocation_ftn (vtable, for_box, &pass_lw);
4290                 if (pass_lw) {
4291                         guint32 lw = vtable->klass->instance_size;
4292                         lw = ((lw + (sizeof (gpointer) - 1)) & ~(sizeof (gpointer) - 1)) / sizeof (gpointer);
4293                         EMIT_NEW_ICONST (cfg, iargs [0], lw);
4294                         EMIT_NEW_VTABLECONST (cfg, iargs [1], vtable);
4295                 }
4296                 else {
4297                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
4298                 }
4299         }
4300
4301         return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
4302 }
4303         
4304 /*
4305  * Returns NULL and set the cfg exception on error.
4306  */     
4307 static MonoInst*
4308 handle_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_used)
4309 {
4310         MonoInst *alloc, *ins;
4311
4312         if (mono_class_is_nullable (klass)) {
4313                 MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
4314
4315                 if (context_used) {
4316                         if (cfg->llvm_only && cfg->gsharedvt) {
4317                                 MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
4318                                                                                                                 MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
4319                                 return emit_llvmonly_calli (cfg, mono_method_signature (method), &val, addr);
4320                         } else {
4321                                 /* FIXME: What if the class is shared?  We might not
4322                                    have to get the method address from the RGCTX. */
4323                                 MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
4324                                                                                                                 MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
4325                                 MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
4326
4327                                 return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
4328                         }
4329                 } else {
4330                         gboolean pass_vtable, pass_mrgctx;
4331                         MonoInst *rgctx_arg = NULL;
4332
4333                         check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
4334                         g_assert (!pass_mrgctx);
4335
4336                         if (pass_vtable) {
4337                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
4338
4339                                 g_assert (vtable);
4340                                 EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
4341                         }
4342
4343                         return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
4344                 }
4345         }
4346
4347         if (mini_is_gsharedvt_klass (klass)) {
4348                 MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
4349                 MonoInst *res, *is_ref, *src_var, *addr;
4350                 int dreg;
4351
4352                 dreg = alloc_ireg (cfg);
4353
4354                 NEW_BBLOCK (cfg, is_ref_bb);
4355                 NEW_BBLOCK (cfg, is_nullable_bb);
4356                 NEW_BBLOCK (cfg, end_bb);
4357                 is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
4358                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
4359                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
4360
4361                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
4362                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
4363
4364                 /* Non-ref case */
4365                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4366                 if (!alloc)
4367                         return NULL;
4368                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4369                 ins->opcode = OP_STOREV_MEMBASE;
4370
4371                 EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, alloc->dreg);
4372                 res->type = STACK_OBJ;
4373                 res->klass = klass;
4374                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4375                 
4376                 /* Ref case */
4377                 MONO_START_BB (cfg, is_ref_bb);
4378
4379                 /* val is a vtype, so has to load the value manually */
4380                 src_var = get_vreg_to_inst (cfg, val->dreg);
4381                 if (!src_var)
4382                         src_var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, val->dreg);
4383                 EMIT_NEW_VARLOADA (cfg, addr, src_var, src_var->inst_vtype);
4384                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, addr->dreg, 0);
4385                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4386
4387                 /* Nullable case */
4388                 MONO_START_BB (cfg, is_nullable_bb);
4389
4390                 {
4391                         MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass,
4392                                                                                                         MONO_RGCTX_INFO_NULLABLE_CLASS_BOX);
4393                         MonoInst *box_call;
4394                         MonoMethodSignature *box_sig;
4395
4396                         /*
4397                          * klass is Nullable<T>, need to call Nullable<T>.Box () using a gsharedvt signature, but we cannot
4398                          * construct that method at JIT time, so have to do things by hand.
4399                          */
4400                         box_sig = (MonoMethodSignature *)mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
4401                         box_sig->ret = &mono_defaults.object_class->byval_arg;
4402                         box_sig->param_count = 1;
4403                         box_sig->params [0] = &klass->byval_arg;
4404
4405                         if (cfg->llvm_only)
4406                                 box_call = emit_llvmonly_calli (cfg, box_sig, &val, addr);
4407                         else
4408                                 box_call = mono_emit_calli (cfg, box_sig, &val, addr, NULL, NULL);
4409                         EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, box_call->dreg);
4410                         res->type = STACK_OBJ;
4411                         res->klass = klass;
4412                 }
4413
4414                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4415
4416                 MONO_START_BB (cfg, end_bb);
4417
4418                 return res;
4419         } else {
4420                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4421                 if (!alloc)
4422                         return NULL;
4423
4424                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4425                 return alloc;
4426         }
4427 }
4428
4429 static gboolean
4430 mini_class_has_reference_variant_generic_argument (MonoCompile *cfg, MonoClass *klass, int context_used)
4431 {
4432         int i;
4433         MonoGenericContainer *container;
4434         MonoGenericInst *ginst;
4435
4436         if (klass->generic_class) {
4437                 container = klass->generic_class->container_class->generic_container;
4438                 ginst = klass->generic_class->context.class_inst;
4439         } else if (klass->generic_container && context_used) {
4440                 container = klass->generic_container;
4441                 ginst = container->context.class_inst;
4442         } else {
4443                 return FALSE;
4444         }
4445
4446         for (i = 0; i < container->type_argc; ++i) {
4447                 MonoType *type;
4448                 if (!(mono_generic_container_get_param_info (container, i)->flags & (MONO_GEN_PARAM_VARIANT|MONO_GEN_PARAM_COVARIANT)))
4449                         continue;
4450                 type = ginst->type_argv [i];
4451                 if (mini_type_is_reference (type))
4452                         return TRUE;
4453         }
4454         return FALSE;
4455 }
4456
4457 static GHashTable* direct_icall_type_hash;
4458
4459 static gboolean
4460 icall_is_direct_callable (MonoCompile *cfg, MonoMethod *cmethod)
4461 {
4462         /* LLVM on amd64 can't handle calls to non-32 bit addresses */
4463         if (!direct_icalls_enabled (cfg))
4464                 return FALSE;
4465
4466         /*
4467          * An icall is directly callable if it doesn't directly or indirectly call mono_raise_exception ().
4468          * Whitelist a few icalls for now.
4469          */
4470         if (!direct_icall_type_hash) {
4471                 GHashTable *h = g_hash_table_new (g_str_hash, g_str_equal);
4472
4473                 g_hash_table_insert (h, (char*)"Decimal", GUINT_TO_POINTER (1));
4474                 g_hash_table_insert (h, (char*)"Number", GUINT_TO_POINTER (1));
4475                 g_hash_table_insert (h, (char*)"Buffer", GUINT_TO_POINTER (1));
4476                 g_hash_table_insert (h, (char*)"Monitor", GUINT_TO_POINTER (1));
4477                 mono_memory_barrier ();
4478                 direct_icall_type_hash = h;
4479         }
4480
4481         if (cmethod->klass == mono_defaults.math_class)
4482                 return TRUE;
4483         /* No locking needed */
4484         if (cmethod->klass->image == mono_defaults.corlib && g_hash_table_lookup (direct_icall_type_hash, cmethod->klass->name))
4485                 return TRUE;
4486         return FALSE;
4487 }
4488
4489 static gboolean
4490 method_needs_stack_walk (MonoCompile *cfg, MonoMethod *cmethod)
4491 {
4492         if (cmethod->klass == mono_defaults.systemtype_class) {
4493                 if (!strcmp (cmethod->name, "GetType"))
4494                         return TRUE;
4495         }
4496         return FALSE;
4497 }
4498
4499 #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)
4500
4501 static MonoInst*
4502 emit_isinst_with_cache (MonoCompile *cfg, MonoClass *klass, MonoInst **args)
4503 {
4504         MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
4505         return mono_emit_method_call (cfg, mono_isinst, args, NULL);
4506 }
4507
4508 static MonoInst*
4509 emit_castclass_with_cache (MonoCompile *cfg, MonoClass *klass, MonoInst **args)
4510 {
4511         MonoMethod *mono_castclass = mono_marshal_get_castclass_with_cache ();
4512         MonoInst *res;
4513
4514         save_cast_details (cfg, klass, args [0]->dreg, TRUE);
4515         res = mono_emit_method_call (cfg, mono_castclass, args, NULL);
4516         reset_cast_details (cfg);
4517
4518         return res;
4519 }
4520
4521 static int
4522 get_castclass_cache_idx (MonoCompile *cfg)
4523 {
4524         /* Each CASTCLASS_CACHE patch needs a unique index which identifies the call site */
4525         cfg->castclass_cache_index ++;
4526         return (cfg->method_index << 16) | cfg->castclass_cache_index;
4527 }
4528
4529
4530 static MonoInst*
4531 emit_isinst_with_cache_nonshared (MonoCompile *cfg, MonoInst *obj, MonoClass *klass)
4532 {
4533         MonoInst *args [3];
4534         int idx;
4535
4536         args [0] = obj; /* obj */
4537         EMIT_NEW_CLASSCONST (cfg, args [1], klass); /* klass */
4538
4539         idx = get_castclass_cache_idx (cfg); /* inline cache*/
4540         args [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
4541
4542         return emit_isinst_with_cache (cfg, klass, args);
4543 }
4544
4545 static MonoInst*
4546 emit_castclass_with_cache_nonshared (MonoCompile *cfg, MonoInst *obj, MonoClass *klass)
4547 {
4548         MonoInst *args [3];
4549         int idx;
4550
4551         /* obj */
4552         args [0] = obj;
4553
4554         /* klass */
4555         EMIT_NEW_CLASSCONST (cfg, args [1], klass);
4556
4557         /* inline cache*/
4558         idx = get_castclass_cache_idx (cfg);
4559         args [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
4560
4561         /*The wrapper doesn't inline well so the bloat of inlining doesn't pay off.*/
4562         return emit_castclass_with_cache (cfg, klass, args);
4563 }
4564
4565 /*
4566  * Returns NULL and set the cfg exception on error.
4567  */
4568 static MonoInst*
4569 handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
4570 {
4571         MonoBasicBlock *is_null_bb;
4572         int obj_reg = src->dreg;
4573         int vtable_reg = alloc_preg (cfg);
4574         MonoInst *klass_inst = NULL;
4575
4576         if (src->opcode == OP_PCONST && src->inst_p0 == 0)
4577                 return src;
4578
4579         if (context_used) {
4580                 MonoInst *args [3];
4581
4582                 if (mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
4583                         MonoInst *cache_ins;
4584
4585                         cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
4586
4587                         /* obj */
4588                         args [0] = src;
4589
4590                         /* klass - it's the second element of the cache entry*/
4591                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
4592
4593                         /* cache */
4594                         args [2] = cache_ins;
4595
4596                         return emit_castclass_with_cache (cfg, klass, args);
4597                 }
4598
4599                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
4600         }
4601
4602         NEW_BBLOCK (cfg, is_null_bb);
4603
4604         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4605         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
4606
4607         save_cast_details (cfg, klass, obj_reg, FALSE);
4608
4609         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4610                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4611                 mini_emit_iface_cast (cfg, vtable_reg, klass, NULL, NULL);
4612         } else {
4613                 int klass_reg = alloc_preg (cfg);
4614
4615                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4616
4617                 if (!klass->rank && !cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
4618                         /* the remoting code is broken, access the class for now */
4619                         if (0) { /*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4620                                 MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4621                                 if (!vt) {
4622                                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4623                                         cfg->exception_ptr = klass;
4624                                         return NULL;
4625                                 }
4626                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4627                         } else {
4628                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4629                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4630                         }
4631                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4632                 } else {
4633                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4634                         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, klass_inst, is_null_bb);
4635                 }
4636         }
4637
4638         MONO_START_BB (cfg, is_null_bb);
4639
4640         reset_cast_details (cfg);
4641
4642         return src;
4643 }
4644
4645 /*
4646  * Returns NULL and set the cfg exception on error.
4647  */
4648 static MonoInst*
4649 handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
4650 {
4651         MonoInst *ins;
4652         MonoBasicBlock *is_null_bb, *false_bb, *end_bb;
4653         int obj_reg = src->dreg;
4654         int vtable_reg = alloc_preg (cfg);
4655         int res_reg = alloc_ireg_ref (cfg);
4656         MonoInst *klass_inst = NULL;
4657
4658         if (context_used) {
4659                 MonoInst *args [3];
4660
4661                 if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
4662                         MonoInst *cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
4663
4664                         args [0] = src; /* obj */
4665
4666                         /* klass - it's the second element of the cache entry*/
4667                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
4668
4669                         args [2] = cache_ins; /* cache */
4670                         return emit_isinst_with_cache (cfg, klass, args);
4671                 }
4672
4673                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
4674         }
4675
4676         NEW_BBLOCK (cfg, is_null_bb);
4677         NEW_BBLOCK (cfg, false_bb);
4678         NEW_BBLOCK (cfg, end_bb);
4679
4680         /* Do the assignment at the beginning, so the other assignment can be if converted */
4681         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, res_reg, obj_reg);
4682         ins->type = STACK_OBJ;
4683         ins->klass = klass;
4684
4685         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4686         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_null_bb);
4687
4688         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4689
4690         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4691                 g_assert (!context_used);
4692                 /* the is_null_bb target simply copies the input register to the output */
4693                 mini_emit_iface_cast (cfg, vtable_reg, klass, false_bb, is_null_bb);
4694         } else {
4695                 int klass_reg = alloc_preg (cfg);
4696
4697                 if (klass->rank) {
4698                         int rank_reg = alloc_preg (cfg);
4699                         int eclass_reg = alloc_preg (cfg);
4700
4701                         g_assert (!context_used);
4702                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
4703                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
4704                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4705                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4706                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
4707                         if (klass->cast_class == mono_defaults.object_class) {
4708                                 int parent_reg = alloc_preg (cfg);
4709                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
4710                                 mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, is_null_bb);
4711                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4712                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4713                         } else if (klass->cast_class == mono_defaults.enum_class->parent) {
4714                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, is_null_bb);
4715                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);                          
4716                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4717                         } else if (klass->cast_class == mono_defaults.enum_class) {
4718                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4719                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4720                         } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
4721                                 mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4722                         } else {
4723                                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY)) {
4724                                         /* Check that the object is a vector too */
4725                                         int bounds_reg = alloc_preg (cfg);
4726                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
4727                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
4728                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4729                                 }
4730
4731                                 /* the is_null_bb target simply copies the input register to the output */
4732                                 mini_emit_isninst_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4733                         }
4734                 } else if (mono_class_is_nullable (klass)) {
4735                         g_assert (!context_used);
4736                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4737                         /* the is_null_bb target simply copies the input register to the output */
4738                         mini_emit_isninst_cast (cfg, klass_reg, klass->cast_class, false_bb, is_null_bb);
4739                 } else {
4740                         if (!cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
4741                                 g_assert (!context_used);
4742                                 /* the remoting code is broken, access the class for now */
4743                                 if (0) {/*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4744                                         MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4745                                         if (!vt) {
4746                                                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4747                                                 cfg->exception_ptr = klass;
4748                                                 return NULL;
4749                                         }
4750                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4751                                 } else {
4752                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4753                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4754                                 }
4755                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4756                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, is_null_bb);
4757                         } else {
4758                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4759                                 /* the is_null_bb target simply copies the input register to the output */
4760                                 mini_emit_isninst_cast_inst (cfg, klass_reg, klass, klass_inst, false_bb, is_null_bb);
4761                         }
4762                 }
4763         }
4764
4765         MONO_START_BB (cfg, false_bb);
4766
4767         MONO_EMIT_NEW_PCONST (cfg, res_reg, 0);
4768         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4769
4770         MONO_START_BB (cfg, is_null_bb);
4771
4772         MONO_START_BB (cfg, end_bb);
4773
4774         return ins;
4775 }
4776
4777 static MonoInst*
4778 handle_cisinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4779 {
4780         /* This opcode takes as input an object reference and a class, and returns:
4781         0) if the object is an instance of the class,
4782         1) if the object is not instance of the class,
4783         2) if the object is a proxy whose type cannot be determined */
4784
4785         MonoInst *ins;
4786 #ifndef DISABLE_REMOTING
4787         MonoBasicBlock *true_bb, *false_bb, *false2_bb, *end_bb, *no_proxy_bb, *interface_fail_bb;
4788 #else
4789         MonoBasicBlock *true_bb, *false_bb, *end_bb;
4790 #endif
4791         int obj_reg = src->dreg;
4792         int dreg = alloc_ireg (cfg);
4793         int tmp_reg;
4794 #ifndef DISABLE_REMOTING
4795         int klass_reg = alloc_preg (cfg);
4796 #endif
4797
4798         NEW_BBLOCK (cfg, true_bb);
4799         NEW_BBLOCK (cfg, false_bb);
4800         NEW_BBLOCK (cfg, end_bb);
4801 #ifndef DISABLE_REMOTING
4802         NEW_BBLOCK (cfg, false2_bb);
4803         NEW_BBLOCK (cfg, no_proxy_bb);
4804 #endif
4805
4806         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4807         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, false_bb);
4808
4809         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4810 #ifndef DISABLE_REMOTING
4811                 NEW_BBLOCK (cfg, interface_fail_bb);
4812 #endif
4813
4814                 tmp_reg = alloc_preg (cfg);
4815                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4816 #ifndef DISABLE_REMOTING
4817                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, true_bb);
4818                 MONO_START_BB (cfg, interface_fail_bb);
4819                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4820                 
4821                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, false_bb);
4822
4823                 tmp_reg = alloc_preg (cfg);
4824                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4825                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4826                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false2_bb);                
4827 #else
4828                 mini_emit_iface_cast (cfg, tmp_reg, klass, false_bb, true_bb);
4829 #endif
4830         } else {
4831 #ifndef DISABLE_REMOTING
4832                 tmp_reg = alloc_preg (cfg);
4833                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4834                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4835
4836                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4837                 tmp_reg = alloc_preg (cfg);
4838                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4839                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4840
4841                 tmp_reg = alloc_preg (cfg);             
4842                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4843                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4844                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4845                 
4846                 mini_emit_isninst_cast (cfg, klass_reg, klass, false2_bb, true_bb);
4847                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false2_bb);
4848
4849                 MONO_START_BB (cfg, no_proxy_bb);
4850
4851                 mini_emit_isninst_cast (cfg, klass_reg, klass, false_bb, true_bb);
4852 #else
4853                 g_error ("transparent proxy support is disabled while trying to JIT code that uses it");
4854 #endif
4855         }
4856
4857         MONO_START_BB (cfg, false_bb);
4858
4859         MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4860         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4861
4862 #ifndef DISABLE_REMOTING
4863         MONO_START_BB (cfg, false2_bb);
4864
4865         MONO_EMIT_NEW_ICONST (cfg, dreg, 2);
4866         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4867 #endif
4868
4869         MONO_START_BB (cfg, true_bb);
4870
4871         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4872
4873         MONO_START_BB (cfg, end_bb);
4874
4875         /* FIXME: */
4876         MONO_INST_NEW (cfg, ins, OP_ICONST);
4877         ins->dreg = dreg;
4878         ins->type = STACK_I4;
4879
4880         return ins;
4881 }
4882
4883 static MonoInst*
4884 handle_ccastclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4885 {
4886         /* This opcode takes as input an object reference and a class, and returns:
4887         0) if the object is an instance of the class,
4888         1) if the object is a proxy whose type cannot be determined
4889         an InvalidCastException exception is thrown otherwhise*/
4890         
4891         MonoInst *ins;
4892 #ifndef DISABLE_REMOTING
4893         MonoBasicBlock *end_bb, *ok_result_bb, *no_proxy_bb, *interface_fail_bb, *fail_1_bb;
4894 #else
4895         MonoBasicBlock *ok_result_bb;
4896 #endif
4897         int obj_reg = src->dreg;
4898         int dreg = alloc_ireg (cfg);
4899         int tmp_reg = alloc_preg (cfg);
4900
4901 #ifndef DISABLE_REMOTING
4902         int klass_reg = alloc_preg (cfg);
4903         NEW_BBLOCK (cfg, end_bb);
4904 #endif
4905
4906         NEW_BBLOCK (cfg, ok_result_bb);
4907
4908         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4909         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, ok_result_bb);
4910
4911         save_cast_details (cfg, klass, obj_reg, FALSE);
4912
4913         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4914 #ifndef DISABLE_REMOTING
4915                 NEW_BBLOCK (cfg, interface_fail_bb);
4916         
4917                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4918                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, ok_result_bb);
4919                 MONO_START_BB (cfg, interface_fail_bb);
4920                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4921
4922                 mini_emit_class_check (cfg, klass_reg, mono_defaults.transparent_proxy_class);
4923
4924                 tmp_reg = alloc_preg (cfg);             
4925                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4926                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4927                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
4928                 
4929                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4930                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4931 #else
4932                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4933                 mini_emit_iface_cast (cfg, tmp_reg, klass, NULL, NULL);
4934                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, ok_result_bb);
4935 #endif
4936         } else {
4937 #ifndef DISABLE_REMOTING
4938                 NEW_BBLOCK (cfg, no_proxy_bb);
4939
4940                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4941                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4942                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4943
4944                 tmp_reg = alloc_preg (cfg);
4945                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4946                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4947
4948                 tmp_reg = alloc_preg (cfg);
4949                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4950                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4951                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4952
4953                 NEW_BBLOCK (cfg, fail_1_bb);
4954                 
4955                 mini_emit_isninst_cast (cfg, klass_reg, klass, fail_1_bb, ok_result_bb);
4956
4957                 MONO_START_BB (cfg, fail_1_bb);
4958
4959                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4960                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4961
4962                 MONO_START_BB (cfg, no_proxy_bb);
4963
4964                 mini_emit_castclass (cfg, obj_reg, klass_reg, klass, ok_result_bb);
4965 #else
4966                 g_error ("Transparent proxy support is disabled while trying to JIT code that uses it");
4967 #endif
4968         }
4969
4970         MONO_START_BB (cfg, ok_result_bb);
4971
4972         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4973
4974 #ifndef DISABLE_REMOTING
4975         MONO_START_BB (cfg, end_bb);
4976 #endif
4977
4978         /* FIXME: */
4979         MONO_INST_NEW (cfg, ins, OP_ICONST);
4980         ins->dreg = dreg;
4981         ins->type = STACK_I4;
4982
4983         return ins;
4984 }
4985
4986 static G_GNUC_UNUSED MonoInst*
4987 handle_enum_has_flag (MonoCompile *cfg, MonoClass *klass, MonoInst *enum_this, MonoInst *enum_flag)
4988 {
4989         MonoType *enum_type = mono_type_get_underlying_type (&klass->byval_arg);
4990         guint32 load_opc = mono_type_to_load_membase (cfg, enum_type);
4991         gboolean is_i4;
4992
4993         switch (enum_type->type) {
4994         case MONO_TYPE_I8:
4995         case MONO_TYPE_U8:
4996 #if SIZEOF_REGISTER == 8
4997         case MONO_TYPE_I:
4998         case MONO_TYPE_U:
4999 #endif
5000                 is_i4 = FALSE;
5001                 break;
5002         default:
5003                 is_i4 = TRUE;
5004                 break;
5005         }
5006
5007         {
5008                 MonoInst *load, *and_, *cmp, *ceq;
5009                 int enum_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
5010                 int and_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
5011                 int dest_reg = alloc_ireg (cfg);
5012
5013                 EMIT_NEW_LOAD_MEMBASE (cfg, load, load_opc, enum_reg, enum_this->dreg, 0);
5014                 EMIT_NEW_BIALU (cfg, and_, is_i4 ? OP_IAND : OP_LAND, and_reg, enum_reg, enum_flag->dreg);
5015                 EMIT_NEW_BIALU (cfg, cmp, is_i4 ? OP_ICOMPARE : OP_LCOMPARE, -1, and_reg, enum_flag->dreg);
5016                 EMIT_NEW_UNALU (cfg, ceq, is_i4 ? OP_ICEQ : OP_LCEQ, dest_reg, -1);
5017
5018                 ceq->type = STACK_I4;
5019
5020                 if (!is_i4) {
5021                         load = mono_decompose_opcode (cfg, load);
5022                         and_ = mono_decompose_opcode (cfg, and_);
5023                         cmp = mono_decompose_opcode (cfg, cmp);
5024                         ceq = mono_decompose_opcode (cfg, ceq);
5025                 }
5026
5027                 return ceq;
5028         }
5029 }
5030
5031 /*
5032  * Returns NULL and set the cfg exception on error.
5033  */
5034 static G_GNUC_UNUSED MonoInst*
5035 handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, MonoMethod *method, int context_used, gboolean virtual_)
5036 {
5037         MonoInst *ptr;
5038         int dreg;
5039         gpointer trampoline;
5040         MonoInst *obj, *method_ins, *tramp_ins;
5041         MonoDomain *domain;
5042         guint8 **code_slot;
5043
5044         if (virtual_ && !cfg->llvm_only) {
5045                 MonoMethod *invoke = mono_get_delegate_invoke (klass);
5046                 g_assert (invoke);
5047
5048                 if (!mono_get_delegate_virtual_invoke_impl (mono_method_signature (invoke), context_used ? NULL : method))
5049                         return NULL;
5050         }
5051
5052         obj = handle_alloc (cfg, klass, FALSE, mono_class_check_context_used (klass));
5053         if (!obj)
5054                 return NULL;
5055
5056         /* Inline the contents of mono_delegate_ctor */
5057
5058         /* Set target field */
5059         /* Optimize away setting of NULL target */
5060         if (!(target->opcode == OP_PCONST && target->inst_p0 == 0)) {
5061                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target), target->dreg);
5062                 if (cfg->gen_write_barriers) {
5063                         dreg = alloc_preg (cfg);
5064                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target));
5065                         emit_write_barrier (cfg, ptr, target);
5066                 }
5067         }
5068
5069         /* Set method field */
5070         method_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
5071         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method), method_ins->dreg);
5072
5073         /* 
5074          * To avoid looking up the compiled code belonging to the target method
5075          * in mono_delegate_trampoline (), we allocate a per-domain memory slot to
5076          * store it, and we fill it after the method has been compiled.
5077          */
5078         if (!method->dynamic && !(cfg->opt & MONO_OPT_SHARED)) {
5079                 MonoInst *code_slot_ins;
5080
5081                 if (context_used) {
5082                         code_slot_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD_DELEGATE_CODE);
5083                 } else {
5084                         domain = mono_domain_get ();
5085                         mono_domain_lock (domain);
5086                         if (!domain_jit_info (domain)->method_code_hash)
5087                                 domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
5088                         code_slot = (guint8 **)g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, method);
5089                         if (!code_slot) {
5090                                 code_slot = (guint8 **)mono_domain_alloc0 (domain, sizeof (gpointer));
5091                                 g_hash_table_insert (domain_jit_info (domain)->method_code_hash, method, code_slot);
5092                         }
5093                         mono_domain_unlock (domain);
5094
5095                         code_slot_ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_METHOD_CODE_SLOT, method);
5096                 }
5097                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_code), code_slot_ins->dreg);                
5098         }
5099
5100         if (cfg->llvm_only) {
5101                 MonoInst *args [16];
5102
5103                 if (virtual_) {
5104                         args [0] = obj;
5105                         args [1] = target;
5106                         args [2] = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
5107                         mono_emit_jit_icall (cfg, mono_llvmonly_init_delegate_virtual, args);
5108                 } else {
5109                         args [0] = obj;
5110                         mono_emit_jit_icall (cfg, mono_llvmonly_init_delegate, args);
5111                 }
5112
5113                 return obj;
5114         }
5115
5116         if (cfg->compile_aot) {
5117                 MonoDelegateClassMethodPair *del_tramp;
5118
5119                 del_tramp = (MonoDelegateClassMethodPair *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoDelegateClassMethodPair));
5120                 del_tramp->klass = klass;
5121                 del_tramp->method = context_used ? NULL : method;
5122                 del_tramp->is_virtual = virtual_;
5123                 EMIT_NEW_AOTCONST (cfg, tramp_ins, MONO_PATCH_INFO_DELEGATE_TRAMPOLINE, del_tramp);
5124         } else {
5125                 if (virtual_)
5126                         trampoline = mono_create_delegate_virtual_trampoline (cfg->domain, klass, context_used ? NULL : method);
5127                 else
5128                         trampoline = mono_create_delegate_trampoline_info (cfg->domain, klass, context_used ? NULL : method);
5129                 EMIT_NEW_PCONST (cfg, tramp_ins, trampoline);
5130         }
5131
5132         /* Set invoke_impl field */
5133         if (virtual_) {
5134                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), tramp_ins->dreg);
5135         } else {
5136                 dreg = alloc_preg (cfg);
5137                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, invoke_impl));
5138                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), dreg);
5139
5140                 dreg = alloc_preg (cfg);
5141                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, method_ptr));
5142                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr), dreg);
5143         }
5144
5145         dreg = alloc_preg (cfg);
5146         MONO_EMIT_NEW_ICONST (cfg, dreg, virtual_ ? 1 : 0);
5147         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_is_virtual), dreg);
5148
5149         /* All the checks which are in mono_delegate_ctor () are done by the delegate trampoline */
5150
5151         return obj;
5152 }
5153
5154 static MonoInst*
5155 handle_array_new (MonoCompile *cfg, int rank, MonoInst **sp, unsigned char *ip)
5156 {
5157         MonoJitICallInfo *info;
5158
5159         /* Need to register the icall so it gets an icall wrapper */
5160         info = mono_get_array_new_va_icall (rank);
5161
5162         cfg->flags |= MONO_CFG_HAS_VARARGS;
5163
5164         /* mono_array_new_va () needs a vararg calling convention */
5165         cfg->exception_message = g_strdup ("array-new");
5166         cfg->disable_llvm = TRUE;
5167
5168         /* FIXME: This uses info->sig, but it should use the signature of the wrapper */
5169         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, sp);
5170 }
5171
5172 /*
5173  * handle_constrained_gsharedvt_call:
5174  *
5175  *   Handle constrained calls where the receiver is a gsharedvt type.
5176  * Return the instruction representing the call. Set the cfg exception on failure.
5177  */
5178 static MonoInst*
5179 handle_constrained_gsharedvt_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp, MonoClass *constrained_class,
5180                                                                    gboolean *ref_emit_widen)
5181 {
5182         MonoInst *ins = NULL;
5183         gboolean emit_widen = *ref_emit_widen;
5184
5185         /*
5186          * Constrained calls need to behave differently at runtime dependending on whenever the receiver is instantiated as ref type or as a vtype.
5187          * 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
5188          * pack the arguments into an array, and do the rest of the work in in an icall.
5189          */
5190         if (((cmethod->klass == mono_defaults.object_class) || (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) || (!cmethod->klass->valuetype && cmethod->klass->image != mono_defaults.corlib)) &&
5191                 (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)) &&
5192                 (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]))))) {
5193                 MonoInst *args [16];
5194
5195                 /*
5196                  * This case handles calls to
5197                  * - object:ToString()/Equals()/GetHashCode(),
5198                  * - System.IComparable<T>:CompareTo()
5199                  * - System.IEquatable<T>:Equals ()
5200                  * plus some simple interface calls enough to support AsyncTaskMethodBuilder.
5201                  */
5202
5203                 args [0] = sp [0];
5204                 if (mono_method_check_context_used (cmethod))
5205                         args [1] = emit_get_rgctx_method (cfg, mono_method_check_context_used (cmethod), cmethod, MONO_RGCTX_INFO_METHOD);
5206                 else
5207                         EMIT_NEW_METHODCONST (cfg, args [1], cmethod);
5208                 args [2] = emit_get_rgctx_klass (cfg, mono_class_check_context_used (constrained_class), constrained_class, MONO_RGCTX_INFO_KLASS);
5209
5210                 /* !fsig->hasthis is for the wrapper for the Object.GetType () icall */
5211                 if (fsig->hasthis && fsig->param_count) {
5212                         /* Pass the arguments using a localloc-ed array using the format expected by runtime_invoke () */
5213                         MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
5214                         ins->dreg = alloc_preg (cfg);
5215                         ins->inst_imm = fsig->param_count * sizeof (mgreg_t);
5216                         MONO_ADD_INS (cfg->cbb, ins);
5217                         args [4] = ins;
5218
5219                         if (mini_is_gsharedvt_type (fsig->params [0])) {
5220                                 int addr_reg, deref_arg_reg;
5221
5222                                 ins = emit_get_gsharedvt_info_klass (cfg, mono_class_from_mono_type (fsig->params [0]), MONO_RGCTX_INFO_CLASS_BOX_TYPE);
5223                                 deref_arg_reg = alloc_preg (cfg);
5224                                 /* deref_arg = BOX_TYPE != MONO_GSHAREDVT_BOX_TYPE_VTYPE */
5225                                 EMIT_NEW_BIALU_IMM (cfg, args [3], OP_ISUB_IMM, deref_arg_reg, ins->dreg, 1);
5226
5227                                 EMIT_NEW_VARLOADA_VREG (cfg, ins, sp [1]->dreg, fsig->params [0]);
5228                                 addr_reg = ins->dreg;
5229                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, addr_reg);
5230                         } else {
5231                                 EMIT_NEW_ICONST (cfg, args [3], 0);
5232                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, sp [1]->dreg);
5233                         }
5234                 } else {
5235                         EMIT_NEW_ICONST (cfg, args [3], 0);
5236                         EMIT_NEW_ICONST (cfg, args [4], 0);
5237                 }
5238                 ins = mono_emit_jit_icall (cfg, mono_gsharedvt_constrained_call, args);
5239                 emit_widen = FALSE;
5240
5241                 if (mini_is_gsharedvt_type (fsig->ret)) {
5242                         ins = handle_unbox_gsharedvt (cfg, mono_class_from_mono_type (fsig->ret), ins);
5243                 } else if (MONO_TYPE_IS_PRIMITIVE (fsig->ret) || MONO_TYPE_ISSTRUCT (fsig->ret)) {
5244                         MonoInst *add;
5245
5246                         /* Unbox */
5247                         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), ins->dreg, sizeof (MonoObject));
5248                         MONO_ADD_INS (cfg->cbb, add);
5249                         /* Load value */
5250                         NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, add->dreg, 0);
5251                         MONO_ADD_INS (cfg->cbb, ins);
5252                         /* ins represents the call result */
5253                 }
5254         } else {
5255                 GSHAREDVT_FAILURE (CEE_CALLVIRT);
5256         }
5257
5258         *ref_emit_widen = emit_widen;
5259
5260         return ins;
5261
5262  exception_exit:
5263         return NULL;
5264 }
5265
5266 static void
5267 mono_emit_load_got_addr (MonoCompile *cfg)
5268 {
5269         MonoInst *getaddr, *dummy_use;
5270
5271         if (!cfg->got_var || cfg->got_var_allocated)
5272                 return;
5273
5274         MONO_INST_NEW (cfg, getaddr, OP_LOAD_GOTADDR);
5275         getaddr->cil_code = cfg->header->code;
5276         getaddr->dreg = cfg->got_var->dreg;
5277
5278         /* Add it to the start of the first bblock */
5279         if (cfg->bb_entry->code) {
5280                 getaddr->next = cfg->bb_entry->code;
5281                 cfg->bb_entry->code = getaddr;
5282         }
5283         else
5284                 MONO_ADD_INS (cfg->bb_entry, getaddr);
5285
5286         cfg->got_var_allocated = TRUE;
5287
5288         /* 
5289          * Add a dummy use to keep the got_var alive, since real uses might
5290          * only be generated by the back ends.
5291          * Add it to end_bblock, so the variable's lifetime covers the whole
5292          * method.
5293          * It would be better to make the usage of the got var explicit in all
5294          * cases when the backend needs it (i.e. calls, throw etc.), so this
5295          * wouldn't be needed.
5296          */
5297         NEW_DUMMY_USE (cfg, dummy_use, cfg->got_var);
5298         MONO_ADD_INS (cfg->bb_exit, dummy_use);
5299 }
5300
5301 static int inline_limit;
5302 static gboolean inline_limit_inited;
5303
5304 static gboolean
5305 mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
5306 {
5307         MonoMethodHeaderSummary header;
5308         MonoVTable *vtable;
5309 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
5310         MonoMethodSignature *sig = mono_method_signature (method);
5311         int i;
5312 #endif
5313
5314         if (cfg->disable_inline)
5315                 return FALSE;
5316         if (cfg->gshared)
5317                 return FALSE;
5318
5319         if (cfg->inline_depth > 10)
5320                 return FALSE;
5321
5322         if (!mono_method_get_header_summary (method, &header))
5323                 return FALSE;
5324
5325         /*runtime, icall and pinvoke are checked by summary call*/
5326         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
5327             (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
5328             (mono_class_is_marshalbyref (method->klass)) ||
5329             header.has_clauses)
5330                 return FALSE;
5331
5332         /* also consider num_locals? */
5333         /* Do the size check early to avoid creating vtables */
5334         if (!inline_limit_inited) {
5335                 if (g_getenv ("MONO_INLINELIMIT"))
5336                         inline_limit = atoi (g_getenv ("MONO_INLINELIMIT"));
5337                 else
5338                         inline_limit = INLINE_LENGTH_LIMIT;
5339                 inline_limit_inited = TRUE;
5340         }
5341         if (header.code_size >= inline_limit && !(method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))
5342                 return FALSE;
5343
5344         /*
5345          * if we can initialize the class of the method right away, we do,
5346          * otherwise we don't allow inlining if the class needs initialization,
5347          * since it would mean inserting a call to mono_runtime_class_init()
5348          * inside the inlined code
5349          */
5350         if (!(cfg->opt & MONO_OPT_SHARED)) {
5351                 /* The AggressiveInlining hint is a good excuse to force that cctor to run. */
5352                 if (method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING) {
5353                         vtable = mono_class_vtable (cfg->domain, method->klass);
5354                         if (!vtable)
5355                                 return FALSE;
5356                         if (!cfg->compile_aot) {
5357                                 MonoError error;
5358                                 if (!mono_runtime_class_init_full (vtable, &error)) {
5359                                         mono_error_cleanup (&error);
5360                                         return FALSE;
5361                                 }
5362                         }
5363                 } else if (method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
5364                         if (cfg->run_cctors && method->klass->has_cctor) {
5365                                 /*FIXME it would easier and lazier to just use mono_class_try_get_vtable */
5366                                 if (!method->klass->runtime_info)
5367                                         /* No vtable created yet */
5368                                         return FALSE;
5369                                 vtable = mono_class_vtable (cfg->domain, method->klass);
5370                                 if (!vtable)
5371                                         return FALSE;
5372                                 /* This makes so that inline cannot trigger */
5373                                 /* .cctors: too many apps depend on them */
5374                                 /* running with a specific order... */
5375                                 if (! vtable->initialized)
5376                                         return FALSE;
5377                                 MonoError error;
5378                                 if (!mono_runtime_class_init_full (vtable, &error)) {
5379                                         mono_error_cleanup (&error);
5380                                         return FALSE;
5381                                 }
5382                         }
5383                 } else if (mono_class_needs_cctor_run (method->klass, NULL)) {
5384                         if (!method->klass->runtime_info)
5385                                 /* No vtable created yet */
5386                                 return FALSE;
5387                         vtable = mono_class_vtable (cfg->domain, method->klass);
5388                         if (!vtable)
5389                                 return FALSE;
5390                         if (!vtable->initialized)
5391                                 return FALSE;
5392                 }
5393         } else {
5394                 /* 
5395                  * If we're compiling for shared code
5396                  * the cctor will need to be run at aot method load time, for example,
5397                  * or at the end of the compilation of the inlining method.
5398                  */
5399                 if (mono_class_needs_cctor_run (method->klass, NULL) && !((method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)))
5400                         return FALSE;
5401         }
5402
5403 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
5404         if (mono_arch_is_soft_float ()) {
5405                 /* FIXME: */
5406                 if (sig->ret && sig->ret->type == MONO_TYPE_R4)
5407                         return FALSE;
5408                 for (i = 0; i < sig->param_count; ++i)
5409                         if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_R4)
5410                                 return FALSE;
5411         }
5412 #endif
5413
5414         if (g_list_find (cfg->dont_inline, method))
5415                 return FALSE;
5416
5417         return TRUE;
5418 }
5419
5420 static gboolean
5421 mini_field_access_needs_cctor_run (MonoCompile *cfg, MonoMethod *method, MonoClass *klass, MonoVTable *vtable)
5422 {
5423         if (!cfg->compile_aot) {
5424                 g_assert (vtable);
5425                 if (vtable->initialized)
5426                         return FALSE;
5427         }
5428
5429         if (klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
5430                 if (cfg->method == method)
5431                         return FALSE;
5432         }
5433
5434         if (!mono_class_needs_cctor_run (klass, method))
5435                 return FALSE;
5436
5437         if (! (method->flags & METHOD_ATTRIBUTE_STATIC) && (klass == method->klass))
5438                 /* The initialization is already done before the method is called */
5439                 return FALSE;
5440
5441         return TRUE;
5442 }
5443
5444 static MonoInst*
5445 mini_emit_ldelema_1_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index, gboolean bcheck)
5446 {
5447         MonoInst *ins;
5448         guint32 size;
5449         int mult_reg, add_reg, array_reg, index_reg, index2_reg;
5450         int context_used;
5451
5452         if (mini_is_gsharedvt_variable_klass (klass)) {
5453                 size = -1;
5454         } else {
5455                 mono_class_init (klass);
5456                 size = mono_class_array_element_size (klass);
5457         }
5458
5459         mult_reg = alloc_preg (cfg);
5460         array_reg = arr->dreg;
5461         index_reg = index->dreg;
5462
5463 #if SIZEOF_REGISTER == 8
5464         /* The array reg is 64 bits but the index reg is only 32 */
5465         if (COMPILE_LLVM (cfg)) {
5466                 /* Not needed */
5467                 index2_reg = index_reg;
5468         } else {
5469                 index2_reg = alloc_preg (cfg);
5470                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index2_reg, index_reg);
5471         }
5472 #else
5473         if (index->type == STACK_I8) {
5474                 index2_reg = alloc_preg (cfg);
5475                 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I4, index2_reg, index_reg);
5476         } else {
5477                 index2_reg = index_reg;
5478         }
5479 #endif
5480
5481         if (bcheck)
5482                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index2_reg);
5483
5484 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5485         if (size == 1 || size == 2 || size == 4 || size == 8) {
5486                 static const int fast_log2 [] = { 1, 0, 1, -1, 2, -1, -1, -1, 3 };
5487
5488                 EMIT_NEW_X86_LEA (cfg, ins, array_reg, index2_reg, fast_log2 [size], MONO_STRUCT_OFFSET (MonoArray, vector));
5489                 ins->klass = mono_class_get_element_class (klass);
5490                 ins->type = STACK_MP;
5491
5492                 return ins;
5493         }
5494 #endif          
5495
5496         add_reg = alloc_ireg_mp (cfg);
5497
5498         if (size == -1) {
5499                 MonoInst *rgctx_ins;
5500
5501                 /* gsharedvt */
5502                 g_assert (cfg->gshared);
5503                 context_used = mini_class_check_context_used (cfg, klass);
5504                 g_assert (context_used);
5505                 rgctx_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE);
5506                 MONO_EMIT_NEW_BIALU (cfg, OP_IMUL, mult_reg, index2_reg, rgctx_ins->dreg);
5507         } else {
5508                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MUL_IMM, mult_reg, index2_reg, size);
5509         }
5510         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, array_reg, mult_reg);
5511         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
5512         ins->klass = mono_class_get_element_class (klass);
5513         ins->type = STACK_MP;
5514         MONO_ADD_INS (cfg->cbb, ins);
5515
5516         return ins;
5517 }
5518
5519 static MonoInst*
5520 mini_emit_ldelema_2_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index_ins1, MonoInst *index_ins2)
5521 {
5522         int bounds_reg = alloc_preg (cfg);
5523         int add_reg = alloc_ireg_mp (cfg);
5524         int mult_reg = alloc_preg (cfg);
5525         int mult2_reg = alloc_preg (cfg);
5526         int low1_reg = alloc_preg (cfg);
5527         int low2_reg = alloc_preg (cfg);
5528         int high1_reg = alloc_preg (cfg);
5529         int high2_reg = alloc_preg (cfg);
5530         int realidx1_reg = alloc_preg (cfg);
5531         int realidx2_reg = alloc_preg (cfg);
5532         int sum_reg = alloc_preg (cfg);
5533         int index1, index2, tmpreg;
5534         MonoInst *ins;
5535         guint32 size;
5536
5537         mono_class_init (klass);
5538         size = mono_class_array_element_size (klass);
5539
5540         index1 = index_ins1->dreg;
5541         index2 = index_ins2->dreg;
5542
5543 #if SIZEOF_REGISTER == 8
5544         /* The array reg is 64 bits but the index reg is only 32 */
5545         if (COMPILE_LLVM (cfg)) {
5546                 /* Not needed */
5547         } else {
5548                 tmpreg = alloc_preg (cfg);
5549                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index1);
5550                 index1 = tmpreg;
5551                 tmpreg = alloc_preg (cfg);
5552                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index2);
5553                 index2 = tmpreg;
5554         }
5555 #else
5556         // FIXME: Do we need to do something here for i8 indexes, like in ldelema_1_ins ?
5557         tmpreg = -1;
5558 #endif
5559
5560         /* range checking */
5561         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, 
5562                                        arr->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
5563
5564         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low1_reg, 
5565                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5566         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx1_reg, index1, low1_reg);
5567         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high1_reg, 
5568                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5569         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high1_reg, realidx1_reg);
5570         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
5571
5572         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low2_reg, 
5573                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5574         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx2_reg, index2, low2_reg);
5575         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high2_reg, 
5576                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5577         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high2_reg, realidx2_reg);
5578         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
5579
5580         MONO_EMIT_NEW_BIALU (cfg, OP_PMUL, mult_reg, high2_reg, realidx1_reg);
5581         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, mult_reg, realidx2_reg);
5582         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PMUL_IMM, mult2_reg, sum_reg, size);
5583         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult2_reg, arr->dreg);
5584         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
5585
5586         ins->type = STACK_MP;
5587         ins->klass = klass;
5588         MONO_ADD_INS (cfg->cbb, ins);
5589
5590         return ins;
5591 }
5592
5593 static MonoInst*
5594 mini_emit_ldelema_ins (MonoCompile *cfg, MonoMethod *cmethod, MonoInst **sp, unsigned char *ip, gboolean is_set)
5595 {
5596         int rank;
5597         MonoInst *addr;
5598         MonoMethod *addr_method;
5599         int element_size;
5600         MonoClass *eclass = cmethod->klass->element_class;
5601
5602         rank = mono_method_signature (cmethod)->param_count - (is_set? 1: 0);
5603
5604         if (rank == 1)
5605                 return mini_emit_ldelema_1_ins (cfg, eclass, sp [0], sp [1], TRUE);
5606
5607         /* emit_ldelema_2 depends on OP_LMUL */
5608         if (!cfg->backend->emulate_mul_div && rank == 2 && (cfg->opt & MONO_OPT_INTRINS) && !mini_is_gsharedvt_variable_klass (eclass)) {
5609                 return mini_emit_ldelema_2_ins (cfg, eclass, sp [0], sp [1], sp [2]);
5610         }
5611
5612         if (mini_is_gsharedvt_variable_klass (eclass))
5613                 element_size = 0;
5614         else
5615                 element_size = mono_class_array_element_size (eclass);
5616         addr_method = mono_marshal_get_array_address (rank, element_size);
5617         addr = mono_emit_method_call (cfg, addr_method, sp, NULL);
5618
5619         return addr;
5620 }
5621
5622 static MonoBreakPolicy
5623 always_insert_breakpoint (MonoMethod *method)
5624 {
5625         return MONO_BREAK_POLICY_ALWAYS;
5626 }
5627
5628 static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
5629
5630 /**
5631  * mono_set_break_policy:
5632  * policy_callback: the new callback function
5633  *
5634  * Allow embedders to decide wherther to actually obey breakpoint instructions
5635  * (both break IL instructions and Debugger.Break () method calls), for example
5636  * to not allow an app to be aborted by a perfectly valid IL opcode when executing
5637  * untrusted or semi-trusted code.
5638  *
5639  * @policy_callback will be called every time a break point instruction needs to
5640  * be inserted with the method argument being the method that calls Debugger.Break()
5641  * or has the IL break instruction. The callback should return #MONO_BREAK_POLICY_NEVER
5642  * if it wants the breakpoint to not be effective in the given method.
5643  * #MONO_BREAK_POLICY_ALWAYS is the default.
5644  */
5645 void
5646 mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
5647 {
5648         if (policy_callback)
5649                 break_policy_func = policy_callback;
5650         else
5651                 break_policy_func = always_insert_breakpoint;
5652 }
5653
5654 static gboolean
5655 should_insert_brekpoint (MonoMethod *method) {
5656         switch (break_policy_func (method)) {
5657         case MONO_BREAK_POLICY_ALWAYS:
5658                 return TRUE;
5659         case MONO_BREAK_POLICY_NEVER:
5660                 return FALSE;
5661         case MONO_BREAK_POLICY_ON_DBG:
5662                 g_warning ("mdb no longer supported");
5663                 return FALSE;
5664         default:
5665                 g_warning ("Incorrect value returned from break policy callback");
5666                 return FALSE;
5667         }
5668 }
5669
5670 /* optimize the simple GetGenericValueImpl/SetGenericValueImpl generic icalls */
5671 static MonoInst*
5672 emit_array_generic_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
5673 {
5674         MonoInst *addr, *store, *load;
5675         MonoClass *eklass = mono_class_from_mono_type (fsig->params [2]);
5676
5677         /* the bounds check is already done by the callers */
5678         addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
5679         if (is_set) {
5680                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, args [2]->dreg, 0);
5681                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, addr->dreg, 0, load->dreg);
5682                 if (mini_type_is_reference (fsig->params [2]))
5683                         emit_write_barrier (cfg, addr, load);
5684         } else {
5685                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, addr->dreg, 0);
5686                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, args [2]->dreg, 0, load->dreg);
5687         }
5688         return store;
5689 }
5690
5691
5692 static gboolean
5693 generic_class_is_reference_type (MonoCompile *cfg, MonoClass *klass)
5694 {
5695         return mini_type_is_reference (&klass->byval_arg);
5696 }
5697
5698 static MonoInst*
5699 emit_array_store (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, gboolean safety_checks)
5700 {
5701         if (safety_checks && generic_class_is_reference_type (cfg, klass) &&
5702                 !(sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL)) {
5703                 MonoClass *obj_array = mono_array_class_get_cached (mono_defaults.object_class, 1);
5704                 MonoMethod *helper = mono_marshal_get_virtual_stelemref (obj_array);
5705                 MonoInst *iargs [3];
5706
5707                 if (!helper->slot)
5708                         mono_class_setup_vtable (obj_array);
5709                 g_assert (helper->slot);
5710
5711                 if (sp [0]->type != STACK_OBJ)
5712                         return NULL;
5713                 if (sp [2]->type != STACK_OBJ)
5714                         return NULL;
5715
5716                 iargs [2] = sp [2];
5717                 iargs [1] = sp [1];
5718                 iargs [0] = sp [0];
5719
5720                 return mono_emit_method_call (cfg, helper, iargs, sp [0]);
5721         } else {
5722                 MonoInst *ins;
5723
5724                 if (mini_is_gsharedvt_variable_klass (klass)) {
5725                         MonoInst *addr;
5726
5727                         // FIXME-VT: OP_ICONST optimization
5728                         addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
5729                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5730                         ins->opcode = OP_STOREV_MEMBASE;
5731                 } else if (sp [1]->opcode == OP_ICONST) {
5732                         int array_reg = sp [0]->dreg;
5733                         int index_reg = sp [1]->dreg;
5734                         int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
5735
5736                         if (SIZEOF_REGISTER == 8 && COMPILE_LLVM (cfg))
5737                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, index_reg, index_reg);
5738
5739                         if (safety_checks)
5740                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
5741                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset, sp [2]->dreg);
5742                 } else {
5743                         MonoInst *addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], safety_checks);
5744                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5745                         if (generic_class_is_reference_type (cfg, klass))
5746                                 emit_write_barrier (cfg, addr, sp [2]);
5747                 }
5748                 return ins;
5749         }
5750 }
5751
5752 static MonoInst*
5753 emit_array_unsafe_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
5754 {
5755         MonoClass *eklass;
5756         
5757         if (is_set)
5758                 eklass = mono_class_from_mono_type (fsig->params [2]);
5759         else
5760                 eklass = mono_class_from_mono_type (fsig->ret);
5761
5762         if (is_set) {
5763                 return emit_array_store (cfg, eklass, args, FALSE);
5764         } else {
5765                 MonoInst *ins, *addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
5766                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &eklass->byval_arg, addr->dreg, 0);
5767                 return ins;
5768         }
5769 }
5770
5771 static gboolean
5772 is_unsafe_mov_compatible (MonoCompile *cfg, MonoClass *param_klass, MonoClass *return_klass)
5773 {
5774         uint32_t align;
5775         int param_size, return_size;
5776
5777         param_klass = mono_class_from_mono_type (mini_get_underlying_type (&param_klass->byval_arg));
5778         return_klass = mono_class_from_mono_type (mini_get_underlying_type (&return_klass->byval_arg));
5779
5780         if (cfg->verbose_level > 3)
5781                 printf ("[UNSAFE-MOV-INTRISIC] %s <- %s\n", return_klass->name, param_klass->name);
5782
5783         //Don't allow mixing reference types with value types
5784         if (param_klass->valuetype != return_klass->valuetype) {
5785                 if (cfg->verbose_level > 3)
5786                         printf ("[UNSAFE-MOV-INTRISIC]\tone of the args is a valuetype and the other is not\n");
5787                 return FALSE;
5788         }
5789
5790         if (!param_klass->valuetype) {
5791                 if (cfg->verbose_level > 3)
5792                         printf ("[UNSAFE-MOV-INTRISIC]\targs are reference types\n");
5793                 return TRUE;
5794         }
5795
5796         //That are blitable
5797         if (param_klass->has_references || return_klass->has_references)
5798                 return FALSE;
5799
5800         /* Avoid mixing structs and primitive types/enums, they need to be handled differently in the JIT */
5801         if ((MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && !MONO_TYPE_ISSTRUCT (&return_klass->byval_arg)) ||
5802                 (!MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && MONO_TYPE_ISSTRUCT (&return_klass->byval_arg))) {
5803                         if (cfg->verbose_level > 3)
5804                                 printf ("[UNSAFE-MOV-INTRISIC]\tmixing structs and scalars\n");
5805                 return FALSE;
5806         }
5807
5808         if (param_klass->byval_arg.type == MONO_TYPE_R4 || param_klass->byval_arg.type == MONO_TYPE_R8 ||
5809                 return_klass->byval_arg.type == MONO_TYPE_R4 || return_klass->byval_arg.type == MONO_TYPE_R8) {
5810                 if (cfg->verbose_level > 3)
5811                         printf ("[UNSAFE-MOV-INTRISIC]\tfloat or double are not supported\n");
5812                 return FALSE;
5813         }
5814
5815         param_size = mono_class_value_size (param_klass, &align);
5816         return_size = mono_class_value_size (return_klass, &align);
5817
5818         //We can do it if sizes match
5819         if (param_size == return_size) {
5820                 if (cfg->verbose_level > 3)
5821                         printf ("[UNSAFE-MOV-INTRISIC]\tsame size\n");
5822                 return TRUE;
5823         }
5824
5825         //No simple way to handle struct if sizes don't match
5826         if (MONO_TYPE_ISSTRUCT (&param_klass->byval_arg)) {
5827                 if (cfg->verbose_level > 3)
5828                         printf ("[UNSAFE-MOV-INTRISIC]\tsize mismatch and type is a struct\n");
5829                 return FALSE;
5830         }
5831
5832         /*
5833          * Same reg size category.
5834          * A quick note on why we don't require widening here.
5835          * The intrinsic is "R Array.UnsafeMov<S,R> (S s)".
5836          *
5837          * Since the source value comes from a function argument, the JIT will already have
5838          * the value in a VREG and performed any widening needed before (say, when loading from a field).
5839          */
5840         if (param_size <= 4 && return_size <= 4) {
5841                 if (cfg->verbose_level > 3)
5842                         printf ("[UNSAFE-MOV-INTRISIC]\tsize mismatch but both are of the same reg class\n");
5843                 return TRUE;
5844         }
5845
5846         return FALSE;
5847 }
5848
5849 static MonoInst*
5850 emit_array_unsafe_mov (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args)
5851 {
5852         MonoClass *param_klass = mono_class_from_mono_type (fsig->params [0]);
5853         MonoClass *return_klass = mono_class_from_mono_type (fsig->ret);
5854
5855         if (mini_is_gsharedvt_variable_type (fsig->ret))
5856                 return NULL;
5857
5858         //Valuetypes that are semantically equivalent or numbers than can be widened to
5859         if (is_unsafe_mov_compatible (cfg, param_klass, return_klass))
5860                 return args [0];
5861
5862         //Arrays of valuetypes that are semantically equivalent
5863         if (param_klass->rank == 1 && return_klass->rank == 1 && is_unsafe_mov_compatible (cfg, param_klass->element_class, return_klass->element_class))
5864                 return args [0];
5865
5866         return NULL;
5867 }
5868
5869 static MonoInst*
5870 mini_emit_inst_for_ctor (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5871 {
5872 #ifdef MONO_ARCH_SIMD_INTRINSICS
5873         MonoInst *ins = NULL;
5874
5875         if (cfg->opt & MONO_OPT_SIMD) {
5876                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
5877                 if (ins)
5878                         return ins;
5879         }
5880 #endif
5881
5882         return mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
5883 }
5884
5885 static MonoInst*
5886 emit_memory_barrier (MonoCompile *cfg, int kind)
5887 {
5888         MonoInst *ins = NULL;
5889         MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
5890         MONO_ADD_INS (cfg->cbb, ins);
5891         ins->backend.memory_barrier_kind = kind;
5892
5893         return ins;
5894 }
5895
5896 static MonoInst*
5897 llvm_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5898 {
5899         MonoInst *ins = NULL;
5900         int opcode = 0;
5901
5902         /* The LLVM backend supports these intrinsics */
5903         if (cmethod->klass == mono_defaults.math_class) {
5904                 if (strcmp (cmethod->name, "Sin") == 0) {
5905                         opcode = OP_SIN;
5906                 } else if (strcmp (cmethod->name, "Cos") == 0) {
5907                         opcode = OP_COS;
5908                 } else if (strcmp (cmethod->name, "Sqrt") == 0) {
5909                         opcode = OP_SQRT;
5910                 } else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8) {
5911                         opcode = OP_ABS;
5912                 }
5913
5914                 if (opcode && fsig->param_count == 1) {
5915                         MONO_INST_NEW (cfg, ins, opcode);
5916                         ins->type = STACK_R8;
5917                         ins->dreg = mono_alloc_dreg (cfg, ins->type);
5918                         ins->sreg1 = args [0]->dreg;
5919                         MONO_ADD_INS (cfg->cbb, ins);
5920                 }
5921
5922                 opcode = 0;
5923                 if (cfg->opt & MONO_OPT_CMOV) {
5924                         if (strcmp (cmethod->name, "Min") == 0) {
5925                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5926                                         opcode = OP_IMIN;
5927                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5928                                         opcode = OP_IMIN_UN;
5929                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5930                                         opcode = OP_LMIN;
5931                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5932                                         opcode = OP_LMIN_UN;
5933                         } else if (strcmp (cmethod->name, "Max") == 0) {
5934                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5935                                         opcode = OP_IMAX;
5936                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5937                                         opcode = OP_IMAX_UN;
5938                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5939                                         opcode = OP_LMAX;
5940                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5941                                         opcode = OP_LMAX_UN;
5942                         }
5943                 }
5944
5945                 if (opcode && fsig->param_count == 2) {
5946                         MONO_INST_NEW (cfg, ins, opcode);
5947                         ins->type = fsig->params [0]->type == MONO_TYPE_I4 ? STACK_I4 : STACK_I8;
5948                         ins->dreg = mono_alloc_dreg (cfg, ins->type);
5949                         ins->sreg1 = args [0]->dreg;
5950                         ins->sreg2 = args [1]->dreg;
5951                         MONO_ADD_INS (cfg->cbb, ins);
5952                 }
5953         }
5954
5955         return ins;
5956 }
5957
5958 static MonoInst*
5959 mini_emit_inst_for_sharable_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5960 {
5961         if (cmethod->klass == mono_defaults.array_class) {
5962                 if (strcmp (cmethod->name, "UnsafeStore") == 0)
5963                         return emit_array_unsafe_access (cfg, fsig, args, TRUE);
5964                 else if (strcmp (cmethod->name, "UnsafeLoad") == 0)
5965                         return emit_array_unsafe_access (cfg, fsig, args, FALSE);
5966                 else if (strcmp (cmethod->name, "UnsafeMov") == 0)
5967                         return emit_array_unsafe_mov (cfg, fsig, args);
5968         }
5969
5970         return NULL;
5971 }
5972
5973 static MonoInst*
5974 mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5975 {
5976         MonoInst *ins = NULL;
5977
5978          MonoClass *runtime_helpers_class = mono_class_get_runtime_helpers_class ();
5979
5980         if (cmethod->klass == mono_defaults.string_class) {
5981                 if (strcmp (cmethod->name, "get_Chars") == 0 && fsig->param_count + fsig->hasthis == 2) {
5982                         int dreg = alloc_ireg (cfg);
5983                         int index_reg = alloc_preg (cfg);
5984                         int add_reg = alloc_preg (cfg);
5985
5986 #if SIZEOF_REGISTER == 8
5987                         if (COMPILE_LLVM (cfg)) {
5988                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, index_reg, args [1]->dreg);
5989                         } else {
5990                                 /* The array reg is 64 bits but the index reg is only 32 */
5991                                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index_reg, args [1]->dreg);
5992                         }
5993 #else
5994                         index_reg = args [1]->dreg;
5995 #endif  
5996                         MONO_EMIT_BOUNDS_CHECK (cfg, args [0]->dreg, MonoString, length, index_reg);
5997
5998 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5999                         EMIT_NEW_X86_LEA (cfg, ins, args [0]->dreg, index_reg, 1, MONO_STRUCT_OFFSET (MonoString, chars));
6000                         add_reg = ins->dreg;
6001                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
6002                                                                    add_reg, 0);
6003 #else
6004                         int mult_reg = alloc_preg (cfg);
6005                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, index_reg, 1);
6006                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
6007                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
6008                                                                    add_reg, MONO_STRUCT_OFFSET (MonoString, chars));
6009 #endif
6010                         type_from_op (cfg, ins, NULL, NULL);
6011                         return ins;
6012                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count + fsig->hasthis == 1) {
6013                         int dreg = alloc_ireg (cfg);
6014                         /* Decompose later to allow more optimizations */
6015                         EMIT_NEW_UNALU (cfg, ins, OP_STRLEN, dreg, args [0]->dreg);
6016                         ins->type = STACK_I4;
6017                         ins->flags |= MONO_INST_FAULT;
6018                         cfg->cbb->has_array_access = TRUE;
6019                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
6020
6021                         return ins;
6022                 } else 
6023                         return NULL;
6024         } else if (cmethod->klass == mono_defaults.object_class) {
6025                 if (strcmp (cmethod->name, "GetType") == 0 && fsig->param_count + fsig->hasthis == 1) {
6026                         int dreg = alloc_ireg_ref (cfg);
6027                         int vt_reg = alloc_preg (cfg);
6028                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vt_reg, args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
6029                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, vt_reg, MONO_STRUCT_OFFSET (MonoVTable, type));
6030                         type_from_op (cfg, ins, NULL, NULL);
6031
6032                         return ins;
6033                 } else if (!cfg->backend->emulate_mul_div && strcmp (cmethod->name, "InternalGetHashCode") == 0 && fsig->param_count == 1 && !mono_gc_is_moving ()) {
6034                         int dreg = alloc_ireg (cfg);
6035                         int t1 = alloc_ireg (cfg);
6036         
6037                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, t1, args [0]->dreg, 3);
6038                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_MUL_IMM, dreg, t1, 2654435761u);
6039                         ins->type = STACK_I4;
6040
6041                         return ins;
6042                 } else if (strcmp (cmethod->name, ".ctor") == 0 && fsig->param_count == 0) {
6043                         MONO_INST_NEW (cfg, ins, OP_NOP);
6044                         MONO_ADD_INS (cfg->cbb, ins);
6045                         return ins;
6046                 } else
6047                         return NULL;
6048         } else if (cmethod->klass == mono_defaults.array_class) {
6049                 if (strcmp (cmethod->name, "GetGenericValueImpl") == 0 && fsig->param_count + fsig->hasthis == 3 && !cfg->gsharedvt)
6050                         return emit_array_generic_access (cfg, fsig, args, FALSE);
6051                 else if (strcmp (cmethod->name, "SetGenericValueImpl") == 0 && fsig->param_count + fsig->hasthis == 3 && !cfg->gsharedvt)
6052                         return emit_array_generic_access (cfg, fsig, args, TRUE);
6053
6054 #ifndef MONO_BIG_ARRAYS
6055                 /*
6056                  * This is an inline version of GetLength/GetLowerBound(0) used frequently in
6057                  * Array methods.
6058                  */
6059                 else if (((strcmp (cmethod->name, "GetLength") == 0 && fsig->param_count + fsig->hasthis == 2) ||
6060                          (strcmp (cmethod->name, "GetLowerBound") == 0 && fsig->param_count + fsig->hasthis == 2)) &&
6061                          args [1]->opcode == OP_ICONST && args [1]->inst_c0 == 0) {
6062                         int dreg = alloc_ireg (cfg);
6063                         int bounds_reg = alloc_ireg_mp (cfg);
6064                         MonoBasicBlock *end_bb, *szarray_bb;
6065                         gboolean get_length = strcmp (cmethod->name, "GetLength") == 0;
6066
6067                         NEW_BBLOCK (cfg, end_bb);
6068                         NEW_BBLOCK (cfg, szarray_bb);
6069
6070                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOAD_MEMBASE, bounds_reg,
6071                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
6072                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
6073                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, szarray_bb);
6074                         /* Non-szarray case */
6075                         if (get_length)
6076                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
6077                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
6078                         else
6079                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
6080                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
6081                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
6082                         MONO_START_BB (cfg, szarray_bb);
6083                         /* Szarray case */
6084                         if (get_length)
6085                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
6086                                                                            args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
6087                         else
6088                                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
6089                         MONO_START_BB (cfg, end_bb);
6090
6091                         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, dreg, dreg);
6092                         ins->type = STACK_I4;
6093                         
6094                         return ins;
6095                 }
6096 #endif
6097
6098                 if (cmethod->name [0] != 'g')
6099                         return NULL;
6100
6101                 if (strcmp (cmethod->name, "get_Rank") == 0 && fsig->param_count + fsig->hasthis == 1) {
6102                         int dreg = alloc_ireg (cfg);
6103                         int vtable_reg = alloc_preg (cfg);
6104                         MONO_EMIT_NEW_LOAD_MEMBASE_OP_FAULT (cfg, OP_LOAD_MEMBASE, vtable_reg, 
6105                                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
6106                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU1_MEMBASE, dreg,
6107                                                                    vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
6108                         type_from_op (cfg, ins, NULL, NULL);
6109
6110                         return ins;
6111                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count + fsig->hasthis == 1) {
6112                         int dreg = alloc_ireg (cfg);
6113
6114                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOADI4_MEMBASE, dreg, 
6115                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
6116                         type_from_op (cfg, ins, NULL, NULL);
6117
6118                         return ins;
6119                 } else
6120                         return NULL;
6121         } else if (cmethod->klass == runtime_helpers_class) {
6122                 if (strcmp (cmethod->name, "get_OffsetToStringData") == 0 && fsig->param_count == 0) {
6123                         EMIT_NEW_ICONST (cfg, ins, MONO_STRUCT_OFFSET (MonoString, chars));
6124                         return ins;
6125                 } else
6126                         return NULL;
6127         } else if (cmethod->klass == mono_defaults.monitor_class) {
6128                 gboolean is_enter = FALSE;
6129
6130                 if (!strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1)
6131                         is_enter = TRUE;
6132
6133                 if (is_enter) {
6134                         /*
6135                          * To make async stack traces work, icalls which can block should have a wrapper.
6136                          * For Monitor.Enter, emit two calls: a fastpath which doesn't have a wrapper, and a slowpath, which does.
6137                          */
6138                         MonoBasicBlock *end_bb;
6139
6140                         NEW_BBLOCK (cfg, end_bb);
6141
6142                         ins = mono_emit_jit_icall (cfg, (gpointer)mono_monitor_enter_fast, args);
6143                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, ins->dreg, 0);
6144                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, end_bb);
6145                         ins = mono_emit_jit_icall (cfg, (gpointer)mono_monitor_enter, args);
6146                         MONO_START_BB (cfg, end_bb);
6147                         return ins;
6148                 }
6149         } else if (cmethod->klass == mono_defaults.thread_class) {
6150                 if (strcmp (cmethod->name, "SpinWait_nop") == 0 && fsig->param_count == 0) {
6151                         MONO_INST_NEW (cfg, ins, OP_RELAXED_NOP);
6152                         MONO_ADD_INS (cfg->cbb, ins);
6153                         return ins;
6154                 } else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0) {
6155                         return emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6156                 } else if (!strcmp (cmethod->name, "VolatileRead") && fsig->param_count == 1) {
6157                         guint32 opcode = 0;
6158                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6159
6160                         if (fsig->params [0]->type == MONO_TYPE_I1)
6161                                 opcode = OP_LOADI1_MEMBASE;
6162                         else if (fsig->params [0]->type == MONO_TYPE_U1)
6163                                 opcode = OP_LOADU1_MEMBASE;
6164                         else if (fsig->params [0]->type == MONO_TYPE_I2)
6165                                 opcode = OP_LOADI2_MEMBASE;
6166                         else if (fsig->params [0]->type == MONO_TYPE_U2)
6167                                 opcode = OP_LOADU2_MEMBASE;
6168                         else if (fsig->params [0]->type == MONO_TYPE_I4)
6169                                 opcode = OP_LOADI4_MEMBASE;
6170                         else if (fsig->params [0]->type == MONO_TYPE_U4)
6171                                 opcode = OP_LOADU4_MEMBASE;
6172                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
6173                                 opcode = OP_LOADI8_MEMBASE;
6174                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6175                                 opcode = OP_LOADR4_MEMBASE;
6176                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6177                                 opcode = OP_LOADR8_MEMBASE;
6178                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
6179                                 opcode = OP_LOAD_MEMBASE;
6180
6181                         if (opcode) {
6182                                 MONO_INST_NEW (cfg, ins, opcode);
6183                                 ins->inst_basereg = args [0]->dreg;
6184                                 ins->inst_offset = 0;
6185                                 MONO_ADD_INS (cfg->cbb, ins);
6186
6187                                 switch (fsig->params [0]->type) {
6188                                 case MONO_TYPE_I1:
6189                                 case MONO_TYPE_U1:
6190                                 case MONO_TYPE_I2:
6191                                 case MONO_TYPE_U2:
6192                                 case MONO_TYPE_I4:
6193                                 case MONO_TYPE_U4:
6194                                         ins->dreg = mono_alloc_ireg (cfg);
6195                                         ins->type = STACK_I4;
6196                                         break;
6197                                 case MONO_TYPE_I8:
6198                                 case MONO_TYPE_U8:
6199                                         ins->dreg = mono_alloc_lreg (cfg);
6200                                         ins->type = STACK_I8;
6201                                         break;
6202                                 case MONO_TYPE_I:
6203                                 case MONO_TYPE_U:
6204                                         ins->dreg = mono_alloc_ireg (cfg);
6205 #if SIZEOF_REGISTER == 8
6206                                         ins->type = STACK_I8;
6207 #else
6208                                         ins->type = STACK_I4;
6209 #endif
6210                                         break;
6211                                 case MONO_TYPE_R4:
6212                                 case MONO_TYPE_R8:
6213                                         ins->dreg = mono_alloc_freg (cfg);
6214                                         ins->type = STACK_R8;
6215                                         break;
6216                                 default:
6217                                         g_assert (mini_type_is_reference (fsig->params [0]));
6218                                         ins->dreg = mono_alloc_ireg_ref (cfg);
6219                                         ins->type = STACK_OBJ;
6220                                         break;
6221                                 }
6222
6223                                 if (opcode == OP_LOADI8_MEMBASE)
6224                                         ins = mono_decompose_opcode (cfg, ins);
6225
6226                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6227
6228                                 return ins;
6229                         }
6230                 } else if (!strcmp (cmethod->name, "VolatileWrite") && fsig->param_count == 2) {
6231                         guint32 opcode = 0;
6232                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6233
6234                         if (fsig->params [0]->type == MONO_TYPE_I1 || fsig->params [0]->type == MONO_TYPE_U1)
6235                                 opcode = OP_STOREI1_MEMBASE_REG;
6236                         else if (fsig->params [0]->type == MONO_TYPE_I2 || fsig->params [0]->type == MONO_TYPE_U2)
6237                                 opcode = OP_STOREI2_MEMBASE_REG;
6238                         else if (fsig->params [0]->type == MONO_TYPE_I4 || fsig->params [0]->type == MONO_TYPE_U4)
6239                                 opcode = OP_STOREI4_MEMBASE_REG;
6240                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
6241                                 opcode = OP_STOREI8_MEMBASE_REG;
6242                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6243                                 opcode = OP_STORER4_MEMBASE_REG;
6244                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6245                                 opcode = OP_STORER8_MEMBASE_REG;
6246                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
6247                                 opcode = OP_STORE_MEMBASE_REG;
6248
6249                         if (opcode) {
6250                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6251
6252                                 MONO_INST_NEW (cfg, ins, opcode);
6253                                 ins->sreg1 = args [1]->dreg;
6254                                 ins->inst_destbasereg = args [0]->dreg;
6255                                 ins->inst_offset = 0;
6256                                 MONO_ADD_INS (cfg->cbb, ins);
6257
6258                                 if (opcode == OP_STOREI8_MEMBASE_REG)
6259                                         ins = mono_decompose_opcode (cfg, ins);
6260
6261                                 return ins;
6262                         }
6263                 }
6264         } else if (cmethod->klass->image == mono_defaults.corlib &&
6265                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
6266                            (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
6267                 ins = NULL;
6268
6269 #if SIZEOF_REGISTER == 8
6270                 if (!cfg->llvm_only && strcmp (cmethod->name, "Read") == 0 && fsig->param_count == 1 && (fsig->params [0]->type == MONO_TYPE_I8)) {
6271                         if (!cfg->llvm_only && mono_arch_opcode_supported (OP_ATOMIC_LOAD_I8)) {
6272                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_LOAD_I8);
6273                                 ins->dreg = mono_alloc_preg (cfg);
6274                                 ins->sreg1 = args [0]->dreg;
6275                                 ins->type = STACK_I8;
6276                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_SEQ;
6277                                 MONO_ADD_INS (cfg->cbb, ins);
6278                         } else {
6279                                 MonoInst *load_ins;
6280
6281                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6282
6283                                 /* 64 bit reads are already atomic */
6284                                 MONO_INST_NEW (cfg, load_ins, OP_LOADI8_MEMBASE);
6285                                 load_ins->dreg = mono_alloc_preg (cfg);
6286                                 load_ins->inst_basereg = args [0]->dreg;
6287                                 load_ins->inst_offset = 0;
6288                                 load_ins->type = STACK_I8;
6289                                 MONO_ADD_INS (cfg->cbb, load_ins);
6290
6291                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6292
6293                                 ins = load_ins;
6294                         }
6295                 }
6296 #endif
6297
6298                 if (strcmp (cmethod->name, "Increment") == 0 && fsig->param_count == 1) {
6299                         MonoInst *ins_iconst;
6300                         guint32 opcode = 0;
6301
6302                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6303                                 opcode = OP_ATOMIC_ADD_I4;
6304                                 cfg->has_atomic_add_i4 = TRUE;
6305                         }
6306 #if SIZEOF_REGISTER == 8
6307                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6308                                 opcode = OP_ATOMIC_ADD_I8;
6309 #endif
6310                         if (opcode) {
6311                                 if (!mono_arch_opcode_supported (opcode))
6312                                         return NULL;
6313                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
6314                                 ins_iconst->inst_c0 = 1;
6315                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
6316                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
6317
6318                                 MONO_INST_NEW (cfg, ins, opcode);
6319                                 ins->dreg = mono_alloc_ireg (cfg);
6320                                 ins->inst_basereg = args [0]->dreg;
6321                                 ins->inst_offset = 0;
6322                                 ins->sreg2 = ins_iconst->dreg;
6323                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6324                                 MONO_ADD_INS (cfg->cbb, ins);
6325                         }
6326                 } else if (strcmp (cmethod->name, "Decrement") == 0 && fsig->param_count == 1) {
6327                         MonoInst *ins_iconst;
6328                         guint32 opcode = 0;
6329
6330                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6331                                 opcode = OP_ATOMIC_ADD_I4;
6332                                 cfg->has_atomic_add_i4 = TRUE;
6333                         }
6334 #if SIZEOF_REGISTER == 8
6335                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6336                                 opcode = OP_ATOMIC_ADD_I8;
6337 #endif
6338                         if (opcode) {
6339                                 if (!mono_arch_opcode_supported (opcode))
6340                                         return NULL;
6341                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
6342                                 ins_iconst->inst_c0 = -1;
6343                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
6344                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
6345
6346                                 MONO_INST_NEW (cfg, ins, opcode);
6347                                 ins->dreg = mono_alloc_ireg (cfg);
6348                                 ins->inst_basereg = args [0]->dreg;
6349                                 ins->inst_offset = 0;
6350                                 ins->sreg2 = ins_iconst->dreg;
6351                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6352                                 MONO_ADD_INS (cfg->cbb, ins);
6353                         }
6354                 } else if (strcmp (cmethod->name, "Add") == 0 && fsig->param_count == 2) {
6355                         guint32 opcode = 0;
6356
6357                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6358                                 opcode = OP_ATOMIC_ADD_I4;
6359                                 cfg->has_atomic_add_i4 = TRUE;
6360                         }
6361 #if SIZEOF_REGISTER == 8
6362                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6363                                 opcode = OP_ATOMIC_ADD_I8;
6364 #endif
6365                         if (opcode) {
6366                                 if (!mono_arch_opcode_supported (opcode))
6367                                         return NULL;
6368                                 MONO_INST_NEW (cfg, ins, opcode);
6369                                 ins->dreg = mono_alloc_ireg (cfg);
6370                                 ins->inst_basereg = args [0]->dreg;
6371                                 ins->inst_offset = 0;
6372                                 ins->sreg2 = args [1]->dreg;
6373                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6374                                 MONO_ADD_INS (cfg->cbb, ins);
6375                         }
6376                 }
6377                 else if (strcmp (cmethod->name, "Exchange") == 0 && fsig->param_count == 2) {
6378                         MonoInst *f2i = NULL, *i2f;
6379                         guint32 opcode, f2i_opcode, i2f_opcode;
6380                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6381                         gboolean is_float = fsig->params [0]->type == MONO_TYPE_R4 || fsig->params [0]->type == MONO_TYPE_R8;
6382
6383                         if (fsig->params [0]->type == MONO_TYPE_I4 ||
6384                             fsig->params [0]->type == MONO_TYPE_R4) {
6385                                 opcode = OP_ATOMIC_EXCHANGE_I4;
6386                                 f2i_opcode = OP_MOVE_F_TO_I4;
6387                                 i2f_opcode = OP_MOVE_I4_TO_F;
6388                                 cfg->has_atomic_exchange_i4 = TRUE;
6389                         }
6390 #if SIZEOF_REGISTER == 8
6391                         else if (is_ref ||
6392                                  fsig->params [0]->type == MONO_TYPE_I8 ||
6393                                  fsig->params [0]->type == MONO_TYPE_R8 ||
6394                                  fsig->params [0]->type == MONO_TYPE_I) {
6395                                 opcode = OP_ATOMIC_EXCHANGE_I8;
6396                                 f2i_opcode = OP_MOVE_F_TO_I8;
6397                                 i2f_opcode = OP_MOVE_I8_TO_F;
6398                         }
6399 #else
6400                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I) {
6401                                 opcode = OP_ATOMIC_EXCHANGE_I4;
6402                                 cfg->has_atomic_exchange_i4 = TRUE;
6403                         }
6404 #endif
6405                         else
6406                                 return NULL;
6407
6408                         if (!mono_arch_opcode_supported (opcode))
6409                                 return NULL;
6410
6411                         if (is_float) {
6412                                 /* TODO: Decompose these opcodes instead of bailing here. */
6413                                 if (COMPILE_SOFT_FLOAT (cfg))
6414                                         return NULL;
6415
6416                                 MONO_INST_NEW (cfg, f2i, f2i_opcode);
6417                                 f2i->dreg = mono_alloc_ireg (cfg);
6418                                 f2i->sreg1 = args [1]->dreg;
6419                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6420                                         f2i->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6421                                 MONO_ADD_INS (cfg->cbb, f2i);
6422                         }
6423
6424                         MONO_INST_NEW (cfg, ins, opcode);
6425                         ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : mono_alloc_ireg (cfg);
6426                         ins->inst_basereg = args [0]->dreg;
6427                         ins->inst_offset = 0;
6428                         ins->sreg2 = is_float ? f2i->dreg : args [1]->dreg;
6429                         MONO_ADD_INS (cfg->cbb, ins);
6430
6431                         switch (fsig->params [0]->type) {
6432                         case MONO_TYPE_I4:
6433                                 ins->type = STACK_I4;
6434                                 break;
6435                         case MONO_TYPE_I8:
6436                                 ins->type = STACK_I8;
6437                                 break;
6438                         case MONO_TYPE_I:
6439 #if SIZEOF_REGISTER == 8
6440                                 ins->type = STACK_I8;
6441 #else
6442                                 ins->type = STACK_I4;
6443 #endif
6444                                 break;
6445                         case MONO_TYPE_R4:
6446                         case MONO_TYPE_R8:
6447                                 ins->type = STACK_R8;
6448                                 break;
6449                         default:
6450                                 g_assert (mini_type_is_reference (fsig->params [0]));
6451                                 ins->type = STACK_OBJ;
6452                                 break;
6453                         }
6454
6455                         if (is_float) {
6456                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
6457                                 i2f->dreg = mono_alloc_freg (cfg);
6458                                 i2f->sreg1 = ins->dreg;
6459                                 i2f->type = STACK_R8;
6460                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
6461                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6462                                 MONO_ADD_INS (cfg->cbb, i2f);
6463
6464                                 ins = i2f;
6465                         }
6466
6467                         if (cfg->gen_write_barriers && is_ref)
6468                                 emit_write_barrier (cfg, args [0], args [1]);
6469                 }
6470                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 3) {
6471                         MonoInst *f2i_new = NULL, *f2i_cmp = NULL, *i2f;
6472                         guint32 opcode, f2i_opcode, i2f_opcode;
6473                         gboolean is_ref = mini_type_is_reference (fsig->params [1]);
6474                         gboolean is_float = fsig->params [1]->type == MONO_TYPE_R4 || fsig->params [1]->type == MONO_TYPE_R8;
6475
6476                         if (fsig->params [1]->type == MONO_TYPE_I4 ||
6477                             fsig->params [1]->type == MONO_TYPE_R4) {
6478                                 opcode = OP_ATOMIC_CAS_I4;
6479                                 f2i_opcode = OP_MOVE_F_TO_I4;
6480                                 i2f_opcode = OP_MOVE_I4_TO_F;
6481                                 cfg->has_atomic_cas_i4 = TRUE;
6482                         }
6483 #if SIZEOF_REGISTER == 8
6484                         else if (is_ref ||
6485                                  fsig->params [1]->type == MONO_TYPE_I8 ||
6486                                  fsig->params [1]->type == MONO_TYPE_R8 ||
6487                                  fsig->params [1]->type == MONO_TYPE_I) {
6488                                 opcode = OP_ATOMIC_CAS_I8;
6489                                 f2i_opcode = OP_MOVE_F_TO_I8;
6490                                 i2f_opcode = OP_MOVE_I8_TO_F;
6491                         }
6492 #else
6493                         else if (is_ref || fsig->params [1]->type == MONO_TYPE_I) {
6494                                 opcode = OP_ATOMIC_CAS_I4;
6495                                 cfg->has_atomic_cas_i4 = TRUE;
6496                         }
6497 #endif
6498                         else
6499                                 return NULL;
6500
6501                         if (!mono_arch_opcode_supported (opcode))
6502                                 return NULL;
6503
6504                         if (is_float) {
6505                                 /* TODO: Decompose these opcodes instead of bailing here. */
6506                                 if (COMPILE_SOFT_FLOAT (cfg))
6507                                         return NULL;
6508
6509                                 MONO_INST_NEW (cfg, f2i_new, f2i_opcode);
6510                                 f2i_new->dreg = mono_alloc_ireg (cfg);
6511                                 f2i_new->sreg1 = args [1]->dreg;
6512                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6513                                         f2i_new->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6514                                 MONO_ADD_INS (cfg->cbb, f2i_new);
6515
6516                                 MONO_INST_NEW (cfg, f2i_cmp, f2i_opcode);
6517                                 f2i_cmp->dreg = mono_alloc_ireg (cfg);
6518                                 f2i_cmp->sreg1 = args [2]->dreg;
6519                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6520                                         f2i_cmp->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6521                                 MONO_ADD_INS (cfg->cbb, f2i_cmp);
6522                         }
6523
6524                         MONO_INST_NEW (cfg, ins, opcode);
6525                         ins->dreg = is_ref ? alloc_ireg_ref (cfg) : alloc_ireg (cfg);
6526                         ins->sreg1 = args [0]->dreg;
6527                         ins->sreg2 = is_float ? f2i_new->dreg : args [1]->dreg;
6528                         ins->sreg3 = is_float ? f2i_cmp->dreg : args [2]->dreg;
6529                         MONO_ADD_INS (cfg->cbb, ins);
6530
6531                         switch (fsig->params [1]->type) {
6532                         case MONO_TYPE_I4:
6533                                 ins->type = STACK_I4;
6534                                 break;
6535                         case MONO_TYPE_I8:
6536                                 ins->type = STACK_I8;
6537                                 break;
6538                         case MONO_TYPE_I:
6539 #if SIZEOF_REGISTER == 8
6540                                 ins->type = STACK_I8;
6541 #else
6542                                 ins->type = STACK_I4;
6543 #endif
6544                                 break;
6545                         case MONO_TYPE_R4:
6546                                 ins->type = cfg->r4_stack_type;
6547                                 break;
6548                         case MONO_TYPE_R8:
6549                                 ins->type = STACK_R8;
6550                                 break;
6551                         default:
6552                                 g_assert (mini_type_is_reference (fsig->params [1]));
6553                                 ins->type = STACK_OBJ;
6554                                 break;
6555                         }
6556
6557                         if (is_float) {
6558                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
6559                                 i2f->dreg = mono_alloc_freg (cfg);
6560                                 i2f->sreg1 = ins->dreg;
6561                                 i2f->type = STACK_R8;
6562                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
6563                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6564                                 MONO_ADD_INS (cfg->cbb, i2f);
6565
6566                                 ins = i2f;
6567                         }
6568
6569                         if (cfg->gen_write_barriers && is_ref)
6570                                 emit_write_barrier (cfg, args [0], args [1]);
6571                 }
6572                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 4 &&
6573                          fsig->params [1]->type == MONO_TYPE_I4) {
6574                         MonoInst *cmp, *ceq;
6575
6576                         if (!mono_arch_opcode_supported (OP_ATOMIC_CAS_I4))
6577                                 return NULL;
6578
6579                         /* int32 r = CAS (location, value, comparand); */
6580                         MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I4);
6581                         ins->dreg = alloc_ireg (cfg);
6582                         ins->sreg1 = args [0]->dreg;
6583                         ins->sreg2 = args [1]->dreg;
6584                         ins->sreg3 = args [2]->dreg;
6585                         ins->type = STACK_I4;
6586                         MONO_ADD_INS (cfg->cbb, ins);
6587
6588                         /* bool result = r == comparand; */
6589                         MONO_INST_NEW (cfg, cmp, OP_ICOMPARE);
6590                         cmp->sreg1 = ins->dreg;
6591                         cmp->sreg2 = args [2]->dreg;
6592                         cmp->type = STACK_I4;
6593                         MONO_ADD_INS (cfg->cbb, cmp);
6594
6595                         MONO_INST_NEW (cfg, ceq, OP_ICEQ);
6596                         ceq->dreg = alloc_ireg (cfg);
6597                         ceq->type = STACK_I4;
6598                         MONO_ADD_INS (cfg->cbb, ceq);
6599
6600                         /* *success = result; */
6601                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, args [3]->dreg, 0, ceq->dreg);
6602
6603                         cfg->has_atomic_cas_i4 = TRUE;
6604                 }
6605                 else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0)
6606                         ins = emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6607
6608                 if (ins)
6609                         return ins;
6610         } else if (cmethod->klass->image == mono_defaults.corlib &&
6611                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
6612                            (strcmp (cmethod->klass->name, "Volatile") == 0)) {
6613                 ins = NULL;
6614
6615                 if (!cfg->llvm_only && !strcmp (cmethod->name, "Read") && fsig->param_count == 1) {
6616                         guint32 opcode = 0;
6617                         MonoType *t = fsig->params [0];
6618                         gboolean is_ref;
6619                         gboolean is_float = t->type == MONO_TYPE_R4 || t->type == MONO_TYPE_R8;
6620
6621                         g_assert (t->byref);
6622                         /* t is a byref type, so the reference check is more complicated */
6623                         is_ref = mini_type_is_reference (&mono_class_from_mono_type (t)->byval_arg);
6624                         if (t->type == MONO_TYPE_I1)
6625                                 opcode = OP_ATOMIC_LOAD_I1;
6626                         else if (t->type == MONO_TYPE_U1 || t->type == MONO_TYPE_BOOLEAN)
6627                                 opcode = OP_ATOMIC_LOAD_U1;
6628                         else if (t->type == MONO_TYPE_I2)
6629                                 opcode = OP_ATOMIC_LOAD_I2;
6630                         else if (t->type == MONO_TYPE_U2)
6631                                 opcode = OP_ATOMIC_LOAD_U2;
6632                         else if (t->type == MONO_TYPE_I4)
6633                                 opcode = OP_ATOMIC_LOAD_I4;
6634                         else if (t->type == MONO_TYPE_U4)
6635                                 opcode = OP_ATOMIC_LOAD_U4;
6636                         else if (t->type == MONO_TYPE_R4)
6637                                 opcode = OP_ATOMIC_LOAD_R4;
6638                         else if (t->type == MONO_TYPE_R8)
6639                                 opcode = OP_ATOMIC_LOAD_R8;
6640 #if SIZEOF_REGISTER == 8
6641                         else if (t->type == MONO_TYPE_I8 || t->type == MONO_TYPE_I)
6642                                 opcode = OP_ATOMIC_LOAD_I8;
6643                         else if (is_ref || t->type == MONO_TYPE_U8 || t->type == MONO_TYPE_U)
6644                                 opcode = OP_ATOMIC_LOAD_U8;
6645 #else
6646                         else if (t->type == MONO_TYPE_I)
6647                                 opcode = OP_ATOMIC_LOAD_I4;
6648                         else if (is_ref || t->type == MONO_TYPE_U)
6649                                 opcode = OP_ATOMIC_LOAD_U4;
6650 #endif
6651
6652                         if (opcode) {
6653                                 if (!mono_arch_opcode_supported (opcode))
6654                                         return NULL;
6655
6656                                 MONO_INST_NEW (cfg, ins, opcode);
6657                                 ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : (is_float ? mono_alloc_freg (cfg) : mono_alloc_ireg (cfg));
6658                                 ins->sreg1 = args [0]->dreg;
6659                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_ACQ;
6660                                 MONO_ADD_INS (cfg->cbb, ins);
6661
6662                                 switch (t->type) {
6663                                 case MONO_TYPE_BOOLEAN:
6664                                 case MONO_TYPE_I1:
6665                                 case MONO_TYPE_U1:
6666                                 case MONO_TYPE_I2:
6667                                 case MONO_TYPE_U2:
6668                                 case MONO_TYPE_I4:
6669                                 case MONO_TYPE_U4:
6670                                         ins->type = STACK_I4;
6671                                         break;
6672                                 case MONO_TYPE_I8:
6673                                 case MONO_TYPE_U8:
6674                                         ins->type = STACK_I8;
6675                                         break;
6676                                 case MONO_TYPE_I:
6677                                 case MONO_TYPE_U:
6678 #if SIZEOF_REGISTER == 8
6679                                         ins->type = STACK_I8;
6680 #else
6681                                         ins->type = STACK_I4;
6682 #endif
6683                                         break;
6684                                 case MONO_TYPE_R4:
6685                                         ins->type = cfg->r4_stack_type;
6686                                         break;
6687                                 case MONO_TYPE_R8:
6688                                         ins->type = STACK_R8;
6689                                         break;
6690                                 default:
6691                                         g_assert (is_ref);
6692                                         ins->type = STACK_OBJ;
6693                                         break;
6694                                 }
6695                         }
6696                 }
6697
6698                 if (!cfg->llvm_only && !strcmp (cmethod->name, "Write") && fsig->param_count == 2) {
6699                         guint32 opcode = 0;
6700                         MonoType *t = fsig->params [0];
6701                         gboolean is_ref;
6702
6703                         g_assert (t->byref);
6704                         is_ref = mini_type_is_reference (&mono_class_from_mono_type (t)->byval_arg);
6705                         if (t->type == MONO_TYPE_I1)
6706                                 opcode = OP_ATOMIC_STORE_I1;
6707                         else if (t->type == MONO_TYPE_U1 || t->type == MONO_TYPE_BOOLEAN)
6708                                 opcode = OP_ATOMIC_STORE_U1;
6709                         else if (t->type == MONO_TYPE_I2)
6710                                 opcode = OP_ATOMIC_STORE_I2;
6711                         else if (t->type == MONO_TYPE_U2)
6712                                 opcode = OP_ATOMIC_STORE_U2;
6713                         else if (t->type == MONO_TYPE_I4)
6714                                 opcode = OP_ATOMIC_STORE_I4;
6715                         else if (t->type == MONO_TYPE_U4)
6716                                 opcode = OP_ATOMIC_STORE_U4;
6717                         else if (t->type == MONO_TYPE_R4)
6718                                 opcode = OP_ATOMIC_STORE_R4;
6719                         else if (t->type == MONO_TYPE_R8)
6720                                 opcode = OP_ATOMIC_STORE_R8;
6721 #if SIZEOF_REGISTER == 8
6722                         else if (t->type == MONO_TYPE_I8 || t->type == MONO_TYPE_I)
6723                                 opcode = OP_ATOMIC_STORE_I8;
6724                         else if (is_ref || t->type == MONO_TYPE_U8 || t->type == MONO_TYPE_U)
6725                                 opcode = OP_ATOMIC_STORE_U8;
6726 #else
6727                         else if (t->type == MONO_TYPE_I)
6728                                 opcode = OP_ATOMIC_STORE_I4;
6729                         else if (is_ref || t->type == MONO_TYPE_U)
6730                                 opcode = OP_ATOMIC_STORE_U4;
6731 #endif
6732
6733                         if (opcode) {
6734                                 if (!mono_arch_opcode_supported (opcode))
6735                                         return NULL;
6736
6737                                 MONO_INST_NEW (cfg, ins, opcode);
6738                                 ins->dreg = args [0]->dreg;
6739                                 ins->sreg1 = args [1]->dreg;
6740                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_REL;
6741                                 MONO_ADD_INS (cfg->cbb, ins);
6742
6743                                 if (cfg->gen_write_barriers && is_ref)
6744                                         emit_write_barrier (cfg, args [0], args [1]);
6745                         }
6746                 }
6747
6748                 if (ins)
6749                         return ins;
6750         } else if (cmethod->klass->image == mono_defaults.corlib &&
6751                            (strcmp (cmethod->klass->name_space, "System.Diagnostics") == 0) &&
6752                            (strcmp (cmethod->klass->name, "Debugger") == 0)) {
6753                 if (!strcmp (cmethod->name, "Break") && fsig->param_count == 0) {
6754                         if (should_insert_brekpoint (cfg->method)) {
6755                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
6756                         } else {
6757                                 MONO_INST_NEW (cfg, ins, OP_NOP);
6758                                 MONO_ADD_INS (cfg->cbb, ins);
6759                         }
6760                         return ins;
6761                 }
6762         } else if (cmethod->klass->image == mono_defaults.corlib &&
6763                    (strcmp (cmethod->klass->name_space, "System") == 0) &&
6764                    (strcmp (cmethod->klass->name, "Environment") == 0)) {
6765                 if (!strcmp (cmethod->name, "get_IsRunningOnWindows") && fsig->param_count == 0) {
6766 #ifdef TARGET_WIN32
6767                         EMIT_NEW_ICONST (cfg, ins, 1);
6768 #else
6769                         EMIT_NEW_ICONST (cfg, ins, 0);
6770 #endif
6771                 }
6772         } else if (cmethod->klass->image == mono_defaults.corlib &&
6773                            (strcmp (cmethod->klass->name_space, "System.Reflection") == 0) &&
6774                            (strcmp (cmethod->klass->name, "Assembly") == 0)) {
6775                 if (cfg->llvm_only && !strcmp (cmethod->name, "GetExecutingAssembly")) {
6776                         /* No stack walks are currently available, so implement this as an intrinsic */
6777                         MonoInst *assembly_ins;
6778
6779                         EMIT_NEW_AOTCONST (cfg, assembly_ins, MONO_PATCH_INFO_IMAGE, cfg->method->klass->image);
6780                         ins = mono_emit_jit_icall (cfg, mono_get_assembly_object, &assembly_ins);
6781                         return ins;
6782                 }
6783         } else if (cmethod->klass->image == mono_defaults.corlib &&
6784                            (strcmp (cmethod->klass->name_space, "System.Reflection") == 0) &&
6785                            (strcmp (cmethod->klass->name, "MethodBase") == 0)) {
6786                 if (cfg->llvm_only && !strcmp (cmethod->name, "GetCurrentMethod")) {
6787                         /* No stack walks are currently available, so implement this as an intrinsic */
6788                         MonoInst *method_ins;
6789                         MonoMethod *declaring = cfg->method;
6790
6791                         /* This returns the declaring generic method */
6792                         if (declaring->is_inflated)
6793                                 declaring = ((MonoMethodInflated*)cfg->method)->declaring;
6794                         EMIT_NEW_AOTCONST (cfg, method_ins, MONO_PATCH_INFO_METHODCONST, declaring);
6795                         ins = mono_emit_jit_icall (cfg, mono_get_method_object, &method_ins);
6796                         cfg->no_inline = TRUE;
6797                         if (cfg->method != cfg->current_method)
6798                                 inline_failure (cfg, "MethodBase:GetCurrentMethod ()");
6799                         return ins;
6800                 }
6801         } else if (cmethod->klass == mono_defaults.math_class) {
6802                 /* 
6803                  * There is general branchless code for Min/Max, but it does not work for 
6804                  * all inputs:
6805                  * http://everything2.com/?node_id=1051618
6806                  */
6807         } else if (((!strcmp (cmethod->klass->image->assembly->aname.name, "MonoMac") ||
6808                     !strcmp (cmethod->klass->image->assembly->aname.name, "monotouch")) &&
6809                                 !strcmp (cmethod->klass->name_space, "XamCore.ObjCRuntime") &&
6810                                 !strcmp (cmethod->klass->name, "Selector")) ||
6811                            ((!strcmp (cmethod->klass->image->assembly->aname.name, "Xamarin.iOS") ||
6812                                  !strcmp (cmethod->klass->image->assembly->aname.name, "Xamarin.Mac")) &&
6813                                 !strcmp (cmethod->klass->name_space, "ObjCRuntime") &&
6814                                 !strcmp (cmethod->klass->name, "Selector"))
6815                            ) {
6816                 if ((cfg->backend->have_objc_get_selector || cfg->compile_llvm) &&
6817                         !strcmp (cmethod->name, "GetHandle") && fsig->param_count == 1 &&
6818                     (args [0]->opcode == OP_GOT_ENTRY || args [0]->opcode == OP_AOTCONST) &&
6819                     cfg->compile_aot) {
6820                         MonoInst *pi;
6821                         MonoJumpInfoToken *ji;
6822                         char *s;
6823
6824                         if (args [0]->opcode == OP_GOT_ENTRY) {
6825                                 pi = (MonoInst *)args [0]->inst_p1;
6826                                 g_assert (pi->opcode == OP_PATCH_INFO);
6827                                 g_assert (GPOINTER_TO_INT (pi->inst_p1) == MONO_PATCH_INFO_LDSTR);
6828                                 ji = (MonoJumpInfoToken *)pi->inst_p0;
6829                         } else {
6830                                 g_assert (GPOINTER_TO_INT (args [0]->inst_p1) == MONO_PATCH_INFO_LDSTR);
6831                                 ji = (MonoJumpInfoToken *)args [0]->inst_p0;
6832                         }
6833
6834                         NULLIFY_INS (args [0]);
6835
6836                         s = mono_ldstr_utf8 (ji->image, mono_metadata_token_index (ji->token), &cfg->error);
6837                         return_val_if_nok (&cfg->error, NULL);
6838
6839                         MONO_INST_NEW (cfg, ins, OP_OBJC_GET_SELECTOR);
6840                         ins->dreg = mono_alloc_ireg (cfg);
6841                         // FIXME: Leaks
6842                         ins->inst_p0 = s;
6843                         MONO_ADD_INS (cfg->cbb, ins);
6844                         return ins;
6845                 }
6846         }
6847
6848 #ifdef MONO_ARCH_SIMD_INTRINSICS
6849         if (cfg->opt & MONO_OPT_SIMD) {
6850                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
6851                 if (ins)
6852                         return ins;
6853         }
6854 #endif
6855
6856         ins = mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
6857         if (ins)
6858                 return ins;
6859
6860         if (COMPILE_LLVM (cfg)) {
6861                 ins = llvm_emit_inst_for_method (cfg, cmethod, fsig, args);
6862                 if (ins)
6863                         return ins;
6864         }
6865
6866         return mono_arch_emit_inst_for_method (cfg, cmethod, fsig, args);
6867 }
6868
6869 /*
6870  * This entry point could be used later for arbitrary method
6871  * redirection.
6872  */
6873 inline static MonoInst*
6874 mini_redirect_call (MonoCompile *cfg, MonoMethod *method,  
6875                                         MonoMethodSignature *signature, MonoInst **args, MonoInst *this_ins)
6876 {
6877         if (method->klass == mono_defaults.string_class) {
6878                 /* managed string allocation support */
6879                 if (strcmp (method->name, "InternalAllocateStr") == 0 && !(mono_profiler_events & MONO_PROFILE_ALLOCATIONS) && !(cfg->opt & MONO_OPT_SHARED)) {
6880                         MonoInst *iargs [2];
6881                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
6882                         MonoMethod *managed_alloc = NULL;
6883
6884                         g_assert (vtable); /*Should not fail since it System.String*/
6885 #ifndef MONO_CROSS_COMPILE
6886                         managed_alloc = mono_gc_get_managed_allocator (method->klass, FALSE, FALSE);
6887 #endif
6888                         if (!managed_alloc)
6889                                 return NULL;
6890                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
6891                         iargs [1] = args [0];
6892                         return mono_emit_method_call (cfg, managed_alloc, iargs, this_ins);
6893                 }
6894         }
6895         return NULL;
6896 }
6897
6898 static void
6899 mono_save_args (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **sp)
6900 {
6901         MonoInst *store, *temp;
6902         int i;
6903
6904         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
6905                 MonoType *argtype = (sig->hasthis && (i == 0)) ? type_from_stack_type (*sp) : sig->params [i - sig->hasthis];
6906
6907                 /*
6908                  * FIXME: We should use *args++ = sp [0], but that would mean the arg
6909                  * would be different than the MonoInst's used to represent arguments, and
6910                  * the ldelema implementation can't deal with that.
6911                  * Solution: When ldelema is used on an inline argument, create a var for 
6912                  * it, emit ldelema on that var, and emit the saving code below in
6913                  * inline_method () if needed.
6914                  */
6915                 temp = mono_compile_create_var (cfg, argtype, OP_LOCAL);
6916                 cfg->args [i] = temp;
6917                 /* This uses cfg->args [i] which is set by the preceeding line */
6918                 EMIT_NEW_ARGSTORE (cfg, store, i, *sp);
6919                 store->cil_code = sp [0]->cil_code;
6920                 sp++;
6921         }
6922 }
6923
6924 #define MONO_INLINE_CALLED_LIMITED_METHODS 1
6925 #define MONO_INLINE_CALLER_LIMITED_METHODS 1
6926
6927 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
6928 static gboolean
6929 check_inline_called_method_name_limit (MonoMethod *called_method)
6930 {
6931         int strncmp_result;
6932         static const char *limit = NULL;
6933         
6934         if (limit == NULL) {
6935                 const char *limit_string = g_getenv ("MONO_INLINE_CALLED_METHOD_NAME_LIMIT");
6936
6937                 if (limit_string != NULL)
6938                         limit = limit_string;
6939                 else
6940                         limit = "";
6941         }
6942
6943         if (limit [0] != '\0') {
6944                 char *called_method_name = mono_method_full_name (called_method, TRUE);
6945
6946                 strncmp_result = strncmp (called_method_name, limit, strlen (limit));
6947                 g_free (called_method_name);
6948         
6949                 //return (strncmp_result <= 0);
6950                 return (strncmp_result == 0);
6951         } else {
6952                 return TRUE;
6953         }
6954 }
6955 #endif
6956
6957 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
6958 static gboolean
6959 check_inline_caller_method_name_limit (MonoMethod *caller_method)
6960 {
6961         int strncmp_result;
6962         static const char *limit = NULL;
6963         
6964         if (limit == NULL) {
6965                 const char *limit_string = g_getenv ("MONO_INLINE_CALLER_METHOD_NAME_LIMIT");
6966                 if (limit_string != NULL) {
6967                         limit = limit_string;
6968                 } else {
6969                         limit = "";
6970                 }
6971         }
6972
6973         if (limit [0] != '\0') {
6974                 char *caller_method_name = mono_method_full_name (caller_method, TRUE);
6975
6976                 strncmp_result = strncmp (caller_method_name, limit, strlen (limit));
6977                 g_free (caller_method_name);
6978         
6979                 //return (strncmp_result <= 0);
6980                 return (strncmp_result == 0);
6981         } else {
6982                 return TRUE;
6983         }
6984 }
6985 #endif
6986
6987 static void
6988 emit_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
6989 {
6990         static double r8_0 = 0.0;
6991         static float r4_0 = 0.0;
6992         MonoInst *ins;
6993         int t;
6994
6995         rtype = mini_get_underlying_type (rtype);
6996         t = rtype->type;
6997
6998         if (rtype->byref) {
6999                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
7000         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
7001                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
7002         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
7003                 MONO_EMIT_NEW_I8CONST (cfg, dreg, 0);
7004         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
7005                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
7006                 ins->type = STACK_R4;
7007                 ins->inst_p0 = (void*)&r4_0;
7008                 ins->dreg = dreg;
7009                 MONO_ADD_INS (cfg->cbb, ins);
7010         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
7011                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
7012                 ins->type = STACK_R8;
7013                 ins->inst_p0 = (void*)&r8_0;
7014                 ins->dreg = dreg;
7015                 MONO_ADD_INS (cfg->cbb, ins);
7016         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
7017                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
7018                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
7019         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (rtype)) {
7020                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
7021         } else {
7022                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
7023         }
7024 }
7025
7026 static void
7027 emit_dummy_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
7028 {
7029         int t;
7030
7031         rtype = mini_get_underlying_type (rtype);
7032         t = rtype->type;
7033
7034         if (rtype->byref) {
7035                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_PCONST);
7036         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
7037                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_ICONST);
7038         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
7039                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_I8CONST);
7040         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
7041                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R4CONST);
7042         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
7043                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R8CONST);
7044         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
7045                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
7046                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
7047         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (rtype)) {
7048                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
7049         } else {
7050                 emit_init_rvar (cfg, dreg, rtype);
7051         }
7052 }
7053
7054 /* If INIT is FALSE, emit dummy initialization statements to keep the IR valid */
7055 static void
7056 emit_init_local (MonoCompile *cfg, int local, MonoType *type, gboolean init)
7057 {
7058         MonoInst *var = cfg->locals [local];
7059         if (COMPILE_SOFT_FLOAT (cfg)) {
7060                 MonoInst *store;
7061                 int reg = alloc_dreg (cfg, (MonoStackType)var->type);
7062                 emit_init_rvar (cfg, reg, type);
7063                 EMIT_NEW_LOCSTORE (cfg, store, local, cfg->cbb->last_ins);
7064         } else {
7065                 if (init)
7066                         emit_init_rvar (cfg, var->dreg, type);
7067                 else
7068                         emit_dummy_init_rvar (cfg, var->dreg, type);
7069         }
7070 }
7071
7072 /*
7073  * inline_method:
7074  *
7075  *   Return the cost of inlining CMETHOD.
7076  */
7077 static int
7078 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
7079                            guchar *ip, guint real_offset, gboolean inline_always)
7080 {
7081         MonoError error;
7082         MonoInst *ins, *rvar = NULL;
7083         MonoMethodHeader *cheader;
7084         MonoBasicBlock *ebblock, *sbblock;
7085         int i, costs;
7086         MonoMethod *prev_inlined_method;
7087         MonoInst **prev_locals, **prev_args;
7088         MonoType **prev_arg_types;
7089         guint prev_real_offset;
7090         GHashTable *prev_cbb_hash;
7091         MonoBasicBlock **prev_cil_offset_to_bb;
7092         MonoBasicBlock *prev_cbb;
7093         const unsigned char *prev_ip;
7094         unsigned char *prev_cil_start;
7095         guint32 prev_cil_offset_to_bb_len;
7096         MonoMethod *prev_current_method;
7097         MonoGenericContext *prev_generic_context;
7098         gboolean ret_var_set, prev_ret_var_set, prev_disable_inline, virtual_ = FALSE;
7099
7100         g_assert (cfg->exception_type == MONO_EXCEPTION_NONE);
7101
7102 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
7103         if ((! inline_always) && ! check_inline_called_method_name_limit (cmethod))
7104                 return 0;
7105 #endif
7106 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
7107         if ((! inline_always) && ! check_inline_caller_method_name_limit (cfg->method))
7108                 return 0;
7109 #endif
7110
7111         if (!fsig)
7112                 fsig = mono_method_signature (cmethod);
7113
7114         if (cfg->verbose_level > 2)
7115                 printf ("INLINE START %p %s -> %s\n", cmethod,  mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
7116
7117         if (!cmethod->inline_info) {
7118                 cfg->stat_inlineable_methods++;
7119                 cmethod->inline_info = 1;
7120         }
7121
7122         /* allocate local variables */
7123         cheader = mono_method_get_header_checked (cmethod, &error);
7124         if (!cheader) {
7125                 if (inline_always) {
7126                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
7127                         mono_error_move (&cfg->error, &error);
7128                 } else {
7129                         mono_error_cleanup (&error);
7130                 }
7131                 return 0;
7132         }
7133
7134         /*Must verify before creating locals as it can cause the JIT to assert.*/
7135         if (mono_compile_is_broken (cfg, cmethod, FALSE)) {
7136                 mono_metadata_free_mh (cheader);
7137                 return 0;
7138         }
7139
7140         /* allocate space to store the return value */
7141         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
7142                 rvar = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
7143         }
7144
7145         prev_locals = cfg->locals;
7146         cfg->locals = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, cheader->num_locals * sizeof (MonoInst*));
7147         for (i = 0; i < cheader->num_locals; ++i)
7148                 cfg->locals [i] = mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
7149
7150         /* allocate start and end blocks */
7151         /* This is needed so if the inline is aborted, we can clean up */
7152         NEW_BBLOCK (cfg, sbblock);
7153         sbblock->real_offset = real_offset;
7154
7155         NEW_BBLOCK (cfg, ebblock);
7156         ebblock->block_num = cfg->num_bblocks++;
7157         ebblock->real_offset = real_offset;
7158
7159         prev_args = cfg->args;
7160         prev_arg_types = cfg->arg_types;
7161         prev_inlined_method = cfg->inlined_method;
7162         cfg->inlined_method = cmethod;
7163         cfg->ret_var_set = FALSE;
7164         cfg->inline_depth ++;
7165         prev_real_offset = cfg->real_offset;
7166         prev_cbb_hash = cfg->cbb_hash;
7167         prev_cil_offset_to_bb = cfg->cil_offset_to_bb;
7168         prev_cil_offset_to_bb_len = cfg->cil_offset_to_bb_len;
7169         prev_cil_start = cfg->cil_start;
7170         prev_ip = cfg->ip;
7171         prev_cbb = cfg->cbb;
7172         prev_current_method = cfg->current_method;
7173         prev_generic_context = cfg->generic_context;
7174         prev_ret_var_set = cfg->ret_var_set;
7175         prev_disable_inline = cfg->disable_inline;
7176
7177         if (ip && *ip == CEE_CALLVIRT && !(cmethod->flags & METHOD_ATTRIBUTE_STATIC))
7178                 virtual_ = TRUE;
7179
7180         costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, rvar, sp, real_offset, virtual_);
7181
7182         ret_var_set = cfg->ret_var_set;
7183
7184         cfg->inlined_method = prev_inlined_method;
7185         cfg->real_offset = prev_real_offset;
7186         cfg->cbb_hash = prev_cbb_hash;
7187         cfg->cil_offset_to_bb = prev_cil_offset_to_bb;
7188         cfg->cil_offset_to_bb_len = prev_cil_offset_to_bb_len;
7189         cfg->cil_start = prev_cil_start;
7190         cfg->ip = prev_ip;
7191         cfg->locals = prev_locals;
7192         cfg->args = prev_args;
7193         cfg->arg_types = prev_arg_types;
7194         cfg->current_method = prev_current_method;
7195         cfg->generic_context = prev_generic_context;
7196         cfg->ret_var_set = prev_ret_var_set;
7197         cfg->disable_inline = prev_disable_inline;
7198         cfg->inline_depth --;
7199
7200         if ((costs >= 0 && costs < 60) || inline_always || (costs >= 0 && (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))) {
7201                 if (cfg->verbose_level > 2)
7202                         printf ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
7203                 
7204                 cfg->stat_inlined_methods++;
7205
7206                 /* always add some code to avoid block split failures */
7207                 MONO_INST_NEW (cfg, ins, OP_NOP);
7208                 MONO_ADD_INS (prev_cbb, ins);
7209
7210                 prev_cbb->next_bb = sbblock;
7211                 link_bblock (cfg, prev_cbb, sbblock);
7212
7213                 /* 
7214                  * Get rid of the begin and end bblocks if possible to aid local
7215                  * optimizations.
7216                  */
7217                 mono_merge_basic_blocks (cfg, prev_cbb, sbblock);
7218
7219                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] != ebblock))
7220                         mono_merge_basic_blocks (cfg, prev_cbb, prev_cbb->out_bb [0]);
7221
7222                 if ((ebblock->in_count == 1) && ebblock->in_bb [0]->out_count == 1) {
7223                         MonoBasicBlock *prev = ebblock->in_bb [0];
7224
7225                         if (prev->next_bb == ebblock) {
7226                                 mono_merge_basic_blocks (cfg, prev, ebblock);
7227                                 cfg->cbb = prev;
7228                                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] == prev)) {
7229                                         mono_merge_basic_blocks (cfg, prev_cbb, prev);
7230                                         cfg->cbb = prev_cbb;
7231                                 }
7232                         } else {
7233                                 /* There could be a bblock after 'prev', and making 'prev' the current bb could cause problems */
7234                                 cfg->cbb = ebblock;
7235                         }
7236                 } else {
7237                         /* 
7238                          * Its possible that the rvar is set in some prev bblock, but not in others.
7239                          * (#1835).
7240                          */
7241                         if (rvar) {
7242                                 MonoBasicBlock *bb;
7243
7244                                 for (i = 0; i < ebblock->in_count; ++i) {
7245                                         bb = ebblock->in_bb [i];
7246
7247                                         if (bb->last_ins && bb->last_ins->opcode == OP_NOT_REACHED) {
7248                                                 cfg->cbb = bb;
7249
7250                                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
7251                                         }
7252                                 }
7253                         }
7254
7255                         cfg->cbb = ebblock;
7256                 }
7257
7258                 if (rvar) {
7259                         /*
7260                          * If the inlined method contains only a throw, then the ret var is not 
7261                          * set, so set it to a dummy value.
7262                          */
7263                         if (!ret_var_set)
7264                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
7265
7266                         EMIT_NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
7267                         *sp++ = ins;
7268                 }
7269                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
7270                 return costs + 1;
7271         } else {
7272                 if (cfg->verbose_level > 2)
7273                         printf ("INLINE ABORTED %s (cost %d)\n", mono_method_full_name (cmethod, TRUE), costs);
7274                 cfg->exception_type = MONO_EXCEPTION_NONE;
7275
7276                 /* This gets rid of the newly added bblocks */
7277                 cfg->cbb = prev_cbb;
7278         }
7279         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
7280         return 0;
7281 }
7282
7283 /*
7284  * Some of these comments may well be out-of-date.
7285  * Design decisions: we do a single pass over the IL code (and we do bblock 
7286  * splitting/merging in the few cases when it's required: a back jump to an IL
7287  * address that was not already seen as bblock starting point).
7288  * Code is validated as we go (full verification is still better left to metadata/verify.c).
7289  * Complex operations are decomposed in simpler ones right away. We need to let the 
7290  * arch-specific code peek and poke inside this process somehow (except when the 
7291  * optimizations can take advantage of the full semantic info of coarse opcodes).
7292  * All the opcodes of the form opcode.s are 'normalized' to opcode.
7293  * MonoInst->opcode initially is the IL opcode or some simplification of that 
7294  * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific 
7295  * opcode with value bigger than OP_LAST.
7296  * At this point the IR can be handed over to an interpreter, a dumb code generator
7297  * or to the optimizing code generator that will translate it to SSA form.
7298  *
7299  * Profiling directed optimizations.
7300  * We may compile by default with few or no optimizations and instrument the code
7301  * or the user may indicate what methods to optimize the most either in a config file
7302  * or through repeated runs where the compiler applies offline the optimizations to 
7303  * each method and then decides if it was worth it.
7304  */
7305
7306 #define CHECK_TYPE(ins) if (!(ins)->type) UNVERIFIED
7307 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) UNVERIFIED
7308 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) UNVERIFIED
7309 #define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) UNVERIFIED
7310 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
7311 #define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
7312 #define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
7313 #define CHECK_TYPELOAD(klass) if (!(klass) || mono_class_has_failure (klass)) TYPE_LOAD_ERROR ((klass))
7314
7315 /* offset from br.s -> br like opcodes */
7316 #define BIG_BRANCH_OFFSET 13
7317
7318 static gboolean
7319 ip_in_bb (MonoCompile *cfg, MonoBasicBlock *bb, const guint8* ip)
7320 {
7321         MonoBasicBlock *b = cfg->cil_offset_to_bb [ip - cfg->cil_start];
7322
7323         return b == NULL || b == bb;
7324 }
7325
7326 static int
7327 get_basic_blocks (MonoCompile *cfg, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
7328 {
7329         unsigned char *ip = start;
7330         unsigned char *target;
7331         int i;
7332         guint cli_addr;
7333         MonoBasicBlock *bblock;
7334         const MonoOpcode *opcode;
7335
7336         while (ip < end) {
7337                 cli_addr = ip - start;
7338                 i = mono_opcode_value ((const guint8 **)&ip, end);
7339                 if (i < 0)
7340                         UNVERIFIED;
7341                 opcode = &mono_opcodes [i];
7342                 switch (opcode->argument) {
7343                 case MonoInlineNone:
7344                         ip++; 
7345                         break;
7346                 case MonoInlineString:
7347                 case MonoInlineType:
7348                 case MonoInlineField:
7349                 case MonoInlineMethod:
7350                 case MonoInlineTok:
7351                 case MonoInlineSig:
7352                 case MonoShortInlineR:
7353                 case MonoInlineI:
7354                         ip += 5;
7355                         break;
7356                 case MonoInlineVar:
7357                         ip += 3;
7358                         break;
7359                 case MonoShortInlineVar:
7360                 case MonoShortInlineI:
7361                         ip += 2;
7362                         break;
7363                 case MonoShortInlineBrTarget:
7364                         target = start + cli_addr + 2 + (signed char)ip [1];
7365                         GET_BBLOCK (cfg, bblock, target);
7366                         ip += 2;
7367                         if (ip < end)
7368                                 GET_BBLOCK (cfg, bblock, ip);
7369                         break;
7370                 case MonoInlineBrTarget:
7371                         target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
7372                         GET_BBLOCK (cfg, bblock, target);
7373                         ip += 5;
7374                         if (ip < end)
7375                                 GET_BBLOCK (cfg, bblock, ip);
7376                         break;
7377                 case MonoInlineSwitch: {
7378                         guint32 n = read32 (ip + 1);
7379                         guint32 j;
7380                         ip += 5;
7381                         cli_addr += 5 + 4 * n;
7382                         target = start + cli_addr;
7383                         GET_BBLOCK (cfg, bblock, target);
7384                         
7385                         for (j = 0; j < n; ++j) {
7386                                 target = start + cli_addr + (gint32)read32 (ip);
7387                                 GET_BBLOCK (cfg, bblock, target);
7388                                 ip += 4;
7389                         }
7390                         break;
7391                 }
7392                 case MonoInlineR:
7393                 case MonoInlineI8:
7394                         ip += 9;
7395                         break;
7396                 default:
7397                         g_assert_not_reached ();
7398                 }
7399
7400                 if (i == CEE_THROW) {
7401                         unsigned char *bb_start = ip - 1;
7402                         
7403                         /* Find the start of the bblock containing the throw */
7404                         bblock = NULL;
7405                         while ((bb_start >= start) && !bblock) {
7406                                 bblock = cfg->cil_offset_to_bb [(bb_start) - start];
7407                                 bb_start --;
7408                         }
7409                         if (bblock)
7410                                 bblock->out_of_line = 1;
7411                 }
7412         }
7413         return 0;
7414 unverified:
7415 exception_exit:
7416         *pos = ip;
7417         return 1;
7418 }
7419
7420 static inline MonoMethod *
7421 mini_get_method_allow_open (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context, MonoError *error)
7422 {
7423         MonoMethod *method;
7424
7425         mono_error_init (error);
7426
7427         if (m->wrapper_type != MONO_WRAPPER_NONE) {
7428                 method = (MonoMethod *)mono_method_get_wrapper_data (m, token);
7429                 if (context) {
7430                         method = mono_class_inflate_generic_method_checked (method, context, error);
7431                 }
7432         } else {
7433                 method = mono_get_method_checked (m->klass->image, token, klass, context, error);
7434         }
7435
7436         return method;
7437 }
7438
7439 static inline MonoMethod *
7440 mini_get_method (MonoCompile *cfg, MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
7441 {
7442         MonoError error;
7443         MonoMethod *method = mini_get_method_allow_open (m, token, klass, context, cfg ? &cfg->error : &error);
7444
7445         if (method && cfg && !cfg->gshared && mono_class_is_open_constructed_type (&method->klass->byval_arg)) {
7446                 mono_error_set_bad_image (&cfg->error, cfg->method->klass->image, "Method with open type while not compiling gshared");
7447                 method = NULL;
7448         }
7449
7450         if (!method && !cfg)
7451                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
7452
7453         return method;
7454 }
7455
7456 static inline MonoClass*
7457 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
7458 {
7459         MonoError error;
7460         MonoClass *klass;
7461
7462         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7463                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
7464                 if (context) {
7465                         klass = mono_class_inflate_generic_class_checked (klass, context, &error);
7466                         mono_error_cleanup (&error); /* FIXME don't swallow the error */
7467                 }
7468         } else {
7469                 klass = mono_class_get_and_inflate_typespec_checked (method->klass->image, token, context, &error);
7470                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
7471         }
7472         if (klass)
7473                 mono_class_init (klass);
7474         return klass;
7475 }
7476
7477 static inline MonoMethodSignature*
7478 mini_get_signature (MonoMethod *method, guint32 token, MonoGenericContext *context, MonoError *error)
7479 {
7480         MonoMethodSignature *fsig;
7481
7482         mono_error_init (error);
7483         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7484                 fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
7485         } else {
7486                 fsig = mono_metadata_parse_signature_checked (method->klass->image, token, error);
7487                 return_val_if_nok (error, NULL);
7488         }
7489         if (context) {
7490                 fsig = mono_inflate_generic_signature(fsig, context, error);
7491         }
7492         return fsig;
7493 }
7494
7495 static MonoMethod*
7496 throw_exception (void)
7497 {
7498         static MonoMethod *method = NULL;
7499
7500         if (!method) {
7501                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
7502                 method = mono_class_get_method_from_name (secman->securitymanager, "ThrowException", 1);
7503         }
7504         g_assert (method);
7505         return method;
7506 }
7507
7508 static void
7509 emit_throw_exception (MonoCompile *cfg, MonoException *ex)
7510 {
7511         MonoMethod *thrower = throw_exception ();
7512         MonoInst *args [1];
7513
7514         EMIT_NEW_PCONST (cfg, args [0], ex);
7515         mono_emit_method_call (cfg, thrower, args, NULL);
7516 }
7517
7518 /*
7519  * Return the original method is a wrapper is specified. We can only access 
7520  * the custom attributes from the original method.
7521  */
7522 static MonoMethod*
7523 get_original_method (MonoMethod *method)
7524 {
7525         if (method->wrapper_type == MONO_WRAPPER_NONE)
7526                 return method;
7527
7528         /* native code (which is like Critical) can call any managed method XXX FIXME XXX to validate all usages */
7529         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)
7530                 return NULL;
7531
7532         /* in other cases we need to find the original method */
7533         return mono_marshal_method_from_wrapper (method);
7534 }
7535
7536 static void
7537 ensure_method_is_allowed_to_access_field (MonoCompile *cfg, MonoMethod *caller, MonoClassField *field)
7538 {
7539         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
7540         MonoException *ex = mono_security_core_clr_is_field_access_allowed (get_original_method (caller), field);
7541         if (ex)
7542                 emit_throw_exception (cfg, ex);
7543 }
7544
7545 static void
7546 ensure_method_is_allowed_to_call_method (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee)
7547 {
7548         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
7549         MonoException *ex = mono_security_core_clr_is_call_allowed (get_original_method (caller), callee);
7550         if (ex)
7551                 emit_throw_exception (cfg, ex);
7552 }
7553
7554 /*
7555  * Check that the IL instructions at ip are the array initialization
7556  * sequence and return the pointer to the data and the size.
7557  */
7558 static const char*
7559 initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, MonoClass *klass, guint32 len, int *out_size, guint32 *out_field_token)
7560 {
7561         /*
7562          * newarr[System.Int32]
7563          * dup
7564          * ldtoken field valuetype ...
7565          * call void class [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle)
7566          */
7567         if (ip [0] == CEE_DUP && ip [1] == CEE_LDTOKEN && ip [5] == 0x4 && ip [6] == CEE_CALL) {
7568                 MonoError error;
7569                 guint32 token = read32 (ip + 7);
7570                 guint32 field_token = read32 (ip + 2);
7571                 guint32 field_index = field_token & 0xffffff;
7572                 guint32 rva;
7573                 const char *data_ptr;
7574                 int size = 0;
7575                 MonoMethod *cmethod;
7576                 MonoClass *dummy_class;
7577                 MonoClassField *field = mono_field_from_token_checked (method->klass->image, field_token, &dummy_class, NULL, &error);
7578                 int dummy_align;
7579
7580                 if (!field) {
7581                         mono_error_cleanup (&error); /* FIXME don't swallow the error */
7582                         return NULL;
7583                 }
7584
7585                 *out_field_token = field_token;
7586
7587                 cmethod = mini_get_method (NULL, method, token, NULL, NULL);
7588                 if (!cmethod)
7589                         return NULL;
7590                 if (strcmp (cmethod->name, "InitializeArray") || strcmp (cmethod->klass->name, "RuntimeHelpers") || cmethod->klass->image != mono_defaults.corlib)
7591                         return NULL;
7592                 switch (mono_type_get_underlying_type (&klass->byval_arg)->type) {
7593                 case MONO_TYPE_BOOLEAN:
7594                 case MONO_TYPE_I1:
7595                 case MONO_TYPE_U1:
7596                         size = 1; break;
7597                 /* we need to swap on big endian, so punt. Should we handle R4 and R8 as well? */
7598 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
7599                 case MONO_TYPE_CHAR:
7600                 case MONO_TYPE_I2:
7601                 case MONO_TYPE_U2:
7602                         size = 2; break;
7603                 case MONO_TYPE_I4:
7604                 case MONO_TYPE_U4:
7605                 case MONO_TYPE_R4:
7606                         size = 4; break;
7607                 case MONO_TYPE_R8:
7608                 case MONO_TYPE_I8:
7609                 case MONO_TYPE_U8:
7610                         size = 8; break;
7611 #endif
7612                 default:
7613                         return NULL;
7614                 }
7615                 size *= len;
7616                 if (size > mono_type_size (field->type, &dummy_align))
7617                     return NULL;
7618                 *out_size = size;
7619                 /*g_print ("optimized in %s: size: %d, numelems: %d\n", method->name, size, newarr->inst_newa_len->inst_c0);*/
7620                 if (!image_is_dynamic (method->klass->image)) {
7621                         field_index = read32 (ip + 2) & 0xffffff;
7622                         mono_metadata_field_info (method->klass->image, field_index - 1, NULL, &rva, NULL);
7623                         data_ptr = mono_image_rva_map (method->klass->image, rva);
7624                         /*g_print ("field: 0x%08x, rva: %d, rva_ptr: %p\n", read32 (ip + 2), rva, data_ptr);*/
7625                         /* for aot code we do the lookup on load */
7626                         if (aot && data_ptr)
7627                                 return (const char *)GUINT_TO_POINTER (rva);
7628                 } else {
7629                         /*FIXME is it possible to AOT a SRE assembly not meant to be saved? */ 
7630                         g_assert (!aot);
7631                         data_ptr = mono_field_get_data (field);
7632                 }
7633                 return data_ptr;
7634         }
7635         return NULL;
7636 }
7637
7638 static void
7639 set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsigned char *ip)
7640 {
7641         MonoError error;
7642         char *method_fname = mono_method_full_name (method, TRUE);
7643         char *method_code;
7644         MonoMethodHeader *header = mono_method_get_header_checked (method, &error);
7645
7646         if (!header) {
7647                 method_code = g_strdup_printf ("could not parse method body due to %s", mono_error_get_message (&error));
7648                 mono_error_cleanup (&error);
7649         } else if (header->code_size == 0)
7650                 method_code = g_strdup ("method body is empty.");
7651         else
7652                 method_code = mono_disasm_code_one (NULL, method, ip, NULL);
7653         mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("Invalid IL code in %s: %s\n", method_fname, method_code));
7654         g_free (method_fname);
7655         g_free (method_code);
7656         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
7657 }
7658
7659 static void
7660 emit_stloc_ir (MonoCompile *cfg, MonoInst **sp, MonoMethodHeader *header, int n)
7661 {
7662         MonoInst *ins;
7663         guint32 opcode = mono_type_to_regmove (cfg, header->locals [n]);
7664         if ((opcode == OP_MOVE) && cfg->cbb->last_ins == sp [0]  &&
7665                         ((sp [0]->opcode == OP_ICONST) || (sp [0]->opcode == OP_I8CONST))) {
7666                 /* Optimize reg-reg moves away */
7667                 /* 
7668                  * Can't optimize other opcodes, since sp[0] might point to
7669                  * the last ins of a decomposed opcode.
7670                  */
7671                 sp [0]->dreg = (cfg)->locals [n]->dreg;
7672         } else {
7673                 EMIT_NEW_LOCSTORE (cfg, ins, n, *sp);
7674         }
7675 }
7676
7677 /*
7678  * ldloca inhibits many optimizations so try to get rid of it in common
7679  * cases.
7680  */
7681 static inline unsigned char *
7682 emit_optimized_ldloca_ir (MonoCompile *cfg, unsigned char *ip, unsigned char *end, int size)
7683 {
7684         int local, token;
7685         MonoClass *klass;
7686         MonoType *type;
7687
7688         if (size == 1) {
7689                 local = ip [1];
7690                 ip += 2;
7691         } else {
7692                 local = read16 (ip + 2);
7693                 ip += 4;
7694         }
7695         
7696         if (ip + 6 < end && (ip [0] == CEE_PREFIX1) && (ip [1] == CEE_INITOBJ) && ip_in_bb (cfg, cfg->cbb, ip + 1)) {
7697                 /* From the INITOBJ case */
7698                 token = read32 (ip + 2);
7699                 klass = mini_get_class (cfg->current_method, token, cfg->generic_context);
7700                 CHECK_TYPELOAD (klass);
7701                 type = mini_get_underlying_type (&klass->byval_arg);
7702                 emit_init_local (cfg, local, type, TRUE);
7703                 return ip + 6;
7704         }
7705  exception_exit:
7706         return NULL;
7707 }
7708
7709 static MonoInst*
7710 emit_llvmonly_virtual_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used, MonoInst **sp)
7711 {
7712         MonoInst *icall_args [16];
7713         MonoInst *call_target, *ins, *vtable_ins;
7714         int arg_reg, this_reg, vtable_reg;
7715         gboolean is_iface = cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE;
7716         gboolean is_gsharedvt = cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig);
7717         gboolean variant_iface = FALSE;
7718         guint32 slot;
7719         int offset;
7720
7721         /*
7722          * In llvm-only mode, vtables contain function descriptors instead of
7723          * method addresses/trampolines.
7724          */
7725         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
7726
7727         if (is_iface)
7728                 slot = mono_method_get_imt_slot (cmethod);
7729         else
7730                 slot = mono_method_get_vtable_index (cmethod);
7731
7732         this_reg = sp [0]->dreg;
7733
7734         if (is_iface && mono_class_has_variant_generic_params (cmethod->klass))
7735                 variant_iface = TRUE;
7736
7737         if (!fsig->generic_param_count && !is_iface && !is_gsharedvt) {
7738                 /*
7739                  * The simplest case, a normal virtual call.
7740                  */
7741                 int slot_reg = alloc_preg (cfg);
7742                 int addr_reg = alloc_preg (cfg);
7743                 int arg_reg = alloc_preg (cfg);
7744                 MonoBasicBlock *non_null_bb;
7745
7746                 vtable_reg = alloc_preg (cfg);
7747                 EMIT_NEW_LOAD_MEMBASE (cfg, vtable_ins, OP_LOAD_MEMBASE, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
7748                 offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) + (slot * SIZEOF_VOID_P);
7749
7750                 /* Load the vtable slot, which contains a function descriptor. */
7751                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, slot_reg, vtable_reg, offset);
7752
7753                 NEW_BBLOCK (cfg, non_null_bb);
7754
7755                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, slot_reg, 0);
7756                 cfg->cbb->last_ins->flags |= MONO_INST_LIKELY;
7757                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, non_null_bb);
7758
7759                 /* Slow path */
7760                 // FIXME: Make the wrapper use the preserveall cconv
7761                 // FIXME: Use one icall per slot for small slot numbers ?
7762                 icall_args [0] = vtable_ins;
7763                 EMIT_NEW_ICONST (cfg, icall_args [1], slot);
7764                 /* Make the icall return the vtable slot value to save some code space */
7765                 ins = mono_emit_jit_icall (cfg, mono_init_vtable_slot, icall_args);
7766                 ins->dreg = slot_reg;
7767                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, non_null_bb);
7768
7769                 /* Fastpath */
7770                 MONO_START_BB (cfg, non_null_bb);
7771                 /* Load the address + arg from the vtable slot */
7772                 EMIT_NEW_LOAD_MEMBASE (cfg, call_target, OP_LOAD_MEMBASE, addr_reg, slot_reg, 0);
7773                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, arg_reg, slot_reg, SIZEOF_VOID_P);
7774
7775                 return emit_extra_arg_calli (cfg, fsig, sp, arg_reg, call_target);
7776         }
7777
7778         if (!fsig->generic_param_count && is_iface && !variant_iface && !is_gsharedvt) {
7779                 /*
7780                  * A simple interface call
7781                  *
7782                  * We make a call through an imt slot to obtain the function descriptor we need to call.
7783                  * The imt slot contains a function descriptor for a runtime function + arg.
7784                  */
7785                 int slot_reg = alloc_preg (cfg);
7786                 int addr_reg = alloc_preg (cfg);
7787                 int arg_reg = alloc_preg (cfg);
7788                 MonoInst *thunk_addr_ins, *thunk_arg_ins, *ftndesc_ins;
7789
7790                 vtable_reg = alloc_preg (cfg);
7791                 EMIT_NEW_LOAD_MEMBASE (cfg, vtable_ins, OP_LOAD_MEMBASE, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
7792                 offset = ((gint32)slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
7793
7794                 /*
7795                  * The slot is already initialized when the vtable is created so there is no need
7796                  * to check it here.
7797                  */
7798
7799                 /* Load the imt slot, which contains a function descriptor. */
7800                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, slot_reg, vtable_reg, offset);
7801
7802                 /* Load the address + arg of the imt thunk from the imt slot */
7803                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_addr_ins, OP_LOAD_MEMBASE, addr_reg, slot_reg, 0);
7804                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_arg_ins, OP_LOAD_MEMBASE, arg_reg, slot_reg, SIZEOF_VOID_P);
7805                 /*
7806                  * IMT thunks in llvm-only mode are C functions which take an info argument
7807                  * plus the imt method and return the ftndesc to call.
7808                  */
7809                 icall_args [0] = thunk_arg_ins;
7810                 icall_args [1] = emit_get_rgctx_method (cfg, context_used,
7811                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD);
7812                 ftndesc_ins = mono_emit_calli (cfg, helper_sig_llvmonly_imt_thunk, icall_args, thunk_addr_ins, NULL, NULL);
7813
7814                 return emit_llvmonly_calli (cfg, fsig, sp, ftndesc_ins);
7815         }
7816
7817         if ((fsig->generic_param_count || variant_iface) && !is_gsharedvt) {
7818                 /*
7819                  * This is similar to the interface case, the vtable slot points to an imt thunk which is
7820                  * dynamically extended as more instantiations are discovered.
7821                  * This handles generic virtual methods both on classes and interfaces.
7822                  */
7823                 int slot_reg = alloc_preg (cfg);
7824                 int addr_reg = alloc_preg (cfg);
7825                 int arg_reg = alloc_preg (cfg);
7826                 int ftndesc_reg = alloc_preg (cfg);
7827                 MonoInst *thunk_addr_ins, *thunk_arg_ins, *ftndesc_ins;
7828                 MonoBasicBlock *slowpath_bb, *end_bb;
7829
7830                 NEW_BBLOCK (cfg, slowpath_bb);
7831                 NEW_BBLOCK (cfg, end_bb);
7832
7833                 vtable_reg = alloc_preg (cfg);
7834                 EMIT_NEW_LOAD_MEMBASE (cfg, vtable_ins, OP_LOAD_MEMBASE, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
7835                 if (is_iface)
7836                         offset = ((gint32)slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
7837                 else
7838                         offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) + (slot * SIZEOF_VOID_P);
7839
7840                 /* Load the slot, which contains a function descriptor. */
7841                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, slot_reg, vtable_reg, offset);
7842
7843                 /* These slots are not initialized, so fall back to the slow path until they are initialized */
7844                 /* That happens when mono_method_add_generic_virtual_invocation () creates an IMT thunk */
7845                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, slot_reg, 0);
7846                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, slowpath_bb);
7847
7848                 /* Fastpath */
7849                 /* Same as with iface calls */
7850                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_addr_ins, OP_LOAD_MEMBASE, addr_reg, slot_reg, 0);
7851                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_arg_ins, OP_LOAD_MEMBASE, arg_reg, slot_reg, SIZEOF_VOID_P);
7852                 icall_args [0] = thunk_arg_ins;
7853                 icall_args [1] = emit_get_rgctx_method (cfg, context_used,
7854                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD);
7855                 ftndesc_ins = mono_emit_calli (cfg, helper_sig_llvmonly_imt_thunk, icall_args, thunk_addr_ins, NULL, NULL);
7856                 ftndesc_ins->dreg = ftndesc_reg;
7857                 /*
7858                  * Unlike normal iface calls, these imt thunks can return NULL, i.e. when they are passed an instantiation
7859                  * they don't know about yet. Fall back to the slowpath in that case.
7860                  */
7861                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, ftndesc_reg, 0);
7862                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, slowpath_bb);
7863
7864                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
7865
7866                 /* Slowpath */
7867                 MONO_START_BB (cfg, slowpath_bb);
7868                 icall_args [0] = vtable_ins;
7869                 EMIT_NEW_ICONST (cfg, icall_args [1], slot);
7870                 icall_args [2] = emit_get_rgctx_method (cfg, context_used,
7871                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD);
7872                 if (is_iface)
7873                         ftndesc_ins = mono_emit_jit_icall (cfg, mono_resolve_generic_virtual_iface_call, icall_args);
7874                 else
7875                         ftndesc_ins = mono_emit_jit_icall (cfg, mono_resolve_generic_virtual_call, icall_args);
7876                 ftndesc_ins->dreg = ftndesc_reg;
7877                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
7878
7879                 /* Common case */
7880                 MONO_START_BB (cfg, end_bb);
7881                 return emit_llvmonly_calli (cfg, fsig, sp, ftndesc_ins);
7882         }
7883
7884         /*
7885          * Non-optimized cases
7886          */
7887         icall_args [0] = sp [0];
7888         EMIT_NEW_ICONST (cfg, icall_args [1], slot);
7889
7890         icall_args [2] = emit_get_rgctx_method (cfg, context_used,
7891                                                                                         cmethod, MONO_RGCTX_INFO_METHOD);
7892
7893         arg_reg = alloc_preg (cfg);
7894         MONO_EMIT_NEW_PCONST (cfg, arg_reg, NULL);
7895         EMIT_NEW_VARLOADA_VREG (cfg, icall_args [3], arg_reg, &mono_defaults.int_class->byval_arg);
7896
7897         g_assert (is_gsharedvt);
7898         if (is_iface)
7899                 call_target = mono_emit_jit_icall (cfg, mono_resolve_iface_call_gsharedvt, icall_args);
7900         else
7901                 call_target = mono_emit_jit_icall (cfg, mono_resolve_vcall_gsharedvt, icall_args);
7902
7903         /*
7904          * Pass the extra argument even if the callee doesn't receive it, most
7905          * calling conventions allow this.
7906          */
7907         return emit_extra_arg_calli (cfg, fsig, sp, arg_reg, call_target);
7908 }
7909
7910 static gboolean
7911 is_exception_class (MonoClass *klass)
7912 {
7913         while (klass) {
7914                 if (klass == mono_defaults.exception_class)
7915                         return TRUE;
7916                 klass = klass->parent;
7917         }
7918         return FALSE;
7919 }
7920
7921 /*
7922  * is_jit_optimizer_disabled:
7923  *
7924  *   Determine whenever M's assembly has a DebuggableAttribute with the
7925  * IsJITOptimizerDisabled flag set.
7926  */
7927 static gboolean
7928 is_jit_optimizer_disabled (MonoMethod *m)
7929 {
7930         MonoError error;
7931         MonoAssembly *ass = m->klass->image->assembly;
7932         MonoCustomAttrInfo* attrs;
7933         MonoClass *klass;
7934         int i;
7935         gboolean val = FALSE;
7936
7937         g_assert (ass);
7938         if (ass->jit_optimizer_disabled_inited)
7939                 return ass->jit_optimizer_disabled;
7940
7941         klass = mono_class_try_get_debuggable_attribute_class ();
7942
7943         if (!klass) {
7944                 /* Linked away */
7945                 ass->jit_optimizer_disabled = FALSE;
7946                 mono_memory_barrier ();
7947                 ass->jit_optimizer_disabled_inited = TRUE;
7948                 return FALSE;
7949         }
7950
7951         attrs = mono_custom_attrs_from_assembly_checked (ass, &error);
7952         mono_error_cleanup (&error); /* FIXME don't swallow the error */
7953         if (attrs) {
7954                 for (i = 0; i < attrs->num_attrs; ++i) {
7955                         MonoCustomAttrEntry *attr = &attrs->attrs [i];
7956                         const gchar *p;
7957                         MonoMethodSignature *sig;
7958
7959                         if (!attr->ctor || attr->ctor->klass != klass)
7960                                 continue;
7961                         /* Decode the attribute. See reflection.c */
7962                         p = (const char*)attr->data;
7963                         g_assert (read16 (p) == 0x0001);
7964                         p += 2;
7965
7966                         // FIXME: Support named parameters
7967                         sig = mono_method_signature (attr->ctor);
7968                         if (sig->param_count != 2 || sig->params [0]->type != MONO_TYPE_BOOLEAN || sig->params [1]->type != MONO_TYPE_BOOLEAN)
7969                                 continue;
7970                         /* Two boolean arguments */
7971                         p ++;
7972                         val = *p;
7973                 }
7974                 mono_custom_attrs_free (attrs);
7975         }
7976
7977         ass->jit_optimizer_disabled = val;
7978         mono_memory_barrier ();
7979         ass->jit_optimizer_disabled_inited = TRUE;
7980
7981         return val;
7982 }
7983
7984 static gboolean
7985 is_supported_tail_call (MonoCompile *cfg, MonoMethod *method, MonoMethod *cmethod, MonoMethodSignature *fsig, int call_opcode)
7986 {
7987         gboolean supported_tail_call;
7988         int i;
7989
7990         supported_tail_call = mono_arch_tail_call_supported (cfg, mono_method_signature (method), mono_method_signature (cmethod));
7991
7992         for (i = 0; i < fsig->param_count; ++i) {
7993                 if (fsig->params [i]->byref || fsig->params [i]->type == MONO_TYPE_PTR || fsig->params [i]->type == MONO_TYPE_FNPTR)
7994                         /* These can point to the current method's stack */
7995                         supported_tail_call = FALSE;
7996         }
7997         if (fsig->hasthis && cmethod->klass->valuetype)
7998                 /* this might point to the current method's stack */
7999                 supported_tail_call = FALSE;
8000         if (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
8001                 supported_tail_call = FALSE;
8002         if (cfg->method->save_lmf)
8003                 supported_tail_call = FALSE;
8004         if (cmethod->wrapper_type && cmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD)
8005                 supported_tail_call = FALSE;
8006         if (call_opcode != CEE_CALL)
8007                 supported_tail_call = FALSE;
8008
8009         /* Debugging support */
8010 #if 0
8011         if (supported_tail_call) {
8012                 if (!mono_debug_count ())
8013                         supported_tail_call = FALSE;
8014         }
8015 #endif
8016
8017         return supported_tail_call;
8018 }
8019
8020 /*
8021  * handle_ctor_call:
8022  *
8023  *   Handle calls made to ctors from NEWOBJ opcodes.
8024  */
8025 static void
8026 handle_ctor_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used,
8027                                   MonoInst **sp, guint8 *ip, int *inline_costs)
8028 {
8029         MonoInst *vtable_arg = NULL, *callvirt_this_arg = NULL, *ins;
8030
8031         if (cmethod->klass->valuetype && mono_class_generic_sharing_enabled (cmethod->klass) &&
8032                                         mono_method_is_generic_sharable (cmethod, TRUE)) {
8033                 if (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst) {
8034                         mono_class_vtable (cfg->domain, cmethod->klass);
8035                         CHECK_TYPELOAD (cmethod->klass);
8036
8037                         vtable_arg = emit_get_rgctx_method (cfg, context_used,
8038                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
8039                 } else {
8040                         if (context_used) {
8041                                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
8042                                                                                                    cmethod->klass, MONO_RGCTX_INFO_VTABLE);
8043                         } else {
8044                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
8045
8046                                 CHECK_TYPELOAD (cmethod->klass);
8047                                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
8048                         }
8049                 }
8050         }
8051
8052         /* Avoid virtual calls to ctors if possible */
8053         if (mono_class_is_marshalbyref (cmethod->klass))
8054                 callvirt_this_arg = sp [0];
8055
8056         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_ctor (cfg, cmethod, fsig, sp))) {
8057                 g_assert (MONO_TYPE_IS_VOID (fsig->ret));
8058                 CHECK_CFG_EXCEPTION;
8059         } else if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used && !vtable_arg &&
8060                            mono_method_check_inlining (cfg, cmethod) &&
8061                            !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE)) {
8062                 int costs;
8063
8064                 if ((costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, FALSE))) {
8065                         cfg->real_offset += 5;
8066
8067                         *inline_costs += costs - 5;
8068                 } else {
8069                         INLINE_FAILURE ("inline failure");
8070                         // FIXME-VT: Clean this up
8071                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))
8072                                 GSHAREDVT_FAILURE(*ip);
8073                         mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, callvirt_this_arg, NULL, NULL);
8074                 }
8075         } else if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
8076                 MonoInst *addr;
8077
8078                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE);
8079
8080                 if (cfg->llvm_only) {
8081                         // FIXME: Avoid initializing vtable_arg
8082                         emit_llvmonly_calli (cfg, fsig, sp, addr);
8083                 } else {
8084                         mono_emit_calli (cfg, fsig, sp, addr, NULL, vtable_arg);
8085                 }
8086         } else if (context_used &&
8087                            ((!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
8088                                  !mono_class_generic_sharing_enabled (cmethod->klass)) || cfg->gsharedvt)) {
8089                 MonoInst *cmethod_addr;
8090
8091                 /* Generic calls made out of gsharedvt methods cannot be patched, so use an indirect call */
8092
8093                 if (cfg->llvm_only) {
8094                         MonoInst *addr = emit_get_rgctx_method (cfg, context_used, cmethod,
8095                                                                                                         MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
8096                         emit_llvmonly_calli (cfg, fsig, sp, addr);
8097                 } else {
8098                         cmethod_addr = emit_get_rgctx_method (cfg, context_used,
8099                                                                                                   cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
8100
8101                         mono_emit_calli (cfg, fsig, sp, cmethod_addr, NULL, vtable_arg);
8102                 }
8103         } else {
8104                 INLINE_FAILURE ("ctor call");
8105                 ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp,
8106                                                                                   callvirt_this_arg, NULL, vtable_arg);
8107         }
8108  exception_exit:
8109         return;
8110 }
8111
8112 static void
8113 emit_setret (MonoCompile *cfg, MonoInst *val)
8114 {
8115         MonoType *ret_type = mini_get_underlying_type (mono_method_signature (cfg->method)->ret);
8116         MonoInst *ins;
8117
8118         if (mini_type_to_stind (cfg, ret_type) == CEE_STOBJ) {
8119                 MonoInst *ret_addr;
8120
8121                 if (!cfg->vret_addr) {
8122                         EMIT_NEW_VARSTORE (cfg, ins, cfg->ret, ret_type, val);
8123                 } else {
8124                         EMIT_NEW_RETLOADA (cfg, ret_addr);
8125
8126                         EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STOREV_MEMBASE, ret_addr->dreg, 0, val->dreg);
8127                         ins->klass = mono_class_from_mono_type (ret_type);
8128                 }
8129         } else {
8130 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
8131                 if (COMPILE_SOFT_FLOAT (cfg) && !ret_type->byref && ret_type->type == MONO_TYPE_R4) {
8132                         MonoInst *iargs [1];
8133                         MonoInst *conv;
8134
8135                         iargs [0] = val;
8136                         conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
8137                         mono_arch_emit_setret (cfg, cfg->method, conv);
8138                 } else {
8139                         mono_arch_emit_setret (cfg, cfg->method, val);
8140                 }
8141 #else
8142                 mono_arch_emit_setret (cfg, cfg->method, val);
8143 #endif
8144         }
8145 }
8146
8147 /*
8148  * mono_method_to_ir:
8149  *
8150  *   Translate the .net IL into linear IR.
8151  */
8152 int
8153 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
8154                    MonoInst *return_var, MonoInst **inline_args, 
8155                    guint inline_offset, gboolean is_virtual_call)
8156 {
8157         MonoError error;
8158         MonoInst *ins, **sp, **stack_start;
8159         MonoBasicBlock *tblock = NULL, *init_localsbb = NULL;
8160         MonoSimpleBasicBlock *bb = NULL, *original_bb = NULL;
8161         MonoMethod *cmethod, *method_definition;
8162         MonoInst **arg_array;
8163         MonoMethodHeader *header;
8164         MonoImage *image;
8165         guint32 token, ins_flag;
8166         MonoClass *klass;
8167         MonoClass *constrained_class = NULL;
8168         unsigned char *ip, *end, *target, *err_pos;
8169         MonoMethodSignature *sig;
8170         MonoGenericContext *generic_context = NULL;
8171         MonoGenericContainer *generic_container = NULL;
8172         MonoType **param_types;
8173         int i, n, start_new_bblock, dreg;
8174         int num_calls = 0, inline_costs = 0;
8175         int breakpoint_id = 0;
8176         guint num_args;
8177         GSList *class_inits = NULL;
8178         gboolean dont_verify, dont_verify_stloc, readonly = FALSE;
8179         int context_used;
8180         gboolean init_locals, seq_points, skip_dead_blocks;
8181         gboolean sym_seq_points = FALSE;
8182         MonoDebugMethodInfo *minfo;
8183         MonoBitSet *seq_point_locs = NULL;
8184         MonoBitSet *seq_point_set_locs = NULL;
8185
8186         cfg->disable_inline = is_jit_optimizer_disabled (method);
8187
8188         /* serialization and xdomain stuff may need access to private fields and methods */
8189         dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
8190         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE;
8191         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH;
8192         dont_verify |= method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; /* bug #77896 */
8193         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP;
8194         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP_INVOKE;
8195
8196         /* still some type unsafety issues in marshal wrappers... (unknown is PtrToStructure) */
8197         dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE;
8198         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_UNKNOWN;
8199         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED;
8200         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_STELEMREF;
8201
8202         image = method->klass->image;
8203         header = mono_method_get_header_checked (method, &cfg->error);
8204         if (!header) {
8205                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
8206                 goto exception_exit;
8207         } else {
8208                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
8209         }
8210
8211         generic_container = mono_method_get_generic_container (method);
8212         sig = mono_method_signature (method);
8213         num_args = sig->hasthis + sig->param_count;
8214         ip = (unsigned char*)header->code;
8215         cfg->cil_start = ip;
8216         end = ip + header->code_size;
8217         cfg->stat_cil_code_size += header->code_size;
8218
8219         seq_points = cfg->gen_seq_points && cfg->method == method;
8220
8221         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
8222                 /* We could hit a seq point before attaching to the JIT (#8338) */
8223                 seq_points = FALSE;
8224         }
8225
8226         if (cfg->gen_sdb_seq_points && cfg->method == method) {
8227                 minfo = mono_debug_lookup_method (method);
8228                 if (minfo) {
8229                         MonoSymSeqPoint *sps;
8230                         int i, n_il_offsets;
8231
8232                         mono_debug_get_seq_points (minfo, NULL, NULL, NULL, &sps, &n_il_offsets);
8233                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
8234                         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);
8235                         sym_seq_points = TRUE;
8236                         for (i = 0; i < n_il_offsets; ++i) {
8237                                 if (sps [i].il_offset < header->code_size)
8238                                         mono_bitset_set_fast (seq_point_locs, sps [i].il_offset);
8239                         }
8240                         g_free (sps);
8241                 } else if (!method->wrapper_type && !method->dynamic && mono_debug_image_has_debug_info (method->klass->image)) {
8242                         /* Methods without line number info like auto-generated property accessors */
8243                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
8244                         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);
8245                         sym_seq_points = TRUE;
8246                 }
8247         }
8248
8249         /* 
8250          * Methods without init_locals set could cause asserts in various passes
8251          * (#497220). To work around this, we emit dummy initialization opcodes
8252          * (OP_DUMMY_ICONST etc.) which generate no code. These are only supported
8253          * on some platforms.
8254          */
8255         if ((cfg->opt & MONO_OPT_UNSAFE) && cfg->backend->have_dummy_init)
8256                 init_locals = header->init_locals;
8257         else
8258                 init_locals = TRUE;
8259
8260         method_definition = method;
8261         while (method_definition->is_inflated) {
8262                 MonoMethodInflated *imethod = (MonoMethodInflated *) method_definition;
8263                 method_definition = imethod->declaring;
8264         }
8265
8266         /* SkipVerification is not allowed if core-clr is enabled */
8267         if (!dont_verify && mini_assembly_can_skip_verification (cfg->domain, method)) {
8268                 dont_verify = TRUE;
8269                 dont_verify_stloc = TRUE;
8270         }
8271
8272         if (sig->is_inflated)
8273                 generic_context = mono_method_get_context (method);
8274         else if (generic_container)
8275                 generic_context = &generic_container->context;
8276         cfg->generic_context = generic_context;
8277
8278         if (!cfg->gshared)
8279                 g_assert (!sig->has_type_parameters);
8280
8281         if (sig->generic_param_count && method->wrapper_type == MONO_WRAPPER_NONE) {
8282                 g_assert (method->is_inflated);
8283                 g_assert (mono_method_get_context (method)->method_inst);
8284         }
8285         if (method->is_inflated && mono_method_get_context (method)->method_inst)
8286                 g_assert (sig->generic_param_count);
8287
8288         if (cfg->method == method) {
8289                 cfg->real_offset = 0;
8290         } else {
8291                 cfg->real_offset = inline_offset;
8292         }
8293
8294         cfg->cil_offset_to_bb = (MonoBasicBlock **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoBasicBlock*) * header->code_size);
8295         cfg->cil_offset_to_bb_len = header->code_size;
8296
8297         cfg->current_method = method;
8298
8299         if (cfg->verbose_level > 2)
8300                 printf ("method to IR %s\n", mono_method_full_name (method, TRUE));
8301
8302         param_types = (MonoType **)mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * num_args);
8303         if (sig->hasthis)
8304                 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
8305         for (n = 0; n < sig->param_count; ++n)
8306                 param_types [n + sig->hasthis] = sig->params [n];
8307         cfg->arg_types = param_types;
8308
8309         cfg->dont_inline = g_list_prepend (cfg->dont_inline, method);
8310         if (cfg->method == method) {
8311
8312                 if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
8313                         cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
8314
8315                 /* ENTRY BLOCK */
8316                 NEW_BBLOCK (cfg, start_bblock);
8317                 cfg->bb_entry = start_bblock;
8318                 start_bblock->cil_code = NULL;
8319                 start_bblock->cil_length = 0;
8320
8321                 /* EXIT BLOCK */
8322                 NEW_BBLOCK (cfg, end_bblock);
8323                 cfg->bb_exit = end_bblock;
8324                 end_bblock->cil_code = NULL;
8325                 end_bblock->cil_length = 0;
8326                 end_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
8327                 g_assert (cfg->num_bblocks == 2);
8328
8329                 arg_array = cfg->args;
8330
8331                 if (header->num_clauses) {
8332                         cfg->spvars = g_hash_table_new (NULL, NULL);
8333                         cfg->exvars = g_hash_table_new (NULL, NULL);
8334                 }
8335                 /* handle exception clauses */
8336                 for (i = 0; i < header->num_clauses; ++i) {
8337                         MonoBasicBlock *try_bb;
8338                         MonoExceptionClause *clause = &header->clauses [i];
8339                         GET_BBLOCK (cfg, try_bb, ip + clause->try_offset);
8340
8341                         try_bb->real_offset = clause->try_offset;
8342                         try_bb->try_start = TRUE;
8343                         try_bb->region = ((i + 1) << 8) | clause->flags;
8344                         GET_BBLOCK (cfg, tblock, ip + clause->handler_offset);
8345                         tblock->real_offset = clause->handler_offset;
8346                         tblock->flags |= BB_EXCEPTION_HANDLER;
8347
8348                         /*
8349                          * Linking the try block with the EH block hinders inlining as we won't be able to 
8350                          * merge the bblocks from inlining and produce an artificial hole for no good reason.
8351                          */
8352                         if (COMPILE_LLVM (cfg))
8353                                 link_bblock (cfg, try_bb, tblock);
8354
8355                         if (*(ip + clause->handler_offset) == CEE_POP)
8356                                 tblock->flags |= BB_EXCEPTION_DEAD_OBJ;
8357
8358                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
8359                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER ||
8360                             clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
8361                                 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
8362                                 MONO_ADD_INS (tblock, ins);
8363
8364                                 if (seq_points && clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY && clause->flags != MONO_EXCEPTION_CLAUSE_FILTER) {
8365                                         /* finally clauses already have a seq point */
8366                                         /* seq points for filter clauses are emitted below */
8367                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
8368                                         MONO_ADD_INS (tblock, ins);
8369                                 }
8370
8371                                 /* todo: is a fault block unsafe to optimize? */
8372                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
8373                                         tblock->flags |= BB_EXCEPTION_UNSAFE;
8374                         }
8375
8376                         /*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);
8377                           while (p < end) {
8378                           printf ("%s", mono_disasm_code_one (NULL, method, p, &p));
8379                           }*/
8380                         /* catch and filter blocks get the exception object on the stack */
8381                         if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
8382                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
8383
8384                                 /* mostly like handle_stack_args (), but just sets the input args */
8385                                 /* printf ("handling clause at IL_%04x\n", clause->handler_offset); */
8386                                 tblock->in_scount = 1;
8387                                 tblock->in_stack = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
8388                                 tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
8389
8390                                 cfg->cbb = tblock;
8391
8392 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
8393                                 /* The EH code passes in the exception in a register to both JITted and LLVM compiled code */
8394                                 if (!cfg->compile_llvm) {
8395                                         MONO_INST_NEW (cfg, ins, OP_GET_EX_OBJ);
8396                                         ins->dreg = tblock->in_stack [0]->dreg;
8397                                         MONO_ADD_INS (tblock, ins);
8398                                 }
8399 #else
8400                                 MonoInst *dummy_use;
8401
8402                                 /* 
8403                                  * Add a dummy use for the exvar so its liveness info will be
8404                                  * correct.
8405                                  */
8406                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, tblock->in_stack [0]);
8407 #endif
8408
8409                                 if (seq_points && clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
8410                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
8411                                         MONO_ADD_INS (tblock, ins);
8412                                 }
8413                                 
8414                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
8415                                         GET_BBLOCK (cfg, tblock, ip + clause->data.filter_offset);
8416                                         tblock->flags |= BB_EXCEPTION_HANDLER;
8417                                         tblock->real_offset = clause->data.filter_offset;
8418                                         tblock->in_scount = 1;
8419                                         tblock->in_stack = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
8420                                         /* The filter block shares the exvar with the handler block */
8421                                         tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
8422                                         MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
8423                                         MONO_ADD_INS (tblock, ins);
8424                                 }
8425                         }
8426
8427                         if (clause->flags != MONO_EXCEPTION_CLAUSE_FILTER &&
8428                                         clause->data.catch_class &&
8429                                         cfg->gshared &&
8430                                         mono_class_check_context_used (clause->data.catch_class)) {
8431                                 /*
8432                                  * In shared generic code with catch
8433                                  * clauses containing type variables
8434                                  * the exception handling code has to
8435                                  * be able to get to the rgctx.
8436                                  * Therefore we have to make sure that
8437                                  * the vtable/mrgctx argument (for
8438                                  * static or generic methods) or the
8439                                  * "this" argument (for non-static
8440                                  * methods) are live.
8441                                  */
8442                                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
8443                                                 mini_method_get_context (method)->method_inst ||
8444                                                 method->klass->valuetype) {
8445                                         mono_get_vtable_var (cfg);
8446                                 } else {
8447                                         MonoInst *dummy_use;
8448
8449                                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, arg_array [0]);
8450                                 }
8451                         }
8452                 }
8453         } else {
8454                 arg_array = (MonoInst **) alloca (sizeof (MonoInst *) * num_args);
8455                 cfg->cbb = start_bblock;
8456                 cfg->args = arg_array;
8457                 mono_save_args (cfg, sig, inline_args);
8458         }
8459
8460         /* FIRST CODE BLOCK */
8461         NEW_BBLOCK (cfg, tblock);
8462         tblock->cil_code = ip;
8463         cfg->cbb = tblock;
8464         cfg->ip = ip;
8465
8466         ADD_BBLOCK (cfg, tblock);
8467
8468         if (cfg->method == method) {
8469                 breakpoint_id = mono_debugger_method_has_breakpoint (method);
8470                 if (breakpoint_id) {
8471                         MONO_INST_NEW (cfg, ins, OP_BREAK);
8472                         MONO_ADD_INS (cfg->cbb, ins);
8473                 }
8474         }
8475
8476         /* we use a separate basic block for the initialization code */
8477         NEW_BBLOCK (cfg, init_localsbb);
8478         cfg->bb_init = init_localsbb;
8479         init_localsbb->real_offset = cfg->real_offset;
8480         start_bblock->next_bb = init_localsbb;
8481         init_localsbb->next_bb = cfg->cbb;
8482         link_bblock (cfg, start_bblock, init_localsbb);
8483         link_bblock (cfg, init_localsbb, cfg->cbb);
8484                 
8485         cfg->cbb = init_localsbb;
8486
8487         if (cfg->gsharedvt && cfg->method == method) {
8488                 MonoGSharedVtMethodInfo *info;
8489                 MonoInst *var, *locals_var;
8490                 int dreg;
8491
8492                 info = (MonoGSharedVtMethodInfo *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoGSharedVtMethodInfo));
8493                 info->method = cfg->method;
8494                 info->count_entries = 16;
8495                 info->entries = (MonoRuntimeGenericContextInfoTemplate *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
8496                 cfg->gsharedvt_info = info;
8497
8498                 var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8499                 /* prevent it from being register allocated */
8500                 //var->flags |= MONO_INST_VOLATILE;
8501                 cfg->gsharedvt_info_var = var;
8502
8503                 ins = emit_get_rgctx_gsharedvt_method (cfg, mini_method_check_context_used (cfg, method), method, info);
8504                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, var->dreg, ins->dreg);
8505
8506                 /* Allocate locals */
8507                 locals_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8508                 /* prevent it from being register allocated */
8509                 //locals_var->flags |= MONO_INST_VOLATILE;
8510                 cfg->gsharedvt_locals_var = locals_var;
8511
8512                 dreg = alloc_ireg (cfg);
8513                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, dreg, var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, locals_size));
8514
8515                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
8516                 ins->dreg = locals_var->dreg;
8517                 ins->sreg1 = dreg;
8518                 MONO_ADD_INS (cfg->cbb, ins);
8519                 cfg->gsharedvt_locals_var_ins = ins;
8520                 
8521                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
8522                 /*
8523                 if (init_locals)
8524                         ins->flags |= MONO_INST_INIT;
8525                 */
8526         }
8527
8528         if (mono_security_core_clr_enabled ()) {
8529                 /* check if this is native code, e.g. an icall or a p/invoke */
8530                 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
8531                         MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
8532                         if (wrapped) {
8533                                 gboolean pinvk = (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL);
8534                                 gboolean icall = (wrapped->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL);
8535
8536                                 /* if this ia a native call then it can only be JITted from platform code */
8537                                 if ((icall || pinvk) && method->klass && method->klass->image) {
8538                                         if (!mono_security_core_clr_is_platform_image (method->klass->image)) {
8539                                                 MonoException *ex = icall ? mono_get_exception_security () : 
8540                                                         mono_get_exception_method_access ();
8541                                                 emit_throw_exception (cfg, ex);
8542                                         }
8543                                 }
8544                         }
8545                 }
8546         }
8547
8548         CHECK_CFG_EXCEPTION;
8549
8550         if (header->code_size == 0)
8551                 UNVERIFIED;
8552
8553         if (get_basic_blocks (cfg, header, cfg->real_offset, ip, end, &err_pos)) {
8554                 ip = err_pos;
8555                 UNVERIFIED;
8556         }
8557
8558         if (cfg->method == method)
8559                 mono_debug_init_method (cfg, cfg->cbb, breakpoint_id);
8560
8561         for (n = 0; n < header->num_locals; ++n) {
8562                 if (header->locals [n]->type == MONO_TYPE_VOID && !header->locals [n]->byref)
8563                         UNVERIFIED;
8564         }
8565         class_inits = NULL;
8566
8567         /* We force the vtable variable here for all shared methods
8568            for the possibility that they might show up in a stack
8569            trace where their exact instantiation is needed. */
8570         if (cfg->gshared && method == cfg->method) {
8571                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
8572                                 mini_method_get_context (method)->method_inst ||
8573                                 method->klass->valuetype) {
8574                         mono_get_vtable_var (cfg);
8575                 } else {
8576                         /* FIXME: Is there a better way to do this?
8577                            We need the variable live for the duration
8578                            of the whole method. */
8579                         cfg->args [0]->flags |= MONO_INST_VOLATILE;
8580                 }
8581         }
8582
8583         /* add a check for this != NULL to inlined methods */
8584         if (is_virtual_call) {
8585                 MonoInst *arg_ins;
8586
8587                 NEW_ARGLOAD (cfg, arg_ins, 0);
8588                 MONO_ADD_INS (cfg->cbb, arg_ins);
8589                 MONO_EMIT_NEW_CHECK_THIS (cfg, arg_ins->dreg);
8590         }
8591
8592         skip_dead_blocks = !dont_verify;
8593         if (skip_dead_blocks) {
8594                 original_bb = bb = mono_basic_block_split (method, &cfg->error, header);
8595                 CHECK_CFG_ERROR;
8596                 g_assert (bb);
8597         }
8598
8599         /* we use a spare stack slot in SWITCH and NEWOBJ and others */
8600         stack_start = sp = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
8601
8602         ins_flag = 0;
8603         start_new_bblock = 0;
8604         while (ip < end) {
8605                 if (cfg->method == method)
8606                         cfg->real_offset = ip - header->code;
8607                 else
8608                         cfg->real_offset = inline_offset;
8609                 cfg->ip = ip;
8610
8611                 context_used = 0;
8612
8613                 if (start_new_bblock) {
8614                         cfg->cbb->cil_length = ip - cfg->cbb->cil_code;
8615                         if (start_new_bblock == 2) {
8616                                 g_assert (ip == tblock->cil_code);
8617                         } else {
8618                                 GET_BBLOCK (cfg, tblock, ip);
8619                         }
8620                         cfg->cbb->next_bb = tblock;
8621                         cfg->cbb = tblock;
8622                         start_new_bblock = 0;
8623                         for (i = 0; i < cfg->cbb->in_scount; ++i) {
8624                                 if (cfg->verbose_level > 3)
8625                                         printf ("loading %d from temp %d\n", i, (int)cfg->cbb->in_stack [i]->inst_c0);
8626                                 EMIT_NEW_TEMPLOAD (cfg, ins, cfg->cbb->in_stack [i]->inst_c0);
8627                                 *sp++ = ins;
8628                         }
8629                         if (class_inits)
8630                                 g_slist_free (class_inits);
8631                         class_inits = NULL;
8632                 } else {
8633                         if ((tblock = cfg->cil_offset_to_bb [ip - cfg->cil_start]) && (tblock != cfg->cbb)) {
8634                                 link_bblock (cfg, cfg->cbb, tblock);
8635                                 if (sp != stack_start) {
8636                                         handle_stack_args (cfg, stack_start, sp - stack_start);
8637                                         sp = stack_start;
8638                                         CHECK_UNVERIFIABLE (cfg);
8639                                 }
8640                                 cfg->cbb->next_bb = tblock;
8641                                 cfg->cbb = tblock;
8642                                 for (i = 0; i < cfg->cbb->in_scount; ++i) {
8643                                         if (cfg->verbose_level > 3)
8644                                                 printf ("loading %d from temp %d\n", i, (int)cfg->cbb->in_stack [i]->inst_c0);
8645                                         EMIT_NEW_TEMPLOAD (cfg, ins, cfg->cbb->in_stack [i]->inst_c0);
8646                                         *sp++ = ins;
8647                                 }
8648                                 g_slist_free (class_inits);
8649                                 class_inits = NULL;
8650                         }
8651                 }
8652
8653                 if (skip_dead_blocks) {
8654                         int ip_offset = ip - header->code;
8655
8656                         if (ip_offset == bb->end)
8657                                 bb = bb->next;
8658
8659                         if (bb->dead) {
8660                                 int op_size = mono_opcode_size (ip, end);
8661                                 g_assert (op_size > 0); /*The BB formation pass must catch all bad ops*/
8662
8663                                 if (cfg->verbose_level > 3) printf ("SKIPPING DEAD OP at %x\n", ip_offset);
8664
8665                                 if (ip_offset + op_size == bb->end) {
8666                                         MONO_INST_NEW (cfg, ins, OP_NOP);
8667                                         MONO_ADD_INS (cfg->cbb, ins);
8668                                         start_new_bblock = 1;
8669                                 }
8670
8671                                 ip += op_size;
8672                                 continue;
8673                         }
8674                 }
8675                 /*
8676                  * Sequence points are points where the debugger can place a breakpoint.
8677                  * Currently, we generate these automatically at points where the IL
8678                  * stack is empty.
8679                  */
8680                 if (seq_points && ((!sym_seq_points && (sp == stack_start)) || (sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code)))) {
8681                         /*
8682                          * Make methods interruptable at the beginning, and at the targets of
8683                          * backward branches.
8684                          * Also, do this at the start of every bblock in methods with clauses too,
8685                          * to be able to handle instructions with inprecise control flow like
8686                          * throw/endfinally.
8687                          * Backward branches are handled at the end of method-to-ir ().
8688                          */
8689                         gboolean intr_loc = ip == header->code || (!cfg->cbb->last_ins && cfg->header->num_clauses);
8690                         gboolean sym_seq_point = sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code);
8691
8692                         /* Avoid sequence points on empty IL like .volatile */
8693                         // FIXME: Enable this
8694                         //if (!(cfg->cbb->last_ins && cfg->cbb->last_ins->opcode == OP_SEQ_POINT)) {
8695                         NEW_SEQ_POINT (cfg, ins, ip - header->code, intr_loc);
8696                         if ((sp != stack_start) && !sym_seq_point)
8697                                 ins->flags |= MONO_INST_NONEMPTY_STACK;
8698                         MONO_ADD_INS (cfg->cbb, ins);
8699
8700                         if (sym_seq_points)
8701                                 mono_bitset_set_fast (seq_point_set_locs, ip - header->code);
8702                 }
8703
8704                 cfg->cbb->real_offset = cfg->real_offset;
8705
8706                 if ((cfg->method == method) && cfg->coverage_info) {
8707                         guint32 cil_offset = ip - header->code;
8708                         cfg->coverage_info->data [cil_offset].cil_code = ip;
8709
8710                         /* TODO: Use an increment here */
8711 #if defined(TARGET_X86)
8712                         MONO_INST_NEW (cfg, ins, OP_STORE_MEM_IMM);
8713                         ins->inst_p0 = &(cfg->coverage_info->data [cil_offset].count);
8714                         ins->inst_imm = 1;
8715                         MONO_ADD_INS (cfg->cbb, ins);
8716 #else
8717                         EMIT_NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
8718                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, ins->dreg, 0, 1);
8719 #endif
8720                 }
8721
8722                 if (cfg->verbose_level > 3)
8723                         printf ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
8724
8725                 switch (*ip) {
8726                 case CEE_NOP:
8727                         if (seq_points && !sym_seq_points && sp != stack_start) {
8728                                 /*
8729                                  * The C# compiler uses these nops to notify the JIT that it should
8730                                  * insert seq points.
8731                                  */
8732                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, FALSE);
8733                                 MONO_ADD_INS (cfg->cbb, ins);
8734                         }
8735                         if (cfg->keep_cil_nops)
8736                                 MONO_INST_NEW (cfg, ins, OP_HARD_NOP);
8737                         else
8738                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8739                         ip++;
8740                         MONO_ADD_INS (cfg->cbb, ins);
8741                         break;
8742                 case CEE_BREAK:
8743                         if (should_insert_brekpoint (cfg->method)) {
8744                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
8745                         } else {
8746                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8747                         }
8748                         ip++;
8749                         MONO_ADD_INS (cfg->cbb, ins);
8750                         break;
8751                 case CEE_LDARG_0:
8752                 case CEE_LDARG_1:
8753                 case CEE_LDARG_2:
8754                 case CEE_LDARG_3:
8755                         CHECK_STACK_OVF (1);
8756                         n = (*ip)-CEE_LDARG_0;
8757                         CHECK_ARG (n);
8758                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8759                         ip++;
8760                         *sp++ = ins;
8761                         break;
8762                 case CEE_LDLOC_0:
8763                 case CEE_LDLOC_1:
8764                 case CEE_LDLOC_2:
8765                 case CEE_LDLOC_3:
8766                         CHECK_STACK_OVF (1);
8767                         n = (*ip)-CEE_LDLOC_0;
8768                         CHECK_LOCAL (n);
8769                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8770                         ip++;
8771                         *sp++ = ins;
8772                         break;
8773                 case CEE_STLOC_0:
8774                 case CEE_STLOC_1:
8775                 case CEE_STLOC_2:
8776                 case CEE_STLOC_3: {
8777                         CHECK_STACK (1);
8778                         n = (*ip)-CEE_STLOC_0;
8779                         CHECK_LOCAL (n);
8780                         --sp;
8781                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
8782                                 UNVERIFIED;
8783                         emit_stloc_ir (cfg, sp, header, n);
8784                         ++ip;
8785                         inline_costs += 1;
8786                         break;
8787                         }
8788                 case CEE_LDARG_S:
8789                         CHECK_OPSIZE (2);
8790                         CHECK_STACK_OVF (1);
8791                         n = ip [1];
8792                         CHECK_ARG (n);
8793                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8794                         *sp++ = ins;
8795                         ip += 2;
8796                         break;
8797                 case CEE_LDARGA_S:
8798                         CHECK_OPSIZE (2);
8799                         CHECK_STACK_OVF (1);
8800                         n = ip [1];
8801                         CHECK_ARG (n);
8802                         NEW_ARGLOADA (cfg, ins, n);
8803                         MONO_ADD_INS (cfg->cbb, ins);
8804                         *sp++ = ins;
8805                         ip += 2;
8806                         break;
8807                 case CEE_STARG_S:
8808                         CHECK_OPSIZE (2);
8809                         CHECK_STACK (1);
8810                         --sp;
8811                         n = ip [1];
8812                         CHECK_ARG (n);
8813                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [ip [1]], *sp))
8814                                 UNVERIFIED;
8815                         EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
8816                         ip += 2;
8817                         break;
8818                 case CEE_LDLOC_S:
8819                         CHECK_OPSIZE (2);
8820                         CHECK_STACK_OVF (1);
8821                         n = ip [1];
8822                         CHECK_LOCAL (n);
8823                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8824                         *sp++ = ins;
8825                         ip += 2;
8826                         break;
8827                 case CEE_LDLOCA_S: {
8828                         unsigned char *tmp_ip;
8829                         CHECK_OPSIZE (2);
8830                         CHECK_STACK_OVF (1);
8831                         CHECK_LOCAL (ip [1]);
8832
8833                         if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 1))) {
8834                                 ip = tmp_ip;
8835                                 inline_costs += 1;
8836                                 break;
8837                         }
8838
8839                         EMIT_NEW_LOCLOADA (cfg, ins, ip [1]);
8840                         *sp++ = ins;
8841                         ip += 2;
8842                         break;
8843                 }
8844                 case CEE_STLOC_S:
8845                         CHECK_OPSIZE (2);
8846                         CHECK_STACK (1);
8847                         --sp;
8848                         CHECK_LOCAL (ip [1]);
8849                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [ip [1]], *sp))
8850                                 UNVERIFIED;
8851                         emit_stloc_ir (cfg, sp, header, ip [1]);
8852                         ip += 2;
8853                         inline_costs += 1;
8854                         break;
8855                 case CEE_LDNULL:
8856                         CHECK_STACK_OVF (1);
8857                         EMIT_NEW_PCONST (cfg, ins, NULL);
8858                         ins->type = STACK_OBJ;
8859                         ++ip;
8860                         *sp++ = ins;
8861                         break;
8862                 case CEE_LDC_I4_M1:
8863                         CHECK_STACK_OVF (1);
8864                         EMIT_NEW_ICONST (cfg, ins, -1);
8865                         ++ip;
8866                         *sp++ = ins;
8867                         break;
8868                 case CEE_LDC_I4_0:
8869                 case CEE_LDC_I4_1:
8870                 case CEE_LDC_I4_2:
8871                 case CEE_LDC_I4_3:
8872                 case CEE_LDC_I4_4:
8873                 case CEE_LDC_I4_5:
8874                 case CEE_LDC_I4_6:
8875                 case CEE_LDC_I4_7:
8876                 case CEE_LDC_I4_8:
8877                         CHECK_STACK_OVF (1);
8878                         EMIT_NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
8879                         ++ip;
8880                         *sp++ = ins;
8881                         break;
8882                 case CEE_LDC_I4_S:
8883                         CHECK_OPSIZE (2);
8884                         CHECK_STACK_OVF (1);
8885                         ++ip;
8886                         EMIT_NEW_ICONST (cfg, ins, *((signed char*)ip));
8887                         ++ip;
8888                         *sp++ = ins;
8889                         break;
8890                 case CEE_LDC_I4:
8891                         CHECK_OPSIZE (5);
8892                         CHECK_STACK_OVF (1);
8893                         EMIT_NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
8894                         ip += 5;
8895                         *sp++ = ins;
8896                         break;
8897                 case CEE_LDC_I8:
8898                         CHECK_OPSIZE (9);
8899                         CHECK_STACK_OVF (1);
8900                         MONO_INST_NEW (cfg, ins, OP_I8CONST);
8901                         ins->type = STACK_I8;
8902                         ins->dreg = alloc_dreg (cfg, STACK_I8);
8903                         ++ip;
8904                         ins->inst_l = (gint64)read64 (ip);
8905                         MONO_ADD_INS (cfg->cbb, ins);
8906                         ip += 8;
8907                         *sp++ = ins;
8908                         break;
8909                 case CEE_LDC_R4: {
8910                         float *f;
8911                         gboolean use_aotconst = FALSE;
8912
8913 #ifdef TARGET_POWERPC
8914                         /* FIXME: Clean this up */
8915                         if (cfg->compile_aot)
8916                                 use_aotconst = TRUE;
8917 #endif
8918
8919                         /* FIXME: we should really allocate this only late in the compilation process */
8920                         f = (float *)mono_domain_alloc (cfg->domain, sizeof (float));
8921                         CHECK_OPSIZE (5);
8922                         CHECK_STACK_OVF (1);
8923
8924                         if (use_aotconst) {
8925                                 MonoInst *cons;
8926                                 int dreg;
8927
8928                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R4, f);
8929
8930                                 dreg = alloc_freg (cfg);
8931                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR4_MEMBASE, dreg, cons->dreg, 0);
8932                                 ins->type = cfg->r4_stack_type;
8933                         } else {
8934                                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
8935                                 ins->type = cfg->r4_stack_type;
8936                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8937                                 ins->inst_p0 = f;
8938                                 MONO_ADD_INS (cfg->cbb, ins);
8939                         }
8940                         ++ip;
8941                         readr4 (ip, f);
8942                         ip += 4;
8943                         *sp++ = ins;                    
8944                         break;
8945                 }
8946                 case CEE_LDC_R8: {
8947                         double *d;
8948                         gboolean use_aotconst = FALSE;
8949
8950 #ifdef TARGET_POWERPC
8951                         /* FIXME: Clean this up */
8952                         if (cfg->compile_aot)
8953                                 use_aotconst = TRUE;
8954 #endif
8955
8956                         /* FIXME: we should really allocate this only late in the compilation process */
8957                         d = (double *)mono_domain_alloc (cfg->domain, sizeof (double));
8958                         CHECK_OPSIZE (9);
8959                         CHECK_STACK_OVF (1);
8960
8961                         if (use_aotconst) {
8962                                 MonoInst *cons;
8963                                 int dreg;
8964
8965                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R8, d);
8966
8967                                 dreg = alloc_freg (cfg);
8968                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR8_MEMBASE, dreg, cons->dreg, 0);
8969                                 ins->type = STACK_R8;
8970                         } else {
8971                                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
8972                                 ins->type = STACK_R8;
8973                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8974                                 ins->inst_p0 = d;
8975                                 MONO_ADD_INS (cfg->cbb, ins);
8976                         }
8977                         ++ip;
8978                         readr8 (ip, d);
8979                         ip += 8;
8980                         *sp++ = ins;
8981                         break;
8982                 }
8983                 case CEE_DUP: {
8984                         MonoInst *temp, *store;
8985                         CHECK_STACK (1);
8986                         CHECK_STACK_OVF (1);
8987                         sp--;
8988                         ins = *sp;
8989
8990                         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
8991                         EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
8992
8993                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8994                         *sp++ = ins;
8995
8996                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8997                         *sp++ = ins;
8998
8999                         ++ip;
9000                         inline_costs += 2;
9001                         break;
9002                 }
9003                 case CEE_POP:
9004                         CHECK_STACK (1);
9005                         ip++;
9006                         --sp;
9007
9008 #ifdef TARGET_X86
9009                         if (sp [0]->type == STACK_R8)
9010                                 /* we need to pop the value from the x86 FP stack */
9011                                 MONO_EMIT_NEW_UNALU (cfg, OP_X86_FPOP, -1, sp [0]->dreg);
9012 #endif
9013                         break;
9014                 case CEE_JMP: {
9015                         MonoCallInst *call;
9016                         MonoMethodSignature *fsig;
9017                         int i, n;
9018
9019                         INLINE_FAILURE ("jmp");
9020                         GSHAREDVT_FAILURE (*ip);
9021
9022                         CHECK_OPSIZE (5);
9023                         if (stack_start != sp)
9024                                 UNVERIFIED;
9025                         token = read32 (ip + 1);
9026                         /* FIXME: check the signature matches */
9027                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
9028                         CHECK_CFG_ERROR;
9029  
9030                         if (cfg->gshared && mono_method_check_context_used (cmethod))
9031                                 GENERIC_SHARING_FAILURE (CEE_JMP);
9032
9033                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
9034
9035                         fsig = mono_method_signature (cmethod);
9036                         n = fsig->param_count + fsig->hasthis;
9037                         if (cfg->llvm_only) {
9038                                 MonoInst **args;
9039
9040                                 args = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
9041                                 for (i = 0; i < n; ++i)
9042                                         EMIT_NEW_ARGLOAD (cfg, args [i], i);
9043                                 ins = mono_emit_method_call_full (cfg, cmethod, fsig, TRUE, args, NULL, NULL, NULL);
9044                                 /*
9045                                  * The code in mono-basic-block.c treats the rest of the code as dead, but we
9046                                  * have to emit a normal return since llvm expects it.
9047                                  */
9048                                 if (cfg->ret)
9049                                         emit_setret (cfg, ins);
9050                                 MONO_INST_NEW (cfg, ins, OP_BR);
9051                                 ins->inst_target_bb = end_bblock;
9052                                 MONO_ADD_INS (cfg->cbb, ins);
9053                                 link_bblock (cfg, cfg->cbb, end_bblock);
9054                                 ip += 5;
9055                                 break;
9056                         } else if (cfg->backend->have_op_tail_call) {
9057                                 /* Handle tail calls similarly to calls */
9058                                 DISABLE_AOT (cfg);
9059
9060                                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
9061                                 call->method = cmethod;
9062                                 call->tail_call = TRUE;
9063                                 call->signature = mono_method_signature (cmethod);
9064                                 call->args = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
9065                                 call->inst.inst_p0 = cmethod;
9066                                 for (i = 0; i < n; ++i)
9067                                         EMIT_NEW_ARGLOAD (cfg, call->args [i], i);
9068
9069                                 if (mini_type_is_vtype (mini_get_underlying_type (call->signature->ret)))
9070                                         call->vret_var = cfg->vret_addr;
9071
9072                                 mono_arch_emit_call (cfg, call);
9073                                 cfg->param_area = MAX(cfg->param_area, call->stack_usage);
9074                                 MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
9075                         } else {
9076                                 for (i = 0; i < num_args; ++i)
9077                                         /* Prevent arguments from being optimized away */
9078                                         arg_array [i]->flags |= MONO_INST_VOLATILE;
9079
9080                                 MONO_INST_NEW_CALL (cfg, call, OP_JMP);
9081                                 ins = (MonoInst*)call;
9082                                 ins->inst_p0 = cmethod;
9083                                 MONO_ADD_INS (cfg->cbb, ins);
9084                         }
9085
9086                         ip += 5;
9087                         start_new_bblock = 1;
9088                         break;
9089                 }
9090                 case CEE_CALLI: {
9091                         MonoInst *addr;
9092                         MonoMethodSignature *fsig;
9093
9094                         CHECK_OPSIZE (5);
9095                         token = read32 (ip + 1);
9096
9097                         ins = NULL;
9098
9099                         //GSHAREDVT_FAILURE (*ip);
9100                         cmethod = NULL;
9101                         CHECK_STACK (1);
9102                         --sp;
9103                         addr = *sp;
9104                         fsig = mini_get_signature (method, token, generic_context, &cfg->error);
9105                         CHECK_CFG_ERROR;
9106
9107                         if (method->dynamic && fsig->pinvoke) {
9108                                 MonoInst *args [3];
9109
9110                                 /*
9111                                  * This is a call through a function pointer using a pinvoke
9112                                  * signature. Have to create a wrapper and call that instead.
9113                                  * FIXME: This is very slow, need to create a wrapper at JIT time
9114                                  * instead based on the signature.
9115                                  */
9116                                 EMIT_NEW_IMAGECONST (cfg, args [0], method->klass->image);
9117                                 EMIT_NEW_PCONST (cfg, args [1], fsig);
9118                                 args [2] = addr;
9119                                 addr = mono_emit_jit_icall (cfg, mono_get_native_calli_wrapper, args);
9120                         }
9121
9122                         n = fsig->param_count + fsig->hasthis;
9123
9124                         CHECK_STACK (n);
9125
9126                         //g_assert (!virtual_ || fsig->hasthis);
9127
9128                         sp -= n;
9129
9130                         inline_costs += 10 * num_calls++;
9131
9132                         /*
9133                          * Making generic calls out of gsharedvt methods.
9134                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
9135                          * patching gshared method addresses into a gsharedvt method.
9136                          */
9137                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
9138                                 /*
9139                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
9140                                  */
9141                                 MonoInst *callee = addr;
9142
9143                                 if (method->wrapper_type != MONO_WRAPPER_DELEGATE_INVOKE)
9144                                         /* Not tested */
9145                                         GSHAREDVT_FAILURE (*ip);
9146
9147                                 if (cfg->llvm_only)
9148                                         // FIXME:
9149                                         GSHAREDVT_FAILURE (*ip);
9150
9151                                 addr = emit_get_rgctx_sig (cfg, context_used,
9152                                                                                           fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
9153                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
9154                                 goto calli_end;
9155                         }
9156
9157                         /* Prevent inlining of methods with indirect calls */
9158                         INLINE_FAILURE ("indirect call");
9159
9160                         if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST || addr->opcode == OP_GOT_ENTRY) {
9161                                 MonoJumpInfoType info_type;
9162                                 gpointer info_data;
9163
9164                                 /*
9165                                  * Instead of emitting an indirect call, emit a direct call
9166                                  * with the contents of the aotconst as the patch info.
9167                                  */
9168                                 if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST) {
9169                                         info_type = (MonoJumpInfoType)addr->inst_c1;
9170                                         info_data = addr->inst_p0;
9171                                 } else {
9172                                         info_type = (MonoJumpInfoType)addr->inst_right->inst_c1;
9173                                         info_data = addr->inst_right->inst_left;
9174                                 }
9175
9176                                 if (info_type == MONO_PATCH_INFO_ICALL_ADDR) {
9177                                         ins = (MonoInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_ICALL_ADDR_CALL, info_data, fsig, sp);
9178                                         NULLIFY_INS (addr);
9179                                         goto calli_end;
9180                                 } else if (info_type == MONO_PATCH_INFO_JIT_ICALL_ADDR) {
9181                                         ins = (MonoInst*)mono_emit_abs_call (cfg, info_type, info_data, fsig, sp);
9182                                         NULLIFY_INS (addr);
9183                                         goto calli_end;
9184                                 }
9185                         }
9186                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9187
9188                         calli_end:
9189
9190                         /* End of call, INS should contain the result of the call, if any */
9191
9192                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9193                                 g_assert (ins);
9194                                 *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
9195                         }
9196
9197                         CHECK_CFG_EXCEPTION;
9198
9199                         ip += 5;
9200                         ins_flag = 0;
9201                         constrained_class = NULL;
9202                         break;
9203                 }
9204                 case CEE_CALL:
9205                 case CEE_CALLVIRT: {
9206                         MonoInst *addr = NULL;
9207                         MonoMethodSignature *fsig = NULL;
9208                         int array_rank = 0;
9209                         int virtual_ = *ip == CEE_CALLVIRT;
9210                         gboolean pass_imt_from_rgctx = FALSE;
9211                         MonoInst *imt_arg = NULL;
9212                         MonoInst *keep_this_alive = NULL;
9213                         gboolean pass_vtable = FALSE;
9214                         gboolean pass_mrgctx = FALSE;
9215                         MonoInst *vtable_arg = NULL;
9216                         gboolean check_this = FALSE;
9217                         gboolean supported_tail_call = FALSE;
9218                         gboolean tail_call = FALSE;
9219                         gboolean need_seq_point = FALSE;
9220                         guint32 call_opcode = *ip;
9221                         gboolean emit_widen = TRUE;
9222                         gboolean push_res = TRUE;
9223                         gboolean skip_ret = FALSE;
9224                         gboolean delegate_invoke = FALSE;
9225                         gboolean direct_icall = FALSE;
9226                         gboolean constrained_partial_call = FALSE;
9227                         MonoMethod *cil_method;
9228
9229                         CHECK_OPSIZE (5);
9230                         token = read32 (ip + 1);
9231
9232                         ins = NULL;
9233
9234                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
9235                         CHECK_CFG_ERROR;
9236
9237                         cil_method = cmethod;
9238                                 
9239                         if (constrained_class) {
9240                                 if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->gshared) {
9241                                         if (!mini_is_gsharedvt_klass (constrained_class)) {
9242                                                 g_assert (!cmethod->klass->valuetype);
9243                                                 if (!mini_type_is_reference (&constrained_class->byval_arg))
9244                                                         constrained_partial_call = TRUE;
9245                                         }
9246                                 }
9247
9248                                 if (method->wrapper_type != MONO_WRAPPER_NONE) {
9249                                         if (cfg->verbose_level > 2)
9250                                                 printf ("DM Constrained call to %s\n", mono_type_get_full_name (constrained_class));
9251                                         if (!((constrained_class->byval_arg.type == MONO_TYPE_VAR ||
9252                                                    constrained_class->byval_arg.type == MONO_TYPE_MVAR) &&
9253                                                   cfg->gshared)) {
9254                                                 cmethod = mono_get_method_constrained_with_method (image, cil_method, constrained_class, generic_context, &cfg->error);
9255                                                 CHECK_CFG_ERROR;
9256                                         }
9257                                 } else {
9258                                         if (cfg->verbose_level > 2)
9259                                                 printf ("Constrained call to %s\n", mono_type_get_full_name (constrained_class));
9260
9261                                         if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->gshared) {
9262                                                 /* 
9263                                                  * This is needed since get_method_constrained can't find 
9264                                                  * the method in klass representing a type var.
9265                                                  * The type var is guaranteed to be a reference type in this
9266                                                  * case.
9267                                                  */
9268                                                 if (!mini_is_gsharedvt_klass (constrained_class))
9269                                                         g_assert (!cmethod->klass->valuetype);
9270                                         } else {
9271                                                 cmethod = mono_get_method_constrained_checked (image, token, constrained_class, generic_context, &cil_method, &cfg->error);
9272                                                 CHECK_CFG_ERROR;
9273                                         }
9274                                 }
9275                         }
9276                                         
9277                         if (!dont_verify && !cfg->skip_visibility) {
9278                                 MonoMethod *target_method = cil_method;
9279                                 if (method->is_inflated) {
9280                                         target_method = mini_get_method_allow_open (method, token, NULL, &(mono_method_get_generic_container (method_definition)->context), &cfg->error);
9281                                         CHECK_CFG_ERROR;
9282                                 }
9283                                 if (!mono_method_can_access_method (method_definition, target_method) &&
9284                                         !mono_method_can_access_method (method, cil_method))
9285                                         emit_method_access_failure (cfg, method, cil_method);
9286                         }
9287
9288                         if (mono_security_core_clr_enabled ())
9289                                 ensure_method_is_allowed_to_call_method (cfg, method, cil_method);
9290
9291                         if (!virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
9292                                 /* MS.NET seems to silently convert this to a callvirt */
9293                                 virtual_ = 1;
9294
9295                         {
9296                                 /*
9297                                  * MS.NET accepts non virtual calls to virtual final methods of transparent proxy classes and
9298                                  * converts to a callvirt.
9299                                  *
9300                                  * tests/bug-515884.il is an example of this behavior
9301                                  */
9302                                 const int test_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_STATIC;
9303                                 const int expected_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL;
9304                                 if (!virtual_ && mono_class_is_marshalbyref (cmethod->klass) && (cmethod->flags & test_flags) == expected_flags && cfg->method->wrapper_type == MONO_WRAPPER_NONE)
9305                                         virtual_ = 1;
9306                         }
9307
9308                         if (!cmethod->klass->inited)
9309                                 if (!mono_class_init (cmethod->klass))
9310                                         TYPE_LOAD_ERROR (cmethod->klass);
9311
9312                         fsig = mono_method_signature (cmethod);
9313                         if (!fsig)
9314                                 LOAD_ERROR;
9315                         if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
9316                                 mini_class_is_system_array (cmethod->klass)) {
9317                                 array_rank = cmethod->klass->rank;
9318                         } else if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && icall_is_direct_callable (cfg, cmethod)) {
9319                                 direct_icall = TRUE;
9320                         } else if (fsig->pinvoke) {
9321                                 MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
9322                                 fsig = mono_method_signature (wrapper);
9323                         } else if (constrained_class) {
9324                         } else {
9325                                 fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
9326                                 CHECK_CFG_ERROR;
9327                         }
9328
9329                         if (cfg->llvm_only && !cfg->method->wrapper_type && (!cmethod || cmethod->is_inflated))
9330                                 cfg->signatures = g_slist_prepend_mempool (cfg->mempool, cfg->signatures, fsig);
9331
9332                         /* See code below */
9333                         if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
9334                                 MonoBasicBlock *tbb;
9335
9336                                 GET_BBLOCK (cfg, tbb, ip + 5);
9337                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
9338                                         /*
9339                                          * We want to extend the try block to cover the call, but we can't do it if the
9340                                          * call is made directly since its followed by an exception check.
9341                                          */
9342                                         direct_icall = FALSE;
9343                                 }
9344                         }
9345
9346                         mono_save_token_info (cfg, image, token, cil_method);
9347
9348                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip + 5 - header->code)))
9349                                 need_seq_point = TRUE;
9350
9351                         /* Don't support calls made using type arguments for now */
9352                         /*
9353                           if (cfg->gsharedvt) {
9354                           if (mini_is_gsharedvt_signature (fsig))
9355                           GSHAREDVT_FAILURE (*ip);
9356                           }
9357                         */
9358
9359                         if (cmethod->string_ctor && method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE)
9360                                 g_assert_not_reached ();
9361
9362                         n = fsig->param_count + fsig->hasthis;
9363
9364                         if (!cfg->gshared && cmethod->klass->generic_container)
9365                                 UNVERIFIED;
9366
9367                         if (!cfg->gshared)
9368                                 g_assert (!mono_method_check_context_used (cmethod));
9369
9370                         CHECK_STACK (n);
9371
9372                         //g_assert (!virtual_ || fsig->hasthis);
9373
9374                         sp -= n;
9375
9376                         /*
9377                          * We have the `constrained.' prefix opcode.
9378                          */
9379                         if (constrained_class) {
9380                                 if (mini_is_gsharedvt_klass (constrained_class)) {
9381                                         if ((cmethod->klass != mono_defaults.object_class) && constrained_class->valuetype && cmethod->klass->valuetype) {
9382                                                 /* The 'Own method' case below */
9383                                         } else if (cmethod->klass->image != mono_defaults.corlib && !(cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !cmethod->klass->valuetype) {
9384                                                 /* 'The type parameter is instantiated as a reference type' case below. */
9385                                         } else {
9386                                                 ins = handle_constrained_gsharedvt_call (cfg, cmethod, fsig, sp, constrained_class, &emit_widen);
9387                                                 CHECK_CFG_EXCEPTION;
9388                                                 g_assert (ins);
9389                                                 goto call_end;
9390                                         }
9391                                 }
9392
9393                                 if (constrained_partial_call) {
9394                                         gboolean need_box = TRUE;
9395
9396                                         /*
9397                                          * The receiver is a valuetype, but the exact type is not known at compile time. This means the
9398                                          * called method is not known at compile time either. The called method could end up being
9399                                          * one of the methods on the parent classes (object/valuetype/enum), in which case we need
9400                                          * to box the receiver.
9401                                          * A simple solution would be to box always and make a normal virtual call, but that would
9402                                          * be bad performance wise.
9403                                          */
9404                                         if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE && cmethod->klass->generic_class) {
9405                                                 /*
9406                                                  * The parent classes implement no generic interfaces, so the called method will be a vtype method, so no boxing neccessary.
9407                                                  */
9408                                                 need_box = FALSE;
9409                                         }
9410
9411                                         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)) {
9412                                                 /* The called method is not virtual, i.e. Object:GetType (), the receiver is a vtype, has to box */
9413                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9414                                                 ins->klass = constrained_class;
9415                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9416                                                 CHECK_CFG_EXCEPTION;
9417                                         } else if (need_box) {
9418                                                 MonoInst *box_type;
9419                                                 MonoBasicBlock *is_ref_bb, *end_bb;
9420                                                 MonoInst *nonbox_call;
9421
9422                                                 /*
9423                                                  * Determine at runtime whenever the called method is defined on object/valuetype/enum, and emit a boxing call
9424                                                  * if needed.
9425                                                  * FIXME: It is possible to inline the called method in a lot of cases, i.e. for T_INT,
9426                                                  * the no-box case goes to a method in Int32, while the box case goes to a method in Enum.
9427                                                  */
9428                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
9429
9430                                                 NEW_BBLOCK (cfg, is_ref_bb);
9431                                                 NEW_BBLOCK (cfg, end_bb);
9432
9433                                                 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);
9434                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, box_type->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
9435                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
9436
9437                                                 /* Non-ref case */
9438                                                 nonbox_call = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9439
9440                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
9441
9442                                                 /* Ref case */
9443                                                 MONO_START_BB (cfg, is_ref_bb);
9444                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9445                                                 ins->klass = constrained_class;
9446                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9447                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9448
9449                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
9450
9451                                                 MONO_START_BB (cfg, end_bb);
9452                                                 cfg->cbb = end_bb;
9453
9454                                                 nonbox_call->dreg = ins->dreg;
9455                                                 goto call_end;
9456                                         } else {
9457                                                 g_assert (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE);
9458                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
9459                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9460                                                 goto call_end;
9461                                         }
9462                                 } else if (constrained_class->valuetype && (cmethod->klass == mono_defaults.object_class || cmethod->klass == mono_defaults.enum_class->parent || cmethod->klass == mono_defaults.enum_class)) {
9463                                         /*
9464                                          * The type parameter is instantiated as a valuetype,
9465                                          * but that type doesn't override the method we're
9466                                          * calling, so we need to box `this'.
9467                                          */
9468                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9469                                         ins->klass = constrained_class;
9470                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9471                                         CHECK_CFG_EXCEPTION;
9472                                 } else if (!constrained_class->valuetype) {
9473                                         int dreg = alloc_ireg_ref (cfg);
9474
9475                                         /*
9476                                          * The type parameter is instantiated as a reference
9477                                          * type.  We have a managed pointer on the stack, so
9478                                          * we need to dereference it here.
9479                                          */
9480                                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, sp [0]->dreg, 0);
9481                                         ins->type = STACK_OBJ;
9482                                         sp [0] = ins;
9483                                 } else {
9484                                         if (cmethod->klass->valuetype) {
9485                                                 /* Own method */
9486                                         } else {
9487                                                 /* Interface method */
9488                                                 int ioffset, slot;
9489
9490                                                 mono_class_setup_vtable (constrained_class);
9491                                                 CHECK_TYPELOAD (constrained_class);
9492                                                 ioffset = mono_class_interface_offset (constrained_class, cmethod->klass);
9493                                                 if (ioffset == -1)
9494                                                         TYPE_LOAD_ERROR (constrained_class);
9495                                                 slot = mono_method_get_vtable_slot (cmethod);
9496                                                 if (slot == -1)
9497                                                         TYPE_LOAD_ERROR (cmethod->klass);
9498                                                 cmethod = constrained_class->vtable [ioffset + slot];
9499
9500                                                 if (cmethod->klass == mono_defaults.enum_class) {
9501                                                         /* Enum implements some interfaces, so treat this as the first case */
9502                                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9503                                                         ins->klass = constrained_class;
9504                                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9505                                                         CHECK_CFG_EXCEPTION;
9506                                                 }
9507                                         }
9508                                         virtual_ = 0;
9509                                 }
9510                                 constrained_class = NULL;
9511                         }
9512
9513                         if (check_call_signature (cfg, fsig, sp))
9514                                 UNVERIFIED;
9515
9516                         if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (cmethod->name, "Invoke"))
9517                                 delegate_invoke = TRUE;
9518
9519                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_sharable_method (cfg, cmethod, fsig, sp))) {
9520                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9521                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
9522                                         emit_widen = FALSE;
9523                                 }
9524
9525                                 goto call_end;
9526                         }
9527
9528                         /* 
9529                          * If the callee is a shared method, then its static cctor
9530                          * might not get called after the call was patched.
9531                          */
9532                         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)) {
9533                                 emit_class_init (cfg, cmethod->klass);
9534                                 CHECK_TYPELOAD (cmethod->klass);
9535                         }
9536
9537                         check_method_sharing (cfg, cmethod, &pass_vtable, &pass_mrgctx);
9538
9539                         if (cfg->gshared) {
9540                                 MonoGenericContext *cmethod_context = mono_method_get_context (cmethod);
9541
9542                                 context_used = mini_method_check_context_used (cfg, cmethod);
9543
9544                                 if (context_used && (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
9545                                         /* Generic method interface
9546                                            calls are resolved via a
9547                                            helper function and don't
9548                                            need an imt. */
9549                                         if (!cmethod_context || !cmethod_context->method_inst)
9550                                                 pass_imt_from_rgctx = TRUE;
9551                                 }
9552
9553                                 /*
9554                                  * If a shared method calls another
9555                                  * shared method then the caller must
9556                                  * have a generic sharing context
9557                                  * because the magic trampoline
9558                                  * requires it.  FIXME: We shouldn't
9559                                  * have to force the vtable/mrgctx
9560                                  * variable here.  Instead there
9561                                  * should be a flag in the cfg to
9562                                  * request a generic sharing context.
9563                                  */
9564                                 if (context_used &&
9565                                                 ((method->flags & METHOD_ATTRIBUTE_STATIC) || method->klass->valuetype))
9566                                         mono_get_vtable_var (cfg);
9567                         }
9568
9569                         if (pass_vtable) {
9570                                 if (context_used) {
9571                                         vtable_arg = emit_get_rgctx_klass (cfg, context_used, cmethod->klass, MONO_RGCTX_INFO_VTABLE);
9572                                 } else {
9573                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
9574
9575                                         CHECK_TYPELOAD (cmethod->klass);
9576                                         EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
9577                                 }
9578                         }
9579
9580                         if (pass_mrgctx) {
9581                                 g_assert (!vtable_arg);
9582
9583                                 if (!cfg->compile_aot) {
9584                                         /* 
9585                                          * emit_get_rgctx_method () calls mono_class_vtable () so check 
9586                                          * for type load errors before.
9587                                          */
9588                                         mono_class_setup_vtable (cmethod->klass);
9589                                         CHECK_TYPELOAD (cmethod->klass);
9590                                 }
9591
9592                                 vtable_arg = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
9593
9594                                 /* !marshalbyref is needed to properly handle generic methods + remoting */
9595                                 if ((!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
9596                                          MONO_METHOD_IS_FINAL (cmethod)) &&
9597                                         !mono_class_is_marshalbyref (cmethod->klass)) {
9598                                         if (virtual_)
9599                                                 check_this = TRUE;
9600                                         virtual_ = 0;
9601                                 }
9602                         }
9603
9604                         if (pass_imt_from_rgctx) {
9605                                 g_assert (!pass_vtable);
9606
9607                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9608                                         cmethod, MONO_RGCTX_INFO_METHOD);
9609                         }
9610
9611                         if (check_this)
9612                                 MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9613
9614                         /* Calling virtual generic methods */
9615                         if (virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) &&
9616                             !(MONO_METHOD_IS_FINAL (cmethod) && 
9617                               cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) &&
9618                             fsig->generic_param_count && 
9619                                 !(cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) &&
9620                                 !cfg->llvm_only) {
9621                                 MonoInst *this_temp, *this_arg_temp, *store;
9622                                 MonoInst *iargs [4];
9623
9624                                 g_assert (fsig->is_inflated);
9625
9626                                 /* Prevent inlining of methods that contain indirect calls */
9627                                 INLINE_FAILURE ("virtual generic call");
9628
9629                                 if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))
9630                                         GSHAREDVT_FAILURE (*ip);
9631
9632                                 if (cfg->backend->have_generalized_imt_thunk && cfg->backend->gshared_supported && cmethod->wrapper_type == MONO_WRAPPER_NONE) {
9633                                         g_assert (!imt_arg);
9634                                         if (!context_used)
9635                                                 g_assert (cmethod->is_inflated);
9636                                         imt_arg = emit_get_rgctx_method (cfg, context_used,
9637                                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
9638                                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, sp [0], imt_arg, NULL);
9639                                 } else {
9640                                         this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
9641                                         NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
9642                                         MONO_ADD_INS (cfg->cbb, store);
9643
9644                                         /* FIXME: This should be a managed pointer */
9645                                         this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
9646
9647                                         EMIT_NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
9648                                         iargs [1] = emit_get_rgctx_method (cfg, context_used,
9649                                                                                                            cmethod, MONO_RGCTX_INFO_METHOD);
9650                                         EMIT_NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
9651                                         addr = mono_emit_jit_icall (cfg,
9652                                                                                                 mono_helper_compile_generic_method, iargs);
9653
9654                                         EMIT_NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
9655
9656                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9657                                 }
9658
9659                                 goto call_end;
9660                         }
9661
9662                         /*
9663                          * Implement a workaround for the inherent races involved in locking:
9664                          * Monitor.Enter ()
9665                          * try {
9666                          * } finally {
9667                          *    Monitor.Exit ()
9668                          * }
9669                          * If a thread abort happens between the call to Monitor.Enter () and the start of the
9670                          * try block, the Exit () won't be executed, see:
9671                          * http://www.bluebytesoftware.com/blog/2007/01/30/MonitorEnterThreadAbortsAndOrphanedLocks.aspx
9672                          * To work around this, we extend such try blocks to include the last x bytes
9673                          * of the Monitor.Enter () call.
9674                          */
9675                         if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
9676                                 MonoBasicBlock *tbb;
9677
9678                                 GET_BBLOCK (cfg, tbb, ip + 5);
9679                                 /* 
9680                                  * Only extend try blocks with a finally, to avoid catching exceptions thrown
9681                                  * from Monitor.Enter like ArgumentNullException.
9682                                  */
9683                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
9684                                         /* Mark this bblock as needing to be extended */
9685                                         tbb->extend_try_block = TRUE;
9686                                 }
9687                         }
9688
9689                         /* Conversion to a JIT intrinsic */
9690                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_method (cfg, cmethod, fsig, sp))) {
9691                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9692                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
9693                                         emit_widen = FALSE;
9694                                 }
9695                                 goto call_end;
9696                         }
9697                         CHECK_CFG_ERROR;
9698                         
9699                         /* Inlining */
9700                         if ((cfg->opt & MONO_OPT_INLINE) &&
9701                                 (!virtual_ || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || MONO_METHOD_IS_FINAL (cmethod)) &&
9702                             mono_method_check_inlining (cfg, cmethod)) {
9703                                 int costs;
9704                                 gboolean always = FALSE;
9705
9706                                 if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
9707                                         (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
9708                                         /* Prevent inlining of methods that call wrappers */
9709                                         INLINE_FAILURE ("wrapper call");
9710                                         cmethod = mono_marshal_get_native_wrapper (cmethod, TRUE, FALSE);
9711                                         always = TRUE;
9712                                 }
9713
9714                                 costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, always);
9715                                 if (costs) {
9716                                         cfg->real_offset += 5;
9717
9718                                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9719                                                 /* *sp is already set by inline_method */
9720                                                 sp++;
9721                                                 push_res = FALSE;
9722                                         }
9723
9724                                         inline_costs += costs;
9725
9726                                         goto call_end;
9727                                 }
9728                         }
9729
9730                         /* Tail recursion elimination */
9731                         if ((cfg->opt & MONO_OPT_TAILC) && call_opcode == CEE_CALL && cmethod == method && ip [5] == CEE_RET && !vtable_arg) {
9732                                 gboolean has_vtargs = FALSE;
9733                                 int i;
9734
9735                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9736                                 INLINE_FAILURE ("tail call");
9737
9738                                 /* keep it simple */
9739                                 for (i =  fsig->param_count - 1; i >= 0; i--) {
9740                                         if (MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->params [i])) 
9741                                                 has_vtargs = TRUE;
9742                                 }
9743
9744                                 if (!has_vtargs) {
9745                                         if (need_seq_point) {
9746                                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
9747                                                 need_seq_point = FALSE;
9748                                         }
9749                                         for (i = 0; i < n; ++i)
9750                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9751                                         MONO_INST_NEW (cfg, ins, OP_BR);
9752                                         MONO_ADD_INS (cfg->cbb, ins);
9753                                         tblock = start_bblock->out_bb [0];
9754                                         link_bblock (cfg, cfg->cbb, tblock);
9755                                         ins->inst_target_bb = tblock;
9756                                         start_new_bblock = 1;
9757
9758                                         /* skip the CEE_RET, too */
9759                                         if (ip_in_bb (cfg, cfg->cbb, ip + 5))
9760                                                 skip_ret = TRUE;
9761                                         push_res = FALSE;
9762                                         goto call_end;
9763                                 }
9764                         }
9765
9766                         inline_costs += 10 * num_calls++;
9767
9768                         /*
9769                          * Synchronized wrappers.
9770                          * Its hard to determine where to replace a method with its synchronized
9771                          * wrapper without causing an infinite recursion. The current solution is
9772                          * to add the synchronized wrapper in the trampolines, and to
9773                          * change the called method to a dummy wrapper, and resolve that wrapper
9774                          * to the real method in mono_jit_compile_method ().
9775                          */
9776                         if (cfg->method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
9777                                 MonoMethod *orig = mono_marshal_method_from_wrapper (cfg->method);
9778                                 if (cmethod == orig || (cmethod->is_inflated && mono_method_get_declaring_generic_method (cmethod) == orig))
9779                                         cmethod = mono_marshal_get_synchronized_inner_wrapper (cmethod);
9780                         }
9781
9782                         /*
9783                          * Making generic calls out of gsharedvt methods.
9784                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
9785                          * patching gshared method addresses into a gsharedvt method.
9786                          */
9787                         if (cfg->gsharedvt && (mini_is_gsharedvt_signature (fsig) || cmethod->is_inflated || cmethod->klass->generic_class) &&
9788                                 !(cmethod->klass->rank && cmethod->klass->byval_arg.type != MONO_TYPE_SZARRAY) &&
9789                                 (!(cfg->llvm_only && virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL)))) {
9790                                 MonoRgctxInfoType info_type;
9791
9792                                 if (virtual_) {
9793                                         //if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
9794                                                 //GSHAREDVT_FAILURE (*ip);
9795                                         // disable for possible remoting calls
9796                                         if (fsig->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class))
9797                                                 GSHAREDVT_FAILURE (*ip);
9798                                         if (fsig->generic_param_count) {
9799                                                 /* virtual generic call */
9800                                                 g_assert (!imt_arg);
9801                                                 /* Same as the virtual generic case above */
9802                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9803                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9804                                                 /* This is not needed, as the trampoline code will pass one, and it might be passed in the same reg as the imt arg */
9805                                                 vtable_arg = NULL;
9806                                         } else if ((cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !imt_arg) {
9807                                                 /* This can happen when we call a fully instantiated iface method */
9808                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9809                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9810                                                 vtable_arg = NULL;
9811                                         }
9812                                 }
9813
9814                                 if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (cmethod->name, "Invoke")))
9815                                         keep_this_alive = sp [0];
9816
9817                                 if (virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))
9818                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
9819                                 else
9820                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE;
9821                                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, info_type);
9822
9823                                 if (cfg->llvm_only) {
9824                                         // FIXME: Avoid initializing vtable_arg
9825                                         ins = emit_llvmonly_calli (cfg, fsig, sp, addr);
9826                                 } else {
9827                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9828                                 }
9829                                 goto call_end;
9830                         }
9831
9832                         /* Generic sharing */
9833
9834                         /*
9835                          * Use this if the callee is gsharedvt sharable too, since
9836                          * at runtime we might find an instantiation so the call cannot
9837                          * be patched (the 'no_patch' code path in mini-trampolines.c).
9838                          */
9839                         if (context_used && !imt_arg && !array_rank && !delegate_invoke &&
9840                                 (!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
9841                                  !mono_class_generic_sharing_enabled (cmethod->klass)) &&
9842                                 (!virtual_ || MONO_METHOD_IS_FINAL (cmethod) ||
9843                                  !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))) {
9844                                 INLINE_FAILURE ("gshared");
9845
9846                                 g_assert (cfg->gshared && cmethod);
9847                                 g_assert (!addr);
9848
9849                                 /*
9850                                  * We are compiling a call to a
9851                                  * generic method from shared code,
9852                                  * which means that we have to look up
9853                                  * the method in the rgctx and do an
9854                                  * indirect call.
9855                                  */
9856                                 if (fsig->hasthis)
9857                                         MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9858
9859                                 if (cfg->llvm_only) {
9860                                         if (cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig))
9861                                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER);
9862                                         else
9863                                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
9864                                         // FIXME: Avoid initializing imt_arg/vtable_arg
9865                                         ins = emit_llvmonly_calli (cfg, fsig, sp, addr);
9866                                 } else {
9867                                         addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
9868                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9869                                 }
9870                                 goto call_end;
9871                         }
9872
9873                         /* Direct calls to icalls */
9874                         if (direct_icall) {
9875                                 MonoMethod *wrapper;
9876                                 int costs;
9877
9878                                 /* Inline the wrapper */
9879                                 wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
9880
9881                                 costs = inline_method (cfg, wrapper, fsig, sp, ip, cfg->real_offset, TRUE);
9882                                 g_assert (costs > 0);
9883                                 cfg->real_offset += 5;
9884
9885                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9886                                         /* *sp is already set by inline_method */
9887                                         sp++;
9888                                         push_res = FALSE;
9889                                 }
9890
9891                                 inline_costs += costs;
9892
9893                                 goto call_end;
9894                         }
9895                                         
9896                         /* Array methods */
9897                         if (array_rank) {
9898                                 MonoInst *addr;
9899
9900                                 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ 
9901                                         MonoInst *val = sp [fsig->param_count];
9902
9903                                         if (val->type == STACK_OBJ) {
9904                                                 MonoInst *iargs [2];
9905
9906                                                 iargs [0] = sp [0];
9907                                                 iargs [1] = val;
9908                                                 
9909                                                 mono_emit_jit_icall (cfg, mono_helper_stelem_ref_check, iargs);
9910                                         }
9911                                         
9912                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, TRUE);
9913                                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, fsig->params [fsig->param_count - 1], addr->dreg, 0, val->dreg);
9914                                         if (cfg->gen_write_barriers && val->type == STACK_OBJ && !(val->opcode == OP_PCONST && val->inst_c0 == 0))
9915                                                 emit_write_barrier (cfg, addr, val);
9916                                         if (cfg->gen_write_barriers && mini_is_gsharedvt_klass (cmethod->klass))
9917                                                 GSHAREDVT_FAILURE (*ip);
9918                                 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
9919                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9920
9921                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, addr->dreg, 0);
9922                                 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
9923                                         if (!cmethod->klass->element_class->valuetype && !readonly)
9924                                                 mini_emit_check_array_type (cfg, sp [0], cmethod->klass);
9925                                         CHECK_TYPELOAD (cmethod->klass);
9926                                         
9927                                         readonly = FALSE;
9928                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9929                                         ins = addr;
9930                                 } else {
9931                                         g_assert_not_reached ();
9932                                 }
9933
9934                                 emit_widen = FALSE;
9935                                 goto call_end;
9936                         }
9937
9938                         ins = mini_redirect_call (cfg, cmethod, fsig, sp, virtual_ ? sp [0] : NULL);
9939                         if (ins)
9940                                 goto call_end;
9941
9942                         /* Tail prefix / tail call optimization */
9943
9944                         /* FIXME: Enabling TAILC breaks some inlining/stack trace/etc tests */
9945                         /* FIXME: runtime generic context pointer for jumps? */
9946                         /* FIXME: handle this for generic sharing eventually */
9947                         if ((ins_flag & MONO_INST_TAILCALL) &&
9948                                 !vtable_arg && !cfg->gshared && is_supported_tail_call (cfg, method, cmethod, fsig, call_opcode))
9949                                 supported_tail_call = TRUE;
9950
9951                         if (supported_tail_call) {
9952                                 MonoCallInst *call;
9953
9954                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9955                                 INLINE_FAILURE ("tail call");
9956
9957                                 //printf ("HIT: %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
9958
9959                                 if (cfg->backend->have_op_tail_call) {
9960                                         /* Handle tail calls similarly to normal calls */
9961                                         tail_call = TRUE;
9962                                 } else {
9963                                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
9964
9965                                         MONO_INST_NEW_CALL (cfg, call, OP_JMP);
9966                                         call->tail_call = TRUE;
9967                                         call->method = cmethod;
9968                                         call->signature = mono_method_signature (cmethod);
9969
9970                                         /*
9971                                          * We implement tail calls by storing the actual arguments into the 
9972                                          * argument variables, then emitting a CEE_JMP.
9973                                          */
9974                                         for (i = 0; i < n; ++i) {
9975                                                 /* Prevent argument from being register allocated */
9976                                                 arg_array [i]->flags |= MONO_INST_VOLATILE;
9977                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9978                                         }
9979                                         ins = (MonoInst*)call;
9980                                         ins->inst_p0 = cmethod;
9981                                         ins->inst_p1 = arg_array [0];
9982                                         MONO_ADD_INS (cfg->cbb, ins);
9983                                         link_bblock (cfg, cfg->cbb, end_bblock);
9984                                         start_new_bblock = 1;
9985
9986                                         // FIXME: Eliminate unreachable epilogs
9987
9988                                         /*
9989                                          * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9990                                          * only reachable from this call.
9991                                          */
9992                                         GET_BBLOCK (cfg, tblock, ip + 5);
9993                                         if (tblock == cfg->cbb || tblock->in_count == 0)
9994                                                 skip_ret = TRUE;
9995                                         push_res = FALSE;
9996
9997                                         goto call_end;
9998                                 }
9999                         }
10000
10001                         /*
10002                          * Virtual calls in llvm-only mode.
10003                          */
10004                         if (cfg->llvm_only && virtual_ && cmethod && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
10005                                 ins = emit_llvmonly_virtual_call (cfg, cmethod, fsig, context_used, sp);
10006                                 goto call_end;
10007                         }
10008
10009                         /* Common call */
10010                         INLINE_FAILURE ("call");
10011                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, tail_call, sp, virtual_ ? sp [0] : NULL,
10012                                                                                           imt_arg, vtable_arg);
10013
10014                         if (tail_call && !cfg->llvm_only) {
10015                                 link_bblock (cfg, cfg->cbb, end_bblock);
10016                                 start_new_bblock = 1;
10017
10018                                 // FIXME: Eliminate unreachable epilogs
10019
10020                                 /*
10021                                  * OP_TAILCALL has no return value, so skip the CEE_RET if it is
10022                                  * only reachable from this call.
10023                                  */
10024                                 GET_BBLOCK (cfg, tblock, ip + 5);
10025                                 if (tblock == cfg->cbb || tblock->in_count == 0)
10026                                         skip_ret = TRUE;
10027                                 push_res = FALSE;
10028                         }
10029
10030                         call_end:
10031
10032                         /* End of call, INS should contain the result of the call, if any */
10033
10034                         if (push_res && !MONO_TYPE_IS_VOID (fsig->ret)) {
10035                                 g_assert (ins);
10036                                 if (emit_widen)
10037                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
10038                                 else
10039                                         *sp++ = ins;
10040                         }
10041
10042                         if (keep_this_alive) {
10043                                 MonoInst *dummy_use;
10044
10045                                 /* See mono_emit_method_call_full () */
10046                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, keep_this_alive);
10047                         }
10048
10049                         if (cfg->llvm_only && cmethod && method_needs_stack_walk (cfg, cmethod)) {
10050                                 /*
10051                                  * Clang can convert these calls to tail calls which screw up the stack
10052                                  * walk. This happens even when the -fno-optimize-sibling-calls
10053                                  * option is passed to clang.
10054                                  * Work around this by emitting a dummy call.
10055                                  */
10056                                 mono_emit_jit_icall (cfg, mono_dummy_jit_icall, NULL);
10057                         }
10058
10059                         CHECK_CFG_EXCEPTION;
10060
10061                         ip += 5;
10062                         if (skip_ret) {
10063                                 g_assert (*ip == CEE_RET);
10064                                 ip += 1;
10065                         }
10066                         ins_flag = 0;
10067                         constrained_class = NULL;
10068                         if (need_seq_point)
10069                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
10070                         break;
10071                 }
10072                 case CEE_RET:
10073                         if (cfg->method != method) {
10074                                 /* return from inlined method */
10075                                 /* 
10076                                  * If in_count == 0, that means the ret is unreachable due to
10077                                  * being preceeded by a throw. In that case, inline_method () will
10078                                  * handle setting the return value 
10079                                  * (test case: test_0_inline_throw ()).
10080                                  */
10081                                 if (return_var && cfg->cbb->in_count) {
10082                                         MonoType *ret_type = mono_method_signature (method)->ret;
10083
10084                                         MonoInst *store;
10085                                         CHECK_STACK (1);
10086                                         --sp;
10087
10088                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
10089                                                 UNVERIFIED;
10090
10091                                         //g_assert (returnvar != -1);
10092                                         EMIT_NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
10093                                         cfg->ret_var_set = TRUE;
10094                                 } 
10095                         } else {
10096                                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
10097
10098                                 if (cfg->lmf_var && cfg->cbb->in_count && !cfg->llvm_only)
10099                                         emit_pop_lmf (cfg);
10100
10101                                 if (cfg->ret) {
10102                                         MonoType *ret_type = mini_get_underlying_type (mono_method_signature (method)->ret);
10103
10104                                         if (seq_points && !sym_seq_points) {
10105                                                 /* 
10106                                                  * Place a seq point here too even through the IL stack is not
10107                                                  * empty, so a step over on
10108                                                  * call <FOO>
10109                                                  * ret
10110                                                  * will work correctly.
10111                                                  */
10112                                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, TRUE);
10113                                                 MONO_ADD_INS (cfg->cbb, ins);
10114                                         }
10115
10116                                         g_assert (!return_var);
10117                                         CHECK_STACK (1);
10118                                         --sp;
10119
10120                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
10121                                                 UNVERIFIED;
10122
10123                                         emit_setret (cfg, *sp);
10124                                 }
10125                         }
10126                         if (sp != stack_start)
10127                                 UNVERIFIED;
10128                         MONO_INST_NEW (cfg, ins, OP_BR);
10129                         ip++;
10130                         ins->inst_target_bb = end_bblock;
10131                         MONO_ADD_INS (cfg->cbb, ins);
10132                         link_bblock (cfg, cfg->cbb, end_bblock);
10133                         start_new_bblock = 1;
10134                         break;
10135                 case CEE_BR_S:
10136                         CHECK_OPSIZE (2);
10137                         MONO_INST_NEW (cfg, ins, OP_BR);
10138                         ip++;
10139                         target = ip + 1 + (signed char)(*ip);
10140                         ++ip;
10141                         GET_BBLOCK (cfg, tblock, target);
10142                         link_bblock (cfg, cfg->cbb, tblock);
10143                         ins->inst_target_bb = tblock;
10144                         if (sp != stack_start) {
10145                                 handle_stack_args (cfg, stack_start, sp - stack_start);
10146                                 sp = stack_start;
10147                                 CHECK_UNVERIFIABLE (cfg);
10148                         }
10149                         MONO_ADD_INS (cfg->cbb, ins);
10150                         start_new_bblock = 1;
10151                         inline_costs += BRANCH_COST;
10152                         break;
10153                 case CEE_BEQ_S:
10154                 case CEE_BGE_S:
10155                 case CEE_BGT_S:
10156                 case CEE_BLE_S:
10157                 case CEE_BLT_S:
10158                 case CEE_BNE_UN_S:
10159                 case CEE_BGE_UN_S:
10160                 case CEE_BGT_UN_S:
10161                 case CEE_BLE_UN_S:
10162                 case CEE_BLT_UN_S:
10163                         CHECK_OPSIZE (2);
10164                         CHECK_STACK (2);
10165                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
10166                         ip++;
10167                         target = ip + 1 + *(signed char*)ip;
10168                         ip++;
10169
10170                         ADD_BINCOND (NULL);
10171
10172                         sp = stack_start;
10173                         inline_costs += BRANCH_COST;
10174                         break;
10175                 case CEE_BR:
10176                         CHECK_OPSIZE (5);
10177                         MONO_INST_NEW (cfg, ins, OP_BR);
10178                         ip++;
10179
10180                         target = ip + 4 + (gint32)read32(ip);
10181                         ip += 4;
10182                         GET_BBLOCK (cfg, tblock, target);
10183                         link_bblock (cfg, cfg->cbb, tblock);
10184                         ins->inst_target_bb = tblock;
10185                         if (sp != stack_start) {
10186                                 handle_stack_args (cfg, stack_start, sp - stack_start);
10187                                 sp = stack_start;
10188                                 CHECK_UNVERIFIABLE (cfg);
10189                         }
10190
10191                         MONO_ADD_INS (cfg->cbb, ins);
10192
10193                         start_new_bblock = 1;
10194                         inline_costs += BRANCH_COST;
10195                         break;
10196                 case CEE_BRFALSE_S:
10197                 case CEE_BRTRUE_S:
10198                 case CEE_BRFALSE:
10199                 case CEE_BRTRUE: {
10200                         MonoInst *cmp;
10201                         gboolean is_short = ((*ip) == CEE_BRFALSE_S) || ((*ip) == CEE_BRTRUE_S);
10202                         gboolean is_true = ((*ip) == CEE_BRTRUE_S) || ((*ip) == CEE_BRTRUE);
10203                         guint32 opsize = is_short ? 1 : 4;
10204
10205                         CHECK_OPSIZE (opsize);
10206                         CHECK_STACK (1);
10207                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
10208                                 UNVERIFIED;
10209                         ip ++;
10210                         target = ip + opsize + (is_short ? *(signed char*)ip : (gint32)read32(ip));
10211                         ip += opsize;
10212
10213                         sp--;
10214
10215                         GET_BBLOCK (cfg, tblock, target);
10216                         link_bblock (cfg, cfg->cbb, tblock);
10217                         GET_BBLOCK (cfg, tblock, ip);
10218                         link_bblock (cfg, cfg->cbb, tblock);
10219
10220                         if (sp != stack_start) {
10221                                 handle_stack_args (cfg, stack_start, sp - stack_start);
10222                                 CHECK_UNVERIFIABLE (cfg);
10223                         }
10224
10225                         MONO_INST_NEW(cfg, cmp, OP_ICOMPARE_IMM);
10226                         cmp->sreg1 = sp [0]->dreg;
10227                         type_from_op (cfg, cmp, sp [0], NULL);
10228                         CHECK_TYPE (cmp);
10229
10230 #if SIZEOF_REGISTER == 4
10231                         if (cmp->opcode == OP_LCOMPARE_IMM) {
10232                                 /* Convert it to OP_LCOMPARE */
10233                                 MONO_INST_NEW (cfg, ins, OP_I8CONST);
10234                                 ins->type = STACK_I8;
10235                                 ins->dreg = alloc_dreg (cfg, STACK_I8);
10236                                 ins->inst_l = 0;
10237                                 MONO_ADD_INS (cfg->cbb, ins);
10238                                 cmp->opcode = OP_LCOMPARE;
10239                                 cmp->sreg2 = ins->dreg;
10240                         }
10241 #endif
10242                         MONO_ADD_INS (cfg->cbb, cmp);
10243
10244                         MONO_INST_NEW (cfg, ins, is_true ? CEE_BNE_UN : CEE_BEQ);
10245                         type_from_op (cfg, ins, sp [0], NULL);
10246                         MONO_ADD_INS (cfg->cbb, ins);
10247                         ins->inst_many_bb = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);
10248                         GET_BBLOCK (cfg, tblock, target);
10249                         ins->inst_true_bb = tblock;
10250                         GET_BBLOCK (cfg, tblock, ip);
10251                         ins->inst_false_bb = tblock;
10252                         start_new_bblock = 2;
10253
10254                         sp = stack_start;
10255                         inline_costs += BRANCH_COST;
10256                         break;
10257                 }
10258                 case CEE_BEQ:
10259                 case CEE_BGE:
10260                 case CEE_BGT:
10261                 case CEE_BLE:
10262                 case CEE_BLT:
10263                 case CEE_BNE_UN:
10264                 case CEE_BGE_UN:
10265                 case CEE_BGT_UN:
10266                 case CEE_BLE_UN:
10267                 case CEE_BLT_UN:
10268                         CHECK_OPSIZE (5);
10269                         CHECK_STACK (2);
10270                         MONO_INST_NEW (cfg, ins, *ip);
10271                         ip++;
10272                         target = ip + 4 + (gint32)read32(ip);
10273                         ip += 4;
10274
10275                         ADD_BINCOND (NULL);
10276
10277                         sp = stack_start;
10278                         inline_costs += BRANCH_COST;
10279                         break;
10280                 case CEE_SWITCH: {
10281                         MonoInst *src1;
10282                         MonoBasicBlock **targets;
10283                         MonoBasicBlock *default_bblock;
10284                         MonoJumpInfoBBTable *table;
10285                         int offset_reg = alloc_preg (cfg);
10286                         int target_reg = alloc_preg (cfg);
10287                         int table_reg = alloc_preg (cfg);
10288                         int sum_reg = alloc_preg (cfg);
10289                         gboolean use_op_switch;
10290
10291                         CHECK_OPSIZE (5);
10292                         CHECK_STACK (1);
10293                         n = read32 (ip + 1);
10294                         --sp;
10295                         src1 = sp [0];
10296                         if ((src1->type != STACK_I4) && (src1->type != STACK_PTR)) 
10297                                 UNVERIFIED;
10298
10299                         ip += 5;
10300                         CHECK_OPSIZE (n * sizeof (guint32));
10301                         target = ip + n * sizeof (guint32);
10302
10303                         GET_BBLOCK (cfg, default_bblock, target);
10304                         default_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
10305
10306                         targets = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * n);
10307                         for (i = 0; i < n; ++i) {
10308                                 GET_BBLOCK (cfg, tblock, target + (gint32)read32(ip));
10309                                 targets [i] = tblock;
10310                                 targets [i]->flags |= BB_INDIRECT_JUMP_TARGET;
10311                                 ip += 4;
10312                         }
10313
10314                         if (sp != stack_start) {
10315                                 /* 
10316                                  * Link the current bb with the targets as well, so handle_stack_args
10317                                  * will set their in_stack correctly.
10318                                  */
10319                                 link_bblock (cfg, cfg->cbb, default_bblock);
10320                                 for (i = 0; i < n; ++i)
10321                                         link_bblock (cfg, cfg->cbb, targets [i]);
10322
10323                                 handle_stack_args (cfg, stack_start, sp - stack_start);
10324                                 sp = stack_start;
10325                                 CHECK_UNVERIFIABLE (cfg);
10326
10327                                 /* Undo the links */
10328                                 mono_unlink_bblock (cfg, cfg->cbb, default_bblock);
10329                                 for (i = 0; i < n; ++i)
10330                                         mono_unlink_bblock (cfg, cfg->cbb, targets [i]);
10331                         }
10332
10333                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, src1->dreg, n);
10334                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBGE_UN, default_bblock);
10335
10336                         for (i = 0; i < n; ++i)
10337                                 link_bblock (cfg, cfg->cbb, targets [i]);
10338
10339                         table = (MonoJumpInfoBBTable *)mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
10340                         table->table = targets;
10341                         table->table_size = n;
10342
10343                         use_op_switch = FALSE;
10344 #ifdef TARGET_ARM
10345                         /* ARM implements SWITCH statements differently */
10346                         /* FIXME: Make it use the generic implementation */
10347                         if (!cfg->compile_aot)
10348                                 use_op_switch = TRUE;
10349 #endif
10350
10351                         if (COMPILE_LLVM (cfg))
10352                                 use_op_switch = TRUE;
10353
10354                         cfg->cbb->has_jump_table = 1;
10355
10356                         if (use_op_switch) {
10357                                 MONO_INST_NEW (cfg, ins, OP_SWITCH);
10358                                 ins->sreg1 = src1->dreg;
10359                                 ins->inst_p0 = table;
10360                                 ins->inst_many_bb = targets;
10361                                 ins->klass = (MonoClass *)GUINT_TO_POINTER (n);
10362                                 MONO_ADD_INS (cfg->cbb, ins);
10363                         } else {
10364                                 if (sizeof (gpointer) == 8)
10365                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 3);
10366                                 else
10367                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 2);
10368
10369 #if SIZEOF_REGISTER == 8
10370                                 /* The upper word might not be zero, and we add it to a 64 bit address later */
10371                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, offset_reg, offset_reg);
10372 #endif
10373
10374                                 if (cfg->compile_aot) {
10375                                         MONO_EMIT_NEW_AOTCONST (cfg, table_reg, table, MONO_PATCH_INFO_SWITCH);
10376                                 } else {
10377                                         MONO_INST_NEW (cfg, ins, OP_JUMP_TABLE);
10378                                         ins->inst_c1 = MONO_PATCH_INFO_SWITCH;
10379                                         ins->inst_p0 = table;
10380                                         ins->dreg = table_reg;
10381                                         MONO_ADD_INS (cfg->cbb, ins);
10382                                 }
10383
10384                                 /* FIXME: Use load_memindex */
10385                                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, table_reg, offset_reg);
10386                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, target_reg, sum_reg, 0);
10387                                 MONO_EMIT_NEW_UNALU (cfg, OP_BR_REG, -1, target_reg);
10388                         }
10389                         start_new_bblock = 1;
10390                         inline_costs += (BRANCH_COST * 2);
10391                         break;
10392                 }
10393                 case CEE_LDIND_I1:
10394                 case CEE_LDIND_U1:
10395                 case CEE_LDIND_I2:
10396                 case CEE_LDIND_U2:
10397                 case CEE_LDIND_I4:
10398                 case CEE_LDIND_U4:
10399                 case CEE_LDIND_I8:
10400                 case CEE_LDIND_I:
10401                 case CEE_LDIND_R4:
10402                 case CEE_LDIND_R8:
10403                 case CEE_LDIND_REF:
10404                         CHECK_STACK (1);
10405                         --sp;
10406
10407                         switch (*ip) {
10408                         case CEE_LDIND_R4:
10409                         case CEE_LDIND_R8:
10410                                 dreg = alloc_freg (cfg);
10411                                 break;
10412                         case CEE_LDIND_I8:
10413                                 dreg = alloc_lreg (cfg);
10414                                 break;
10415                         case CEE_LDIND_REF:
10416                                 dreg = alloc_ireg_ref (cfg);
10417                                 break;
10418                         default:
10419                                 dreg = alloc_preg (cfg);
10420                         }
10421
10422                         NEW_LOAD_MEMBASE (cfg, ins, ldind_to_load_membase (*ip), dreg, sp [0]->dreg, 0);
10423                         ins->type = ldind_type [*ip - CEE_LDIND_I1];
10424                         if (*ip == CEE_LDIND_R4)
10425                                 ins->type = cfg->r4_stack_type;
10426                         ins->flags |= ins_flag;
10427                         MONO_ADD_INS (cfg->cbb, ins);
10428                         *sp++ = ins;
10429                         if (ins_flag & MONO_INST_VOLATILE) {
10430                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10431                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10432                         }
10433                         ins_flag = 0;
10434                         ++ip;
10435                         break;
10436                 case CEE_STIND_REF:
10437                 case CEE_STIND_I1:
10438                 case CEE_STIND_I2:
10439                 case CEE_STIND_I4:
10440                 case CEE_STIND_I8:
10441                 case CEE_STIND_R4:
10442                 case CEE_STIND_R8:
10443                 case CEE_STIND_I:
10444                         CHECK_STACK (2);
10445                         sp -= 2;
10446
10447                         if (ins_flag & MONO_INST_VOLATILE) {
10448                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
10449                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
10450                         }
10451
10452                         NEW_STORE_MEMBASE (cfg, ins, stind_to_store_membase (*ip), sp [0]->dreg, 0, sp [1]->dreg);
10453                         ins->flags |= ins_flag;
10454                         ins_flag = 0;
10455
10456                         MONO_ADD_INS (cfg->cbb, ins);
10457
10458                         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)))
10459                                 emit_write_barrier (cfg, sp [0], sp [1]);
10460
10461                         inline_costs += 1;
10462                         ++ip;
10463                         break;
10464
10465                 case CEE_MUL:
10466                         CHECK_STACK (2);
10467
10468                         MONO_INST_NEW (cfg, ins, (*ip));
10469                         sp -= 2;
10470                         ins->sreg1 = sp [0]->dreg;
10471                         ins->sreg2 = sp [1]->dreg;
10472                         type_from_op (cfg, ins, sp [0], sp [1]);
10473                         CHECK_TYPE (ins);
10474                         ins->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type);
10475
10476                         /* Use the immediate opcodes if possible */
10477                         if ((sp [1]->opcode == OP_ICONST) && mono_arch_is_inst_imm (sp [1]->inst_c0)) {
10478                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
10479                                 if (imm_opcode != -1) {
10480                                         ins->opcode = imm_opcode;
10481                                         ins->inst_p1 = (gpointer)(gssize)(sp [1]->inst_c0);
10482                                         ins->sreg2 = -1;
10483
10484                                         NULLIFY_INS (sp [1]);
10485                                 }
10486                         }
10487
10488                         MONO_ADD_INS ((cfg)->cbb, (ins));
10489
10490                         *sp++ = mono_decompose_opcode (cfg, ins);
10491                         ip++;
10492                         break;
10493                 case CEE_ADD:
10494                 case CEE_SUB:
10495                 case CEE_DIV:
10496                 case CEE_DIV_UN:
10497                 case CEE_REM:
10498                 case CEE_REM_UN:
10499                 case CEE_AND:
10500                 case CEE_OR:
10501                 case CEE_XOR:
10502                 case CEE_SHL:
10503                 case CEE_SHR:
10504                 case CEE_SHR_UN:
10505                         CHECK_STACK (2);
10506
10507                         MONO_INST_NEW (cfg, ins, (*ip));
10508                         sp -= 2;
10509                         ins->sreg1 = sp [0]->dreg;
10510                         ins->sreg2 = sp [1]->dreg;
10511                         type_from_op (cfg, ins, sp [0], sp [1]);
10512                         CHECK_TYPE (ins);
10513                         add_widen_op (cfg, ins, &sp [0], &sp [1]);
10514                         ins->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type);
10515
10516                         /* FIXME: Pass opcode to is_inst_imm */
10517
10518                         /* Use the immediate opcodes if possible */
10519                         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)) {
10520                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
10521                                 if (imm_opcode != -1) {
10522                                         ins->opcode = imm_opcode;
10523                                         if (sp [1]->opcode == OP_I8CONST) {
10524 #if SIZEOF_REGISTER == 8
10525                                                 ins->inst_imm = sp [1]->inst_l;
10526 #else
10527                                                 ins->inst_ls_word = sp [1]->inst_ls_word;
10528                                                 ins->inst_ms_word = sp [1]->inst_ms_word;
10529 #endif
10530                                         }
10531                                         else
10532                                                 ins->inst_imm = (gssize)(sp [1]->inst_c0);
10533                                         ins->sreg2 = -1;
10534
10535                                         /* Might be followed by an instruction added by add_widen_op */
10536                                         if (sp [1]->next == NULL)
10537                                                 NULLIFY_INS (sp [1]);
10538                                 }
10539                         }
10540                         MONO_ADD_INS ((cfg)->cbb, (ins));
10541
10542                         *sp++ = mono_decompose_opcode (cfg, ins);
10543                         ip++;
10544                         break;
10545                 case CEE_NEG:
10546                 case CEE_NOT:
10547                 case CEE_CONV_I1:
10548                 case CEE_CONV_I2:
10549                 case CEE_CONV_I4:
10550                 case CEE_CONV_R4:
10551                 case CEE_CONV_R8:
10552                 case CEE_CONV_U4:
10553                 case CEE_CONV_I8:
10554                 case CEE_CONV_U8:
10555                 case CEE_CONV_OVF_I8:
10556                 case CEE_CONV_OVF_U8:
10557                 case CEE_CONV_R_UN:
10558                         CHECK_STACK (1);
10559
10560                         /* Special case this earlier so we have long constants in the IR */
10561                         if ((((*ip) == CEE_CONV_I8) || ((*ip) == CEE_CONV_U8)) && (sp [-1]->opcode == OP_ICONST)) {
10562                                 int data = sp [-1]->inst_c0;
10563                                 sp [-1]->opcode = OP_I8CONST;
10564                                 sp [-1]->type = STACK_I8;
10565 #if SIZEOF_REGISTER == 8
10566                                 if ((*ip) == CEE_CONV_U8)
10567                                         sp [-1]->inst_c0 = (guint32)data;
10568                                 else
10569                                         sp [-1]->inst_c0 = data;
10570 #else
10571                                 sp [-1]->inst_ls_word = data;
10572                                 if ((*ip) == CEE_CONV_U8)
10573                                         sp [-1]->inst_ms_word = 0;
10574                                 else
10575                                         sp [-1]->inst_ms_word = (data < 0) ? -1 : 0;
10576 #endif
10577                                 sp [-1]->dreg = alloc_dreg (cfg, STACK_I8);
10578                         }
10579                         else {
10580                                 ADD_UNOP (*ip);
10581                         }
10582                         ip++;
10583                         break;
10584                 case CEE_CONV_OVF_I4:
10585                 case CEE_CONV_OVF_I1:
10586                 case CEE_CONV_OVF_I2:
10587                 case CEE_CONV_OVF_I:
10588                 case CEE_CONV_OVF_U:
10589                         CHECK_STACK (1);
10590
10591                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
10592                                 ADD_UNOP (CEE_CONV_OVF_I8);
10593                                 ADD_UNOP (*ip);
10594                         } else {
10595                                 ADD_UNOP (*ip);
10596                         }
10597                         ip++;
10598                         break;
10599                 case CEE_CONV_OVF_U1:
10600                 case CEE_CONV_OVF_U2:
10601                 case CEE_CONV_OVF_U4:
10602                         CHECK_STACK (1);
10603
10604                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
10605                                 ADD_UNOP (CEE_CONV_OVF_U8);
10606                                 ADD_UNOP (*ip);
10607                         } else {
10608                                 ADD_UNOP (*ip);
10609                         }
10610                         ip++;
10611                         break;
10612                 case CEE_CONV_OVF_I1_UN:
10613                 case CEE_CONV_OVF_I2_UN:
10614                 case CEE_CONV_OVF_I4_UN:
10615                 case CEE_CONV_OVF_I8_UN:
10616                 case CEE_CONV_OVF_U1_UN:
10617                 case CEE_CONV_OVF_U2_UN:
10618                 case CEE_CONV_OVF_U4_UN:
10619                 case CEE_CONV_OVF_U8_UN:
10620                 case CEE_CONV_OVF_I_UN:
10621                 case CEE_CONV_OVF_U_UN:
10622                 case CEE_CONV_U2:
10623                 case CEE_CONV_U1:
10624                 case CEE_CONV_I:
10625                 case CEE_CONV_U:
10626                         CHECK_STACK (1);
10627                         ADD_UNOP (*ip);
10628                         CHECK_CFG_EXCEPTION;
10629                         ip++;
10630                         break;
10631                 case CEE_ADD_OVF:
10632                 case CEE_ADD_OVF_UN:
10633                 case CEE_MUL_OVF:
10634                 case CEE_MUL_OVF_UN:
10635                 case CEE_SUB_OVF:
10636                 case CEE_SUB_OVF_UN:
10637                         CHECK_STACK (2);
10638                         ADD_BINOP (*ip);
10639                         ip++;
10640                         break;
10641                 case CEE_CPOBJ:
10642                         GSHAREDVT_FAILURE (*ip);
10643                         CHECK_OPSIZE (5);
10644                         CHECK_STACK (2);
10645                         token = read32 (ip + 1);
10646                         klass = mini_get_class (method, token, generic_context);
10647                         CHECK_TYPELOAD (klass);
10648                         sp -= 2;
10649                         if (generic_class_is_reference_type (cfg, klass)) {
10650                                 MonoInst *store, *load;
10651                                 int dreg = alloc_ireg_ref (cfg);
10652
10653                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, dreg, sp [1]->dreg, 0);
10654                                 load->flags |= ins_flag;
10655                                 MONO_ADD_INS (cfg->cbb, load);
10656
10657                                 NEW_STORE_MEMBASE (cfg, store, OP_STORE_MEMBASE_REG, sp [0]->dreg, 0, dreg);
10658                                 store->flags |= ins_flag;
10659                                 MONO_ADD_INS (cfg->cbb, store);
10660
10661                                 if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER)
10662                                         emit_write_barrier (cfg, sp [0], sp [1]);
10663                         } else {
10664                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
10665                         }
10666                         ins_flag = 0;
10667                         ip += 5;
10668                         break;
10669                 case CEE_LDOBJ: {
10670                         int loc_index = -1;
10671                         int stloc_len = 0;
10672
10673                         CHECK_OPSIZE (5);
10674                         CHECK_STACK (1);
10675                         --sp;
10676                         token = read32 (ip + 1);
10677                         klass = mini_get_class (method, token, generic_context);
10678                         CHECK_TYPELOAD (klass);
10679
10680                         /* Optimize the common ldobj+stloc combination */
10681                         switch (ip [5]) {
10682                         case CEE_STLOC_S:
10683                                 loc_index = ip [6];
10684                                 stloc_len = 2;
10685                                 break;
10686                         case CEE_STLOC_0:
10687                         case CEE_STLOC_1:
10688                         case CEE_STLOC_2:
10689                         case CEE_STLOC_3:
10690                                 loc_index = ip [5] - CEE_STLOC_0;
10691                                 stloc_len = 1;
10692                                 break;
10693                         default:
10694                                 break;
10695                         }
10696
10697                         if ((loc_index != -1) && ip_in_bb (cfg, cfg->cbb, ip + 5)) {
10698                                 CHECK_LOCAL (loc_index);
10699
10700                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10701                                 ins->dreg = cfg->locals [loc_index]->dreg;
10702                                 ins->flags |= ins_flag;
10703                                 ip += 5;
10704                                 ip += stloc_len;
10705                                 if (ins_flag & MONO_INST_VOLATILE) {
10706                                         /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10707                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10708                                 }
10709                                 ins_flag = 0;
10710                                 break;
10711                         }
10712
10713                         /* Optimize the ldobj+stobj combination */
10714                         /* The reference case ends up being a load+store anyway */
10715                         /* Skip this if the operation is volatile. */
10716                         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)) {
10717                                 CHECK_STACK (1);
10718
10719                                 sp --;
10720
10721                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
10722
10723                                 ip += 5 + 5;
10724                                 ins_flag = 0;
10725                                 break;
10726                         }
10727
10728                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10729                         ins->flags |= ins_flag;
10730                         *sp++ = ins;
10731
10732                         if (ins_flag & MONO_INST_VOLATILE) {
10733                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10734                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10735                         }
10736
10737                         ip += 5;
10738                         ins_flag = 0;
10739                         inline_costs += 1;
10740                         break;
10741                 }
10742                 case CEE_LDSTR:
10743                         CHECK_STACK_OVF (1);
10744                         CHECK_OPSIZE (5);
10745                         n = read32 (ip + 1);
10746
10747                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
10748                                 EMIT_NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
10749                                 ins->type = STACK_OBJ;
10750                                 *sp = ins;
10751                         }
10752                         else if (method->wrapper_type != MONO_WRAPPER_NONE) {
10753                                 MonoInst *iargs [1];
10754                                 char *str = (char *)mono_method_get_wrapper_data (method, n);
10755
10756                                 if (cfg->compile_aot)
10757                                         EMIT_NEW_LDSTRLITCONST (cfg, iargs [0], str);
10758                                 else
10759                                         EMIT_NEW_PCONST (cfg, iargs [0], str);
10760                                 *sp = mono_emit_jit_icall (cfg, mono_string_new_wrapper, iargs);
10761                         } else {
10762                                 if (cfg->opt & MONO_OPT_SHARED) {
10763                                         MonoInst *iargs [3];
10764
10765                                         if (cfg->compile_aot) {
10766                                                 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
10767                                         }
10768                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10769                                         EMIT_NEW_IMAGECONST (cfg, iargs [1], image);
10770                                         EMIT_NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
10771                                         *sp = mono_emit_jit_icall (cfg, ves_icall_mono_ldstr, iargs);
10772                                         mono_ldstr_checked (cfg->domain, image, mono_metadata_token_index (n), &cfg->error);
10773                                         CHECK_CFG_ERROR;
10774                                 } else {
10775                                         if (cfg->cbb->out_of_line) {
10776                                                 MonoInst *iargs [2];
10777
10778                                                 if (image == mono_defaults.corlib) {
10779                                                         /* 
10780                                                          * Avoid relocations in AOT and save some space by using a 
10781                                                          * version of helper_ldstr specialized to mscorlib.
10782                                                          */
10783                                                         EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (n));
10784                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr_mscorlib, iargs);
10785                                                 } else {
10786                                                         /* Avoid creating the string object */
10787                                                         EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
10788                                                         EMIT_NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n));
10789                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr, iargs);
10790                                                 }
10791                                         } 
10792                                         else
10793                                         if (cfg->compile_aot) {
10794                                                 NEW_LDSTRCONST (cfg, ins, image, n);
10795                                                 *sp = ins;
10796                                                 MONO_ADD_INS (cfg->cbb, ins);
10797                                         } 
10798                                         else {
10799                                                 NEW_PCONST (cfg, ins, NULL);
10800                                                 ins->type = STACK_OBJ;
10801                                                 ins->inst_p0 = mono_ldstr_checked (cfg->domain, image, mono_metadata_token_index (n), &cfg->error);
10802                                                 CHECK_CFG_ERROR;
10803                                                 
10804                                                 if (!ins->inst_p0)
10805                                                         OUT_OF_MEMORY_FAILURE;
10806
10807                                                 *sp = ins;
10808                                                 MONO_ADD_INS (cfg->cbb, ins);
10809                                         }
10810                                 }
10811                         }
10812
10813                         sp++;
10814                         ip += 5;
10815                         break;
10816                 case CEE_NEWOBJ: {
10817                         MonoInst *iargs [2];
10818                         MonoMethodSignature *fsig;
10819                         MonoInst this_ins;
10820                         MonoInst *alloc;
10821                         MonoInst *vtable_arg = NULL;
10822
10823                         CHECK_OPSIZE (5);
10824                         token = read32 (ip + 1);
10825                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
10826                         CHECK_CFG_ERROR;
10827
10828                         fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
10829                         CHECK_CFG_ERROR;
10830
10831                         mono_save_token_info (cfg, image, token, cmethod);
10832
10833                         if (!mono_class_init (cmethod->klass))
10834                                 TYPE_LOAD_ERROR (cmethod->klass);
10835
10836                         context_used = mini_method_check_context_used (cfg, cmethod);
10837
10838                         if (mono_security_core_clr_enabled ())
10839                                 ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
10840
10841                         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)) {
10842                                 emit_class_init (cfg, cmethod->klass);
10843                                 CHECK_TYPELOAD (cmethod->klass);
10844                         }
10845
10846                         /*
10847                         if (cfg->gsharedvt) {
10848                                 if (mini_is_gsharedvt_variable_signature (sig))
10849                                         GSHAREDVT_FAILURE (*ip);
10850                         }
10851                         */
10852
10853                         n = fsig->param_count;
10854                         CHECK_STACK (n);
10855
10856                         /* 
10857                          * Generate smaller code for the common newobj <exception> instruction in
10858                          * argument checking code.
10859                          */
10860                         if (cfg->cbb->out_of_line && cmethod->klass->image == mono_defaults.corlib &&
10861                                 is_exception_class (cmethod->klass) && n <= 2 &&
10862                                 ((n < 1) || (!fsig->params [0]->byref && fsig->params [0]->type == MONO_TYPE_STRING)) && 
10863                                 ((n < 2) || (!fsig->params [1]->byref && fsig->params [1]->type == MONO_TYPE_STRING))) {
10864                                 MonoInst *iargs [3];
10865
10866                                 sp -= n;
10867
10868                                 EMIT_NEW_ICONST (cfg, iargs [0], cmethod->klass->type_token);
10869                                 switch (n) {
10870                                 case 0:
10871                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_0, iargs);
10872                                         break;
10873                                 case 1:
10874                                         iargs [1] = sp [0];
10875                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_1, iargs);
10876                                         break;
10877                                 case 2:
10878                                         iargs [1] = sp [0];
10879                                         iargs [2] = sp [1];
10880                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_2, iargs);
10881                                         break;
10882                                 default:
10883                                         g_assert_not_reached ();
10884                                 }
10885
10886                                 ip += 5;
10887                                 inline_costs += 5;
10888                                 break;
10889                         }
10890
10891                         /* move the args to allow room for 'this' in the first position */
10892                         while (n--) {
10893                                 --sp;
10894                                 sp [1] = sp [0];
10895                         }
10896
10897                         /* check_call_signature () requires sp[0] to be set */
10898                         this_ins.type = STACK_OBJ;
10899                         sp [0] = &this_ins;
10900                         if (check_call_signature (cfg, fsig, sp))
10901                                 UNVERIFIED;
10902
10903                         iargs [0] = NULL;
10904
10905                         if (mini_class_is_system_array (cmethod->klass)) {
10906                                 *sp = emit_get_rgctx_method (cfg, context_used,
10907                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
10908
10909                                 /* Avoid varargs in the common case */
10910                                 if (fsig->param_count == 1)
10911                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_1, sp);
10912                                 else if (fsig->param_count == 2)
10913                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_2, sp);
10914                                 else if (fsig->param_count == 3)
10915                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_3, sp);
10916                                 else if (fsig->param_count == 4)
10917                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_4, sp);
10918                                 else
10919                                         alloc = handle_array_new (cfg, fsig->param_count, sp, ip);
10920                         } else if (cmethod->string_ctor) {
10921                                 g_assert (!context_used);
10922                                 g_assert (!vtable_arg);
10923                                 /* we simply pass a null pointer */
10924                                 EMIT_NEW_PCONST (cfg, *sp, NULL); 
10925                                 /* now call the string ctor */
10926                                 alloc = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, NULL, NULL, NULL);
10927                         } else {
10928                                 if (cmethod->klass->valuetype) {
10929                                         iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
10930                                         emit_init_rvar (cfg, iargs [0]->dreg, &cmethod->klass->byval_arg);
10931                                         EMIT_NEW_TEMPLOADA (cfg, *sp, iargs [0]->inst_c0);
10932
10933                                         alloc = NULL;
10934
10935                                         /* 
10936                                          * The code generated by mini_emit_virtual_call () expects
10937                                          * iargs [0] to be a boxed instance, but luckily the vcall
10938                                          * will be transformed into a normal call there.
10939                                          */
10940                                 } else if (context_used) {
10941                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, context_used);
10942                                         *sp = alloc;
10943                                 } else {
10944                                         MonoVTable *vtable = NULL;
10945
10946                                         if (!cfg->compile_aot)
10947                                                 vtable = mono_class_vtable (cfg->domain, cmethod->klass);
10948                                         CHECK_TYPELOAD (cmethod->klass);
10949
10950                                         /*
10951                                          * TypeInitializationExceptions thrown from the mono_runtime_class_init
10952                                          * call in mono_jit_runtime_invoke () can abort the finalizer thread.
10953                                          * As a workaround, we call class cctors before allocating objects.
10954                                          */
10955                                         if (mini_field_access_needs_cctor_run (cfg, method, cmethod->klass, vtable) && !(g_slist_find (class_inits, cmethod->klass))) {
10956                                                 emit_class_init (cfg, cmethod->klass);
10957                                                 if (cfg->verbose_level > 2)
10958                                                         printf ("class %s.%s needs init call for ctor\n", cmethod->klass->name_space, cmethod->klass->name);
10959                                                 class_inits = g_slist_prepend (class_inits, cmethod->klass);
10960                                         }
10961
10962                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, 0);
10963                                         *sp = alloc;
10964                                 }
10965                                 CHECK_CFG_EXCEPTION; /*for handle_alloc*/
10966
10967                                 if (alloc)
10968                                         MONO_EMIT_NEW_UNALU (cfg, OP_NOT_NULL, -1, alloc->dreg);
10969
10970                                 /* Now call the actual ctor */
10971                                 handle_ctor_call (cfg, cmethod, fsig, context_used, sp, ip, &inline_costs);
10972                                 CHECK_CFG_EXCEPTION;
10973                         }
10974
10975                         if (alloc == NULL) {
10976                                 /* Valuetype */
10977                                 EMIT_NEW_TEMPLOAD (cfg, ins, iargs [0]->inst_c0);
10978                                 type_to_eval_stack_type (cfg, &ins->klass->byval_arg, ins);
10979                                 *sp++= ins;
10980                         } else {
10981                                 *sp++ = alloc;
10982                         }
10983                         
10984                         ip += 5;
10985                         inline_costs += 5;
10986                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip - header->code)))
10987                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
10988                         break;
10989                 }
10990                 case CEE_CASTCLASS:
10991                 case CEE_ISINST: {
10992                         CHECK_STACK (1);
10993                         --sp;
10994                         CHECK_OPSIZE (5);
10995                         token = read32 (ip + 1);
10996                         klass = mini_get_class (method, token, generic_context);
10997                         CHECK_TYPELOAD (klass);
10998                         if (sp [0]->type != STACK_OBJ)
10999                                 UNVERIFIED;
11000
11001                         MONO_INST_NEW (cfg, ins, *ip == CEE_ISINST ? OP_ISINST : OP_CASTCLASS);
11002                         ins->dreg = alloc_preg (cfg);
11003                         ins->sreg1 = (*sp)->dreg;
11004                         ins->klass = klass;
11005                         ins->type = STACK_OBJ;
11006                         MONO_ADD_INS (cfg->cbb, ins);
11007
11008                         CHECK_CFG_EXCEPTION;
11009                         *sp++ = ins;
11010                         ip += 5;
11011
11012                         cfg->flags |= MONO_CFG_HAS_TYPE_CHECK;
11013                         break;
11014                 }
11015                 case CEE_UNBOX_ANY: {
11016                         MonoInst *res, *addr;
11017
11018                         CHECK_STACK (1);
11019                         --sp;
11020                         CHECK_OPSIZE (5);
11021                         token = read32 (ip + 1);
11022                         klass = mini_get_class (method, token, generic_context);
11023                         CHECK_TYPELOAD (klass);
11024
11025                         mono_save_token_info (cfg, image, token, klass);
11026
11027                         context_used = mini_class_check_context_used (cfg, klass);
11028
11029                         if (mini_is_gsharedvt_klass (klass)) {
11030                                 res = handle_unbox_gsharedvt (cfg, klass, *sp);
11031                                 inline_costs += 2;
11032                         } else if (generic_class_is_reference_type (cfg, klass)) {
11033                                 MONO_INST_NEW (cfg, res, OP_CASTCLASS);
11034                                 res->dreg = alloc_preg (cfg);
11035                                 res->sreg1 = (*sp)->dreg;
11036                                 res->klass = klass;
11037                                 res->type = STACK_OBJ;
11038                                 MONO_ADD_INS (cfg->cbb, res);
11039                                 cfg->flags |= MONO_CFG_HAS_TYPE_CHECK;
11040                         } else if (mono_class_is_nullable (klass)) {
11041                                 res = handle_unbox_nullable (cfg, *sp, klass, context_used);
11042                         } else {
11043                                 addr = handle_unbox (cfg, klass, sp, context_used);
11044                                 /* LDOBJ */
11045                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11046                                 res = ins;
11047                                 inline_costs += 2;
11048                         }
11049
11050                         *sp ++ = res;
11051                         ip += 5;
11052                         break;
11053                 }
11054                 case CEE_BOX: {
11055                         MonoInst *val;
11056                         MonoClass *enum_class;
11057                         MonoMethod *has_flag;
11058
11059                         CHECK_STACK (1);
11060                         --sp;
11061                         val = *sp;
11062                         CHECK_OPSIZE (5);
11063                         token = read32 (ip + 1);
11064                         klass = mini_get_class (method, token, generic_context);
11065                         CHECK_TYPELOAD (klass);
11066
11067                         mono_save_token_info (cfg, image, token, klass);
11068
11069                         context_used = mini_class_check_context_used (cfg, klass);
11070
11071                         if (generic_class_is_reference_type (cfg, klass)) {
11072                                 *sp++ = val;
11073                                 ip += 5;
11074                                 break;
11075                         }
11076
11077                         if (klass == mono_defaults.void_class)
11078                                 UNVERIFIED;
11079                         if (target_type_is_incompatible (cfg, &klass->byval_arg, *sp))
11080                                 UNVERIFIED;
11081                         /* frequent check in generic code: box (struct), brtrue */
11082
11083                         /*
11084                          * Look for:
11085                          *
11086                          *   <push int/long ptr>
11087                          *   <push int/long>
11088                          *   box MyFlags
11089                          *   constrained. MyFlags
11090                          *   callvirt instace bool class [mscorlib] System.Enum::HasFlag (class [mscorlib] System.Enum)
11091                          *
11092                          * If we find this sequence and the operand types on box and constrained
11093                          * are equal, we can emit a specialized instruction sequence instead of
11094                          * the very slow HasFlag () call.
11095                          */
11096                         if ((cfg->opt & MONO_OPT_INTRINS) &&
11097                             /* Cheap checks first. */
11098                             ip + 5 + 6 + 5 < end &&
11099                             ip [5] == CEE_PREFIX1 &&
11100                             ip [6] == CEE_CONSTRAINED_ &&
11101                             ip [11] == CEE_CALLVIRT &&
11102                             ip_in_bb (cfg, cfg->cbb, ip + 5 + 6 + 5) &&
11103                             mono_class_is_enum (klass) &&
11104                             (enum_class = mini_get_class (method, read32 (ip + 7), generic_context)) &&
11105                             (has_flag = mini_get_method (cfg, method, read32 (ip + 12), NULL, generic_context)) &&
11106                             has_flag->klass == mono_defaults.enum_class &&
11107                             !strcmp (has_flag->name, "HasFlag") &&
11108                             has_flag->signature->hasthis &&
11109                             has_flag->signature->param_count == 1) {
11110                                 CHECK_TYPELOAD (enum_class);
11111
11112                                 if (enum_class == klass) {
11113                                         MonoInst *enum_this, *enum_flag;
11114
11115                                         ip += 5 + 6 + 5;
11116                                         --sp;
11117
11118                                         enum_this = sp [0];
11119                                         enum_flag = sp [1];
11120
11121                                         *sp++ = handle_enum_has_flag (cfg, klass, enum_this, enum_flag);
11122                                         break;
11123                                 }
11124                         }
11125
11126                         // FIXME: LLVM can't handle the inconsistent bb linking
11127                         if (!mono_class_is_nullable (klass) &&
11128                                 !mini_is_gsharedvt_klass (klass) &&
11129                                 ip + 5 < end && ip_in_bb (cfg, cfg->cbb, ip + 5) &&
11130                                 (ip [5] == CEE_BRTRUE || 
11131                                  ip [5] == CEE_BRTRUE_S ||
11132                                  ip [5] == CEE_BRFALSE ||
11133                                  ip [5] == CEE_BRFALSE_S)) {
11134                                 gboolean is_true = ip [5] == CEE_BRTRUE || ip [5] == CEE_BRTRUE_S;
11135                                 int dreg;
11136                                 MonoBasicBlock *true_bb, *false_bb;
11137
11138                                 ip += 5;
11139
11140                                 if (cfg->verbose_level > 3) {
11141                                         printf ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
11142                                         printf ("<box+brtrue opt>\n");
11143                                 }
11144
11145                                 switch (*ip) {
11146                                 case CEE_BRTRUE_S:
11147                                 case CEE_BRFALSE_S:
11148                                         CHECK_OPSIZE (2);
11149                                         ip++;
11150                                         target = ip + 1 + (signed char)(*ip);
11151                                         ip++;
11152                                         break;
11153                                 case CEE_BRTRUE:
11154                                 case CEE_BRFALSE:
11155                                         CHECK_OPSIZE (5);
11156                                         ip++;
11157                                         target = ip + 4 + (gint)(read32 (ip));
11158                                         ip += 4;
11159                                         break;
11160                                 default:
11161                                         g_assert_not_reached ();
11162                                 }
11163
11164                                 /* 
11165                                  * We need to link both bblocks, since it is needed for handling stack
11166                                  * arguments correctly (See test_0_box_brtrue_opt_regress_81102).
11167                                  * Branching to only one of them would lead to inconsistencies, so
11168                                  * generate an ICONST+BRTRUE, the branch opts will get rid of them.
11169                                  */
11170                                 GET_BBLOCK (cfg, true_bb, target);
11171                                 GET_BBLOCK (cfg, false_bb, ip);
11172
11173                                 mono_link_bblock (cfg, cfg->cbb, true_bb);
11174                                 mono_link_bblock (cfg, cfg->cbb, false_bb);
11175
11176                                 if (sp != stack_start) {
11177                                         handle_stack_args (cfg, stack_start, sp - stack_start);
11178                                         sp = stack_start;
11179                                         CHECK_UNVERIFIABLE (cfg);
11180                                 }
11181
11182                                 if (COMPILE_LLVM (cfg)) {
11183                                         dreg = alloc_ireg (cfg);
11184                                         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
11185                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, dreg, is_true ? 0 : 1);
11186
11187                                         MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, OP_IBEQ, true_bb, false_bb);
11188                                 } else {
11189                                         /* The JIT can't eliminate the iconst+compare */
11190                                         MONO_INST_NEW (cfg, ins, OP_BR);
11191                                         ins->inst_target_bb = is_true ? true_bb : false_bb;
11192                                         MONO_ADD_INS (cfg->cbb, ins);
11193                                 }
11194
11195                                 start_new_bblock = 1;
11196                                 break;
11197                         }
11198
11199                         *sp++ = handle_box (cfg, val, klass, context_used);
11200
11201                         CHECK_CFG_EXCEPTION;
11202                         ip += 5;
11203                         inline_costs += 1;
11204                         break;
11205                 }
11206                 case CEE_UNBOX: {
11207                         CHECK_STACK (1);
11208                         --sp;
11209                         CHECK_OPSIZE (5);
11210                         token = read32 (ip + 1);
11211                         klass = mini_get_class (method, token, generic_context);
11212                         CHECK_TYPELOAD (klass);
11213
11214                         mono_save_token_info (cfg, image, token, klass);
11215
11216                         context_used = mini_class_check_context_used (cfg, klass);
11217
11218                         if (mono_class_is_nullable (klass)) {
11219                                 MonoInst *val;
11220
11221                                 val = handle_unbox_nullable (cfg, *sp, klass, context_used);
11222                                 EMIT_NEW_VARLOADA (cfg, ins, get_vreg_to_inst (cfg, val->dreg), &val->klass->byval_arg);
11223
11224                                 *sp++= ins;
11225                         } else {
11226                                 ins = handle_unbox (cfg, klass, sp, context_used);
11227                                 *sp++ = ins;
11228                         }
11229                         ip += 5;
11230                         inline_costs += 2;
11231                         break;
11232                 }
11233                 case CEE_LDFLD:
11234                 case CEE_LDFLDA:
11235                 case CEE_STFLD:
11236                 case CEE_LDSFLD:
11237                 case CEE_LDSFLDA:
11238                 case CEE_STSFLD: {
11239                         MonoClassField *field;
11240 #ifndef DISABLE_REMOTING
11241                         int costs;
11242 #endif
11243                         guint foffset;
11244                         gboolean is_instance;
11245                         int op;
11246                         gpointer addr = NULL;
11247                         gboolean is_special_static;
11248                         MonoType *ftype;
11249                         MonoInst *store_val = NULL;
11250                         MonoInst *thread_ins;
11251
11252                         op = *ip;
11253                         is_instance = (op == CEE_LDFLD || op == CEE_LDFLDA || op == CEE_STFLD);
11254                         if (is_instance) {
11255                                 if (op == CEE_STFLD) {
11256                                         CHECK_STACK (2);
11257                                         sp -= 2;
11258                                         store_val = sp [1];
11259                                 } else {
11260                                         CHECK_STACK (1);
11261                                         --sp;
11262                                 }
11263                                 if (sp [0]->type == STACK_I4 || sp [0]->type == STACK_I8 || sp [0]->type == STACK_R8)
11264                                         UNVERIFIED;
11265                                 if (*ip != CEE_LDFLD && sp [0]->type == STACK_VTYPE)
11266                                         UNVERIFIED;
11267                         } else {
11268                                 if (op == CEE_STSFLD) {
11269                                         CHECK_STACK (1);
11270                                         sp--;
11271                                         store_val = sp [0];
11272                                 }
11273                         }
11274
11275                         CHECK_OPSIZE (5);
11276                         token = read32 (ip + 1);
11277                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
11278                                 field = (MonoClassField *)mono_method_get_wrapper_data (method, token);
11279                                 klass = field->parent;
11280                         }
11281                         else {
11282                                 field = mono_field_from_token_checked (image, token, &klass, generic_context, &cfg->error);
11283                                 CHECK_CFG_ERROR;
11284                         }
11285                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
11286                                 FIELD_ACCESS_FAILURE (method, field);
11287                         mono_class_init (klass);
11288
11289                         /* if the class is Critical then transparent code cannot access it's fields */
11290                         if (!is_instance && mono_security_core_clr_enabled ())
11291                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
11292
11293                         /* XXX this is technically required but, so far (SL2), no [SecurityCritical] types (not many exists) have
11294                            any visible *instance* field  (in fact there's a single case for a static field in Marshal) XXX
11295                         if (mono_security_core_clr_enabled ())
11296                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
11297                         */
11298
11299                         ftype = mono_field_get_type (field);
11300
11301                         /*
11302                          * LDFLD etc. is usable on static fields as well, so convert those cases to
11303                          * the static case.
11304                          */
11305                         if (is_instance && ftype->attrs & FIELD_ATTRIBUTE_STATIC) {
11306                                 switch (op) {
11307                                 case CEE_LDFLD:
11308                                         op = CEE_LDSFLD;
11309                                         break;
11310                                 case CEE_STFLD:
11311                                         op = CEE_STSFLD;
11312                                         break;
11313                                 case CEE_LDFLDA:
11314                                         op = CEE_LDSFLDA;
11315                                         break;
11316                                 default:
11317                                         g_assert_not_reached ();
11318                                 }
11319                                 is_instance = FALSE;
11320                         }
11321
11322                         context_used = mini_class_check_context_used (cfg, klass);
11323
11324                         /* INSTANCE CASE */
11325
11326                         foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
11327                         if (op == CEE_STFLD) {
11328                                 if (target_type_is_incompatible (cfg, field->type, sp [1]))
11329                                         UNVERIFIED;
11330 #ifndef DISABLE_REMOTING
11331                                 if ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class) {
11332                                         MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type); 
11333                                         MonoInst *iargs [5];
11334
11335                                         GSHAREDVT_FAILURE (op);
11336
11337                                         iargs [0] = sp [0];
11338                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11339                                         EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
11340                                         EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : 
11341                                                     field->offset);
11342                                         iargs [4] = sp [1];
11343
11344                                         if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
11345                                                 costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), 
11346                                                                                            iargs, ip, cfg->real_offset, TRUE);
11347                                                 CHECK_CFG_EXCEPTION;
11348                                                 g_assert (costs > 0);
11349                                                       
11350                                                 cfg->real_offset += 5;
11351
11352                                                 inline_costs += costs;
11353                                         } else {
11354                                                 mono_emit_method_call (cfg, stfld_wrapper, iargs, NULL);
11355                                         }
11356                                 } else
11357 #endif
11358                                 {
11359                                         MonoInst *store, *wbarrier_ptr_ins = NULL;
11360
11361                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
11362
11363                                         if (ins_flag & MONO_INST_VOLATILE) {
11364                                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11365                                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11366                                         }
11367
11368                                         if (mini_is_gsharedvt_klass (klass)) {
11369                                                 MonoInst *offset_ins;
11370
11371                                                 context_used = mini_class_check_context_used (cfg, klass);
11372
11373                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11374                                                 /* The value is offset by 1 */
11375                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
11376                                                 dreg = alloc_ireg_mp (cfg);
11377                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11378                                                 wbarrier_ptr_ins = ins;
11379                                                 /* The decomposition will call mini_emit_stobj () which will emit a wbarrier if needed */
11380                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, dreg, 0, sp [1]->dreg);
11381                                         } else {
11382                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, sp [0]->dreg, foffset, sp [1]->dreg);
11383                                         }
11384                                         if (sp [0]->opcode != OP_LDADDR)
11385                                                 store->flags |= MONO_INST_FAULT;
11386
11387                                         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)) {
11388                                                 if (mini_is_gsharedvt_klass (klass)) {
11389                                                         g_assert (wbarrier_ptr_ins);
11390                                                         emit_write_barrier (cfg, wbarrier_ptr_ins, sp [1]);
11391                                                 } else {
11392                                                         /* insert call to write barrier */
11393                                                         MonoInst *ptr;
11394                                                         int dreg;
11395
11396                                                         dreg = alloc_ireg_mp (cfg);
11397                                                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
11398                                                         emit_write_barrier (cfg, ptr, sp [1]);
11399                                                 }
11400                                         }
11401
11402                                         store->flags |= ins_flag;
11403                                 }
11404                                 ins_flag = 0;
11405                                 ip += 5;
11406                                 break;
11407                         }
11408
11409 #ifndef DISABLE_REMOTING
11410                         if (is_instance && ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class)) {
11411                                 MonoMethod *wrapper = (op == CEE_LDFLDA) ? mono_marshal_get_ldflda_wrapper (field->type) : mono_marshal_get_ldfld_wrapper (field->type); 
11412                                 MonoInst *iargs [4];
11413
11414                                 GSHAREDVT_FAILURE (op);
11415
11416                                 iargs [0] = sp [0];
11417                                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11418                                 EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
11419                                 EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
11420                                 if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
11421                                         costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), 
11422                                                                                    iargs, ip, cfg->real_offset, TRUE);
11423                                         CHECK_CFG_EXCEPTION;
11424                                         g_assert (costs > 0);
11425                                                       
11426                                         cfg->real_offset += 5;
11427
11428                                         *sp++ = iargs [0];
11429
11430                                         inline_costs += costs;
11431                                 } else {
11432                                         ins = mono_emit_method_call (cfg, wrapper, iargs, NULL);
11433                                         *sp++ = ins;
11434                                 }
11435                         } else 
11436 #endif
11437                         if (is_instance) {
11438                                 if (sp [0]->type == STACK_VTYPE) {
11439                                         MonoInst *var;
11440
11441                                         /* Have to compute the address of the variable */
11442
11443                                         var = get_vreg_to_inst (cfg, sp [0]->dreg);
11444                                         if (!var)
11445                                                 var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, sp [0]->dreg);
11446                                         else
11447                                                 g_assert (var->klass == klass);
11448                                         
11449                                         EMIT_NEW_VARLOADA (cfg, ins, var, &var->klass->byval_arg);
11450                                         sp [0] = ins;
11451                                 }
11452
11453                                 if (op == CEE_LDFLDA) {
11454                                         if (sp [0]->type == STACK_OBJ) {
11455                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
11456                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "NullReferenceException");
11457                                         }
11458
11459                                         dreg = alloc_ireg_mp (cfg);
11460
11461                                         if (mini_is_gsharedvt_klass (klass)) {
11462                                                 MonoInst *offset_ins;
11463
11464                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11465                                                 /* The value is offset by 1 */
11466                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
11467                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11468                                         } else {
11469                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
11470                                         }
11471                                         ins->klass = mono_class_from_mono_type (field->type);
11472                                         ins->type = STACK_MP;
11473                                         *sp++ = ins;
11474                                 } else {
11475                                         MonoInst *load;
11476
11477                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
11478
11479                                         if (mini_is_gsharedvt_klass (klass)) {
11480                                                 MonoInst *offset_ins;
11481
11482                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11483                                                 /* The value is offset by 1 */
11484                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
11485                                                 dreg = alloc_ireg_mp (cfg);
11486                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11487                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, dreg, 0);
11488                                         } else {
11489                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, sp [0]->dreg, foffset);
11490                                         }
11491                                         load->flags |= ins_flag;
11492                                         if (sp [0]->opcode != OP_LDADDR)
11493                                                 load->flags |= MONO_INST_FAULT;
11494                                         *sp++ = load;
11495                                 }
11496                         }
11497
11498                         if (is_instance) {
11499                                 ins_flag = 0;
11500                                 ip += 5;
11501                                 break;
11502                         }
11503
11504                         /* STATIC CASE */
11505                         context_used = mini_class_check_context_used (cfg, klass);
11506
11507                         if (ftype->attrs & FIELD_ATTRIBUTE_LITERAL) {
11508                                 mono_error_set_field_load (&cfg->error, field->parent, field->name, "Using static instructions with literal field");
11509                                 CHECK_CFG_ERROR;
11510                         }
11511
11512                         /* The special_static_fields field is init'd in mono_class_vtable, so it needs
11513                          * to be called here.
11514                          */
11515                         if (!context_used && !(cfg->opt & MONO_OPT_SHARED)) {
11516                                 mono_class_vtable (cfg->domain, klass);
11517                                 CHECK_TYPELOAD (klass);
11518                         }
11519                         mono_domain_lock (cfg->domain);
11520                         if (cfg->domain->special_static_fields)
11521                                 addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
11522                         mono_domain_unlock (cfg->domain);
11523
11524                         is_special_static = mono_class_field_is_special_static (field);
11525
11526                         if (is_special_static && ((gsize)addr & 0x80000000) == 0)
11527                                 thread_ins = mono_get_thread_intrinsic (cfg);
11528                         else
11529                                 thread_ins = NULL;
11530
11531                         /* Generate IR to compute the field address */
11532                         if (is_special_static && ((gsize)addr & 0x80000000) == 0 && thread_ins && !(cfg->opt & MONO_OPT_SHARED) && !context_used) {
11533                                 /*
11534                                  * Fast access to TLS data
11535                                  * Inline version of get_thread_static_data () in
11536                                  * threads.c.
11537                                  */
11538                                 guint32 offset;
11539                                 int idx, static_data_reg, array_reg, dreg;
11540
11541                                 GSHAREDVT_FAILURE (op);
11542
11543                                 MONO_ADD_INS (cfg->cbb, thread_ins);
11544                                 static_data_reg = alloc_ireg (cfg);
11545                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, MONO_STRUCT_OFFSET (MonoInternalThread, static_data));
11546
11547                                 if (cfg->compile_aot) {
11548                                         int offset_reg, offset2_reg, idx_reg;
11549
11550                                         /* For TLS variables, this will return the TLS offset */
11551                                         EMIT_NEW_SFLDACONST (cfg, ins, field);
11552                                         offset_reg = ins->dreg;
11553                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset_reg, offset_reg, 0x7fffffff);
11554                                         idx_reg = alloc_ireg (cfg);
11555                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, idx_reg, offset_reg, 0x3f);
11556                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
11557                                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
11558                                         array_reg = alloc_ireg (cfg);
11559                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
11560                                         offset2_reg = alloc_ireg (cfg);
11561                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, offset2_reg, offset_reg, 6);
11562                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset2_reg, 0x1ffffff);
11563                                         dreg = alloc_ireg (cfg);
11564                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, array_reg, offset2_reg);
11565                                 } else {
11566                                         offset = (gsize)addr & 0x7fffffff;
11567                                         idx = offset & 0x3f;
11568
11569                                         array_reg = alloc_ireg (cfg);
11570                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, idx * sizeof (gpointer));
11571                                         dreg = alloc_ireg (cfg);
11572                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_ADD_IMM, dreg, array_reg, ((offset >> 6) & 0x1ffffff));
11573                                 }
11574                         } else if ((cfg->opt & MONO_OPT_SHARED) ||
11575                                         (cfg->compile_aot && is_special_static) ||
11576                                         (context_used && is_special_static)) {
11577                                 MonoInst *iargs [2];
11578
11579                                 g_assert (field->parent);
11580                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11581                                 if (context_used) {
11582                                         iargs [1] = emit_get_rgctx_field (cfg, context_used,
11583                                                 field, MONO_RGCTX_INFO_CLASS_FIELD);
11584                                 } else {
11585                                         EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
11586                                 }
11587                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
11588                         } else if (context_used) {
11589                                 MonoInst *static_data;
11590
11591                                 /*
11592                                 g_print ("sharing static field access in %s.%s.%s - depth %d offset %d\n",
11593                                         method->klass->name_space, method->klass->name, method->name,
11594                                         depth, field->offset);
11595                                 */
11596
11597                                 if (mono_class_needs_cctor_run (klass, method))
11598                                         emit_class_init (cfg, klass);
11599
11600                                 /*
11601                                  * The pointer we're computing here is
11602                                  *
11603                                  *   super_info.static_data + field->offset
11604                                  */
11605                                 static_data = emit_get_rgctx_klass (cfg, context_used,
11606                                         klass, MONO_RGCTX_INFO_STATIC_DATA);
11607
11608                                 if (mini_is_gsharedvt_klass (klass)) {
11609                                         MonoInst *offset_ins;
11610
11611                                         offset_ins = emit_get_rgctx_field (cfg, context_used, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11612                                         /* The value is offset by 1 */
11613                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
11614                                         dreg = alloc_ireg_mp (cfg);
11615                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, static_data->dreg, offset_ins->dreg);
11616                                 } else if (field->offset == 0) {
11617                                         ins = static_data;
11618                                 } else {
11619                                         int addr_reg = mono_alloc_preg (cfg);
11620                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, addr_reg, static_data->dreg, field->offset);
11621                                 }
11622                                 } else if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
11623                                 MonoInst *iargs [2];
11624
11625                                 g_assert (field->parent);
11626                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11627                                 EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
11628                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
11629                         } else {
11630                                 MonoVTable *vtable = NULL;
11631
11632                                 if (!cfg->compile_aot)
11633                                         vtable = mono_class_vtable (cfg->domain, klass);
11634                                 CHECK_TYPELOAD (klass);
11635
11636                                 if (!addr) {
11637                                         if (mini_field_access_needs_cctor_run (cfg, method, klass, vtable)) {
11638                                                 if (!(g_slist_find (class_inits, klass))) {
11639                                                         emit_class_init (cfg, klass);
11640                                                         if (cfg->verbose_level > 2)
11641                                                                 printf ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, mono_field_get_name (field));
11642                                                         class_inits = g_slist_prepend (class_inits, klass);
11643                                                 }
11644                                         } else {
11645                                                 if (cfg->run_cctors) {
11646                                                         /* This makes so that inline cannot trigger */
11647                                                         /* .cctors: too many apps depend on them */
11648                                                         /* running with a specific order... */
11649                                                         g_assert (vtable);
11650                                                         if (! vtable->initialized)
11651                                                                 INLINE_FAILURE ("class init");
11652                                                         if (!mono_runtime_class_init_full (vtable, &cfg->error)) {
11653                                                                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
11654                                                                 goto exception_exit;
11655                                                         }
11656                                                 }
11657                                         }
11658                                         if (cfg->compile_aot)
11659                                                 EMIT_NEW_SFLDACONST (cfg, ins, field);
11660                                         else {
11661                                                 g_assert (vtable);
11662                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11663                                                 g_assert (addr);
11664                                                 EMIT_NEW_PCONST (cfg, ins, addr);
11665                                         }
11666                                 } else {
11667                                         MonoInst *iargs [1];
11668                                         EMIT_NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
11669                                         ins = mono_emit_jit_icall (cfg, mono_get_special_static_data, iargs);
11670                                 }
11671                         }
11672
11673                         /* Generate IR to do the actual load/store operation */
11674
11675                         if ((op == CEE_STFLD || op == CEE_STSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11676                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11677                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11678                         }
11679
11680                         if (op == CEE_LDSFLDA) {
11681                                 ins->klass = mono_class_from_mono_type (ftype);
11682                                 ins->type = STACK_PTR;
11683                                 *sp++ = ins;
11684                         } else if (op == CEE_STSFLD) {
11685                                 MonoInst *store;
11686
11687                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, ftype, ins->dreg, 0, store_val->dreg);
11688                                 store->flags |= ins_flag;
11689                         } else {
11690                                 gboolean is_const = FALSE;
11691                                 MonoVTable *vtable = NULL;
11692                                 gpointer addr = NULL;
11693
11694                                 if (!context_used) {
11695                                         vtable = mono_class_vtable (cfg->domain, klass);
11696                                         CHECK_TYPELOAD (klass);
11697                                 }
11698                                 if ((ftype->attrs & FIELD_ATTRIBUTE_INIT_ONLY) && (((addr = mono_aot_readonly_field_override (field)) != NULL) ||
11699                                                 (!context_used && !((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && vtable->initialized))) {
11700                                         int ro_type = ftype->type;
11701                                         if (!addr)
11702                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11703                                         if (ro_type == MONO_TYPE_VALUETYPE && ftype->data.klass->enumtype) {
11704                                                 ro_type = mono_class_enum_basetype (ftype->data.klass)->type;
11705                                         }
11706
11707                                         GSHAREDVT_FAILURE (op);
11708
11709                                         /* printf ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, mono_field_get_name (field));*/
11710                                         is_const = TRUE;
11711                                         switch (ro_type) {
11712                                         case MONO_TYPE_BOOLEAN:
11713                                         case MONO_TYPE_U1:
11714                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint8 *)addr));
11715                                                 sp++;
11716                                                 break;
11717                                         case MONO_TYPE_I1:
11718                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint8 *)addr));
11719                                                 sp++;
11720                                                 break;                                          
11721                                         case MONO_TYPE_CHAR:
11722                                         case MONO_TYPE_U2:
11723                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint16 *)addr));
11724                                                 sp++;
11725                                                 break;
11726                                         case MONO_TYPE_I2:
11727                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint16 *)addr));
11728                                                 sp++;
11729                                                 break;
11730                                                 break;
11731                                         case MONO_TYPE_I4:
11732                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint32 *)addr));
11733                                                 sp++;
11734                                                 break;                                          
11735                                         case MONO_TYPE_U4:
11736                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint32 *)addr));
11737                                                 sp++;
11738                                                 break;
11739                                         case MONO_TYPE_I:
11740                                         case MONO_TYPE_U:
11741                                         case MONO_TYPE_PTR:
11742                                         case MONO_TYPE_FNPTR:
11743                                                 EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11744                                                 type_to_eval_stack_type ((cfg), field->type, *sp);
11745                                                 sp++;
11746                                                 break;
11747                                         case MONO_TYPE_STRING:
11748                                         case MONO_TYPE_OBJECT:
11749                                         case MONO_TYPE_CLASS:
11750                                         case MONO_TYPE_SZARRAY:
11751                                         case MONO_TYPE_ARRAY:
11752                                                 if (!mono_gc_is_moving ()) {
11753                                                         EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11754                                                         type_to_eval_stack_type ((cfg), field->type, *sp);
11755                                                         sp++;
11756                                                 } else {
11757                                                         is_const = FALSE;
11758                                                 }
11759                                                 break;
11760                                         case MONO_TYPE_I8:
11761                                         case MONO_TYPE_U8:
11762                                                 EMIT_NEW_I8CONST (cfg, *sp, *((gint64 *)addr));
11763                                                 sp++;
11764                                                 break;
11765                                         case MONO_TYPE_R4:
11766                                         case MONO_TYPE_R8:
11767                                         case MONO_TYPE_VALUETYPE:
11768                                         default:
11769                                                 is_const = FALSE;
11770                                                 break;
11771                                         }
11772                                 }
11773
11774                                 if (!is_const) {
11775                                         MonoInst *load;
11776
11777                                         CHECK_STACK_OVF (1);
11778
11779                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, ins->dreg, 0);
11780                                         load->flags |= ins_flag;
11781                                         ins_flag = 0;
11782                                         *sp++ = load;
11783                                 }
11784                         }
11785
11786                         if ((op == CEE_LDFLD || op == CEE_LDSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11787                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
11788                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
11789                         }
11790
11791                         ins_flag = 0;
11792                         ip += 5;
11793                         break;
11794                 }
11795                 case CEE_STOBJ:
11796                         CHECK_STACK (2);
11797                         sp -= 2;
11798                         CHECK_OPSIZE (5);
11799                         token = read32 (ip + 1);
11800                         klass = mini_get_class (method, token, generic_context);
11801                         CHECK_TYPELOAD (klass);
11802                         if (ins_flag & MONO_INST_VOLATILE) {
11803                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11804                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11805                         }
11806                         /* FIXME: should check item at sp [1] is compatible with the type of the store. */
11807                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0, sp [1]->dreg);
11808                         ins->flags |= ins_flag;
11809                         if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER &&
11810                                         generic_class_is_reference_type (cfg, klass)) {
11811                                 /* insert call to write barrier */
11812                                 emit_write_barrier (cfg, sp [0], sp [1]);
11813                         }
11814                         ins_flag = 0;
11815                         ip += 5;
11816                         inline_costs += 1;
11817                         break;
11818
11819                         /*
11820                          * Array opcodes
11821                          */
11822                 case CEE_NEWARR: {
11823                         MonoInst *len_ins;
11824                         const char *data_ptr;
11825                         int data_size = 0;
11826                         guint32 field_token;
11827
11828                         CHECK_STACK (1);
11829                         --sp;
11830
11831                         CHECK_OPSIZE (5);
11832                         token = read32 (ip + 1);
11833
11834                         klass = mini_get_class (method, token, generic_context);
11835                         CHECK_TYPELOAD (klass);
11836
11837                         context_used = mini_class_check_context_used (cfg, klass);
11838
11839                         if (sp [0]->type == STACK_I8 || (SIZEOF_VOID_P == 8 && sp [0]->type == STACK_PTR)) {
11840                                 MONO_INST_NEW (cfg, ins, OP_LCONV_TO_OVF_U4);
11841                                 ins->sreg1 = sp [0]->dreg;
11842                                 ins->type = STACK_I4;
11843                                 ins->dreg = alloc_ireg (cfg);
11844                                 MONO_ADD_INS (cfg->cbb, ins);
11845                                 *sp = mono_decompose_opcode (cfg, ins);
11846                         }
11847
11848                         if (context_used) {
11849                                 MonoInst *args [3];
11850                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11851                                 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
11852
11853                                 /* FIXME: Use OP_NEWARR and decompose later to help abcrem */
11854
11855                                 /* vtable */
11856                                 args [0] = emit_get_rgctx_klass (cfg, context_used,
11857                                         array_class, MONO_RGCTX_INFO_VTABLE);
11858                                 /* array len */
11859                                 args [1] = sp [0];
11860
11861                                 if (managed_alloc)
11862                                         ins = mono_emit_method_call (cfg, managed_alloc, args, NULL);
11863                                 else
11864                                         ins = mono_emit_jit_icall (cfg, ves_icall_array_new_specific, args);
11865                         } else {
11866                                 if (cfg->opt & MONO_OPT_SHARED) {
11867                                         /* Decompose now to avoid problems with references to the domainvar */
11868                                         MonoInst *iargs [3];
11869
11870                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11871                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11872                                         iargs [2] = sp [0];
11873
11874                                         ins = mono_emit_jit_icall (cfg, ves_icall_array_new, iargs);
11875                                 } else {
11876                                         /* Decompose later since it is needed by abcrem */
11877                                         MonoClass *array_type = mono_array_class_get (klass, 1);
11878                                         mono_class_vtable (cfg->domain, array_type);
11879                                         CHECK_TYPELOAD (array_type);
11880
11881                                         MONO_INST_NEW (cfg, ins, OP_NEWARR);
11882                                         ins->dreg = alloc_ireg_ref (cfg);
11883                                         ins->sreg1 = sp [0]->dreg;
11884                                         ins->inst_newa_class = klass;
11885                                         ins->type = STACK_OBJ;
11886                                         ins->klass = array_type;
11887                                         MONO_ADD_INS (cfg->cbb, ins);
11888                                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11889                                         cfg->cbb->has_array_access = TRUE;
11890
11891                                         /* Needed so mono_emit_load_get_addr () gets called */
11892                                         mono_get_got_var (cfg);
11893                                 }
11894                         }
11895
11896                         len_ins = sp [0];
11897                         ip += 5;
11898                         *sp++ = ins;
11899                         inline_costs += 1;
11900
11901                         /* 
11902                          * we inline/optimize the initialization sequence if possible.
11903                          * we should also allocate the array as not cleared, since we spend as much time clearing to 0 as initializing
11904                          * for small sizes open code the memcpy
11905                          * ensure the rva field is big enough
11906                          */
11907                         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))) {
11908                                 MonoMethod *memcpy_method = get_memcpy_method ();
11909                                 MonoInst *iargs [3];
11910                                 int add_reg = alloc_ireg_mp (cfg);
11911
11912                                 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, add_reg, ins->dreg, MONO_STRUCT_OFFSET (MonoArray, vector));
11913                                 if (cfg->compile_aot) {
11914                                         EMIT_NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(field_token), STACK_PTR, NULL);
11915                                 } else {
11916                                         EMIT_NEW_PCONST (cfg, iargs [1], (char*)data_ptr);
11917                                 }
11918                                 EMIT_NEW_ICONST (cfg, iargs [2], data_size);
11919                                 mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
11920                                 ip += 11;
11921                         }
11922
11923                         break;
11924                 }
11925                 case CEE_LDLEN:
11926                         CHECK_STACK (1);
11927                         --sp;
11928                         if (sp [0]->type != STACK_OBJ)
11929                                 UNVERIFIED;
11930
11931                         MONO_INST_NEW (cfg, ins, OP_LDLEN);
11932                         ins->dreg = alloc_preg (cfg);
11933                         ins->sreg1 = sp [0]->dreg;
11934                         ins->type = STACK_I4;
11935                         /* This flag will be inherited by the decomposition */
11936                         ins->flags |= MONO_INST_FAULT;
11937                         MONO_ADD_INS (cfg->cbb, ins);
11938                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11939                         cfg->cbb->has_array_access = TRUE;
11940                         ip ++;
11941                         *sp++ = ins;
11942                         break;
11943                 case CEE_LDELEMA:
11944                         CHECK_STACK (2);
11945                         sp -= 2;
11946                         CHECK_OPSIZE (5);
11947                         if (sp [0]->type != STACK_OBJ)
11948                                 UNVERIFIED;
11949
11950                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11951
11952                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11953                         CHECK_TYPELOAD (klass);
11954                         /* we need to make sure that this array is exactly the type it needs
11955                          * to be for correctness. the wrappers are lax with their usage
11956                          * so we need to ignore them here
11957                          */
11958                         if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE && !readonly) {
11959                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11960                                 mini_emit_check_array_type (cfg, sp [0], array_class);
11961                                 CHECK_TYPELOAD (array_class);
11962                         }
11963
11964                         readonly = FALSE;
11965                         ins = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11966                         *sp++ = ins;
11967                         ip += 5;
11968                         break;
11969                 case CEE_LDELEM:
11970                 case CEE_LDELEM_I1:
11971                 case CEE_LDELEM_U1:
11972                 case CEE_LDELEM_I2:
11973                 case CEE_LDELEM_U2:
11974                 case CEE_LDELEM_I4:
11975                 case CEE_LDELEM_U4:
11976                 case CEE_LDELEM_I8:
11977                 case CEE_LDELEM_I:
11978                 case CEE_LDELEM_R4:
11979                 case CEE_LDELEM_R8:
11980                 case CEE_LDELEM_REF: {
11981                         MonoInst *addr;
11982
11983                         CHECK_STACK (2);
11984                         sp -= 2;
11985
11986                         if (*ip == CEE_LDELEM) {
11987                                 CHECK_OPSIZE (5);
11988                                 token = read32 (ip + 1);
11989                                 klass = mini_get_class (method, token, generic_context);
11990                                 CHECK_TYPELOAD (klass);
11991                                 mono_class_init (klass);
11992                         }
11993                         else
11994                                 klass = array_access_to_klass (*ip);
11995
11996                         if (sp [0]->type != STACK_OBJ)
11997                                 UNVERIFIED;
11998
11999                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
12000
12001                         if (mini_is_gsharedvt_variable_klass (klass)) {
12002                                 // FIXME-VT: OP_ICONST optimization
12003                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
12004                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
12005                                 ins->opcode = OP_LOADV_MEMBASE;
12006                         } else if (sp [1]->opcode == OP_ICONST) {
12007                                 int array_reg = sp [0]->dreg;
12008                                 int index_reg = sp [1]->dreg;
12009                                 int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
12010
12011                                 if (SIZEOF_REGISTER == 8 && COMPILE_LLVM (cfg))
12012                                         MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, index_reg, index_reg);
12013
12014                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
12015                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset);
12016                         } else {
12017                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
12018                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
12019                         }
12020                         *sp++ = ins;
12021                         if (*ip == CEE_LDELEM)
12022                                 ip += 5;
12023                         else
12024                                 ++ip;
12025                         break;
12026                 }
12027                 case CEE_STELEM_I:
12028                 case CEE_STELEM_I1:
12029                 case CEE_STELEM_I2:
12030                 case CEE_STELEM_I4:
12031                 case CEE_STELEM_I8:
12032                 case CEE_STELEM_R4:
12033                 case CEE_STELEM_R8:
12034                 case CEE_STELEM_REF:
12035                 case CEE_STELEM: {
12036                         CHECK_STACK (3);
12037                         sp -= 3;
12038
12039                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
12040
12041                         if (*ip == CEE_STELEM) {
12042                                 CHECK_OPSIZE (5);
12043                                 token = read32 (ip + 1);
12044                                 klass = mini_get_class (method, token, generic_context);
12045                                 CHECK_TYPELOAD (klass);
12046                                 mono_class_init (klass);
12047                         }
12048                         else
12049                                 klass = array_access_to_klass (*ip);
12050
12051                         if (sp [0]->type != STACK_OBJ)
12052                                 UNVERIFIED;
12053
12054                         emit_array_store (cfg, klass, sp, TRUE);
12055
12056                         if (*ip == CEE_STELEM)
12057                                 ip += 5;
12058                         else
12059                                 ++ip;
12060                         inline_costs += 1;
12061                         break;
12062                 }
12063                 case CEE_CKFINITE: {
12064                         CHECK_STACK (1);
12065                         --sp;
12066
12067                         if (cfg->llvm_only) {
12068                                 MonoInst *iargs [1];
12069
12070                                 iargs [0] = sp [0];
12071                                 *sp++ = mono_emit_jit_icall (cfg, mono_ckfinite, iargs);
12072                         } else  {
12073                                 MONO_INST_NEW (cfg, ins, OP_CKFINITE);
12074                                 ins->sreg1 = sp [0]->dreg;
12075                                 ins->dreg = alloc_freg (cfg);
12076                                 ins->type = STACK_R8;
12077                                 MONO_ADD_INS (cfg->cbb, ins);
12078
12079                                 *sp++ = mono_decompose_opcode (cfg, ins);
12080                         }
12081
12082                         ++ip;
12083                         break;
12084                 }
12085                 case CEE_REFANYVAL: {
12086                         MonoInst *src_var, *src;
12087
12088                         int klass_reg = alloc_preg (cfg);
12089                         int dreg = alloc_preg (cfg);
12090
12091                         GSHAREDVT_FAILURE (*ip);
12092
12093                         CHECK_STACK (1);
12094                         MONO_INST_NEW (cfg, ins, *ip);
12095                         --sp;
12096                         CHECK_OPSIZE (5);
12097                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
12098                         CHECK_TYPELOAD (klass);
12099
12100                         context_used = mini_class_check_context_used (cfg, klass);
12101
12102                         // FIXME:
12103                         src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
12104                         if (!src_var)
12105                                 src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
12106                         EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
12107                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass));
12108
12109                         if (context_used) {
12110                                 MonoInst *klass_ins;
12111
12112                                 klass_ins = emit_get_rgctx_klass (cfg, context_used,
12113                                                 klass, MONO_RGCTX_INFO_KLASS);
12114
12115                                 // FIXME:
12116                                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_ins->dreg);
12117                                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
12118                         } else {
12119                                 mini_emit_class_check (cfg, klass_reg, klass);
12120                         }
12121                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value));
12122                         ins->type = STACK_MP;
12123                         ins->klass = klass;
12124                         *sp++ = ins;
12125                         ip += 5;
12126                         break;
12127                 }
12128                 case CEE_MKREFANY: {
12129                         MonoInst *loc, *addr;
12130
12131                         GSHAREDVT_FAILURE (*ip);
12132
12133                         CHECK_STACK (1);
12134                         MONO_INST_NEW (cfg, ins, *ip);
12135                         --sp;
12136                         CHECK_OPSIZE (5);
12137                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
12138                         CHECK_TYPELOAD (klass);
12139
12140                         context_used = mini_class_check_context_used (cfg, klass);
12141
12142                         loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
12143                         EMIT_NEW_TEMPLOADA (cfg, addr, loc->inst_c0);
12144
12145                         if (context_used) {
12146                                 MonoInst *const_ins;
12147                                 int type_reg = alloc_preg (cfg);
12148
12149                                 const_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
12150                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_ins->dreg);
12151                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_ins->dreg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
12152                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
12153                         } else if (cfg->compile_aot) {
12154                                 int const_reg = alloc_preg (cfg);
12155                                 int type_reg = alloc_preg (cfg);
12156
12157                                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
12158                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_reg);
12159                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_reg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
12160                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
12161                         } else {
12162                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), &klass->byval_arg);
12163                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), klass);
12164                         }
12165                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value), sp [0]->dreg);
12166
12167                         EMIT_NEW_TEMPLOAD (cfg, ins, loc->inst_c0);
12168                         ins->type = STACK_VTYPE;
12169                         ins->klass = mono_defaults.typed_reference_class;
12170                         *sp++ = ins;
12171                         ip += 5;
12172                         break;
12173                 }
12174                 case CEE_LDTOKEN: {
12175                         gpointer handle;
12176                         MonoClass *handle_class;
12177
12178                         CHECK_STACK_OVF (1);
12179
12180                         CHECK_OPSIZE (5);
12181                         n = read32 (ip + 1);
12182
12183                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD ||
12184                                         method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
12185                                 handle = mono_method_get_wrapper_data (method, n);
12186                                 handle_class = (MonoClass *)mono_method_get_wrapper_data (method, n + 1);
12187                                 if (handle_class == mono_defaults.typehandle_class)
12188                                         handle = &((MonoClass*)handle)->byval_arg;
12189                         }
12190                         else {
12191                                 handle = mono_ldtoken_checked (image, n, &handle_class, generic_context, &cfg->error);
12192                                 CHECK_CFG_ERROR;
12193                         }
12194                         if (!handle)
12195                                 LOAD_ERROR;
12196                         mono_class_init (handle_class);
12197                         if (cfg->gshared) {
12198                                 if (mono_metadata_token_table (n) == MONO_TABLE_TYPEDEF ||
12199                                                 mono_metadata_token_table (n) == MONO_TABLE_TYPEREF) {
12200                                         /* This case handles ldtoken
12201                                            of an open type, like for
12202                                            typeof(Gen<>). */
12203                                         context_used = 0;
12204                                 } else if (handle_class == mono_defaults.typehandle_class) {
12205                                         context_used = mini_class_check_context_used (cfg, mono_class_from_mono_type ((MonoType *)handle));
12206                                 } else if (handle_class == mono_defaults.fieldhandle_class)
12207                                         context_used = mini_class_check_context_used (cfg, ((MonoClassField*)handle)->parent);
12208                                 else if (handle_class == mono_defaults.methodhandle_class)
12209                                         context_used = mini_method_check_context_used (cfg, (MonoMethod *)handle);
12210                                 else
12211                                         g_assert_not_reached ();
12212                         }
12213
12214                         if ((cfg->opt & MONO_OPT_SHARED) &&
12215                                         method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD &&
12216                                         method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED) {
12217                                 MonoInst *addr, *vtvar, *iargs [3];
12218                                 int method_context_used;
12219
12220                                 method_context_used = mini_method_check_context_used (cfg, method);
12221
12222                                 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL); 
12223
12224                                 EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
12225                                 EMIT_NEW_ICONST (cfg, iargs [1], n);
12226                                 if (method_context_used) {
12227                                         iargs [2] = emit_get_rgctx_method (cfg, method_context_used,
12228                                                 method, MONO_RGCTX_INFO_METHOD);
12229                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper_generic_shared, iargs);
12230                                 } else {
12231                                         EMIT_NEW_PCONST (cfg, iargs [2], generic_context);
12232                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper, iargs);
12233                                 }
12234                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
12235
12236                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
12237
12238                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
12239                         } else {
12240                                 if ((ip + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 5) && 
12241                                         ((ip [5] == CEE_CALL) || (ip [5] == CEE_CALLVIRT)) && 
12242                                         (cmethod = mini_get_method (cfg, method, read32 (ip + 6), NULL, generic_context)) &&
12243                                         (cmethod->klass == mono_defaults.systemtype_class) &&
12244                                         (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
12245                                         MonoClass *tclass = mono_class_from_mono_type ((MonoType *)handle);
12246
12247                                         mono_class_init (tclass);
12248                                         if (context_used) {
12249                                                 ins = emit_get_rgctx_klass (cfg, context_used,
12250                                                         tclass, MONO_RGCTX_INFO_REFLECTION_TYPE);
12251                                         } else if (cfg->compile_aot) {
12252                                                 if (method->wrapper_type) {
12253                                                         mono_error_init (&error); //got to do it since there are multiple conditionals below
12254                                                         if (mono_class_get_checked (tclass->image, tclass->type_token, &error) == tclass && !generic_context) {
12255                                                                 /* Special case for static synchronized wrappers */
12256                                                                 EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, tclass->image, tclass->type_token, generic_context);
12257                                                         } else {
12258                                                                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
12259                                                                 /* FIXME: n is not a normal token */
12260                                                                 DISABLE_AOT (cfg);
12261                                                                 EMIT_NEW_PCONST (cfg, ins, NULL);
12262                                                         }
12263                                                 } else {
12264                                                         EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n, generic_context);
12265                                                 }
12266                                         } else {
12267                                                 MonoReflectionType *rt = mono_type_get_object_checked (cfg->domain, (MonoType *)handle, &cfg->error);
12268                                                 CHECK_CFG_ERROR;
12269                                                 EMIT_NEW_PCONST (cfg, ins, rt);
12270                                         }
12271                                         ins->type = STACK_OBJ;
12272                                         ins->klass = cmethod->klass;
12273                                         ip += 5;
12274                                 } else {
12275                                         MonoInst *addr, *vtvar;
12276
12277                                         vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
12278
12279                                         if (context_used) {
12280                                                 if (handle_class == mono_defaults.typehandle_class) {
12281                                                         ins = emit_get_rgctx_klass (cfg, context_used,
12282                                                                         mono_class_from_mono_type ((MonoType *)handle),
12283                                                                         MONO_RGCTX_INFO_TYPE);
12284                                                 } else if (handle_class == mono_defaults.methodhandle_class) {
12285                                                         ins = emit_get_rgctx_method (cfg, context_used,
12286                                                                         (MonoMethod *)handle, MONO_RGCTX_INFO_METHOD);
12287                                                 } else if (handle_class == mono_defaults.fieldhandle_class) {
12288                                                         ins = emit_get_rgctx_field (cfg, context_used,
12289                                                                         (MonoClassField *)handle, MONO_RGCTX_INFO_CLASS_FIELD);
12290                                                 } else {
12291                                                         g_assert_not_reached ();
12292                                                 }
12293                                         } else if (cfg->compile_aot) {
12294                                                 EMIT_NEW_LDTOKENCONST (cfg, ins, image, n, generic_context);
12295                                         } else {
12296                                                 EMIT_NEW_PCONST (cfg, ins, handle);
12297                                         }
12298                                         EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
12299                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
12300                                         EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
12301                                 }
12302                         }
12303
12304                         *sp++ = ins;
12305                         ip += 5;
12306                         break;
12307                 }
12308                 case CEE_THROW:
12309                         CHECK_STACK (1);
12310                         if (sp [-1]->type != STACK_OBJ)
12311                                 UNVERIFIED;
12312
12313                         MONO_INST_NEW (cfg, ins, OP_THROW);
12314                         --sp;
12315                         ins->sreg1 = sp [0]->dreg;
12316                         ip++;
12317                         cfg->cbb->out_of_line = TRUE;
12318                         MONO_ADD_INS (cfg->cbb, ins);
12319                         MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
12320                         MONO_ADD_INS (cfg->cbb, ins);
12321                         sp = stack_start;
12322                         
12323                         link_bblock (cfg, cfg->cbb, end_bblock);
12324                         start_new_bblock = 1;
12325                         /* This can complicate code generation for llvm since the return value might not be defined */
12326                         if (COMPILE_LLVM (cfg))
12327                                 INLINE_FAILURE ("throw");
12328                         break;
12329                 case CEE_ENDFINALLY:
12330                         if (!ip_in_finally_clause (cfg, ip - header->code))
12331                                 UNVERIFIED;
12332                         /* mono_save_seq_point_info () depends on this */
12333                         if (sp != stack_start)
12334                                 emit_seq_point (cfg, method, ip, FALSE, FALSE);
12335                         MONO_INST_NEW (cfg, ins, OP_ENDFINALLY);
12336                         MONO_ADD_INS (cfg->cbb, ins);
12337                         ip++;
12338                         start_new_bblock = 1;
12339
12340                         /*
12341                          * Control will leave the method so empty the stack, otherwise
12342                          * the next basic block will start with a nonempty stack.
12343                          */
12344                         while (sp != stack_start) {
12345                                 sp--;
12346                         }
12347                         break;
12348                 case CEE_LEAVE:
12349                 case CEE_LEAVE_S: {
12350                         GList *handlers;
12351
12352                         if (*ip == CEE_LEAVE) {
12353                                 CHECK_OPSIZE (5);
12354                                 target = ip + 5 + (gint32)read32(ip + 1);
12355                         } else {
12356                                 CHECK_OPSIZE (2);
12357                                 target = ip + 2 + (signed char)(ip [1]);
12358                         }
12359
12360                         /* empty the stack */
12361                         while (sp != stack_start) {
12362                                 sp--;
12363                         }
12364
12365                         /* 
12366                          * If this leave statement is in a catch block, check for a
12367                          * pending exception, and rethrow it if necessary.
12368                          * We avoid doing this in runtime invoke wrappers, since those are called
12369                          * by native code which excepts the wrapper to catch all exceptions.
12370                          */
12371                         for (i = 0; i < header->num_clauses; ++i) {
12372                                 MonoExceptionClause *clause = &header->clauses [i];
12373
12374                                 /* 
12375                                  * Use <= in the final comparison to handle clauses with multiple
12376                                  * leave statements, like in bug #78024.
12377                                  * The ordering of the exception clauses guarantees that we find the
12378                                  * innermost clause.
12379                                  */
12380                                 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) {
12381                                         MonoInst *exc_ins;
12382                                         MonoBasicBlock *dont_throw;
12383
12384                                         /*
12385                                           MonoInst *load;
12386
12387                                           NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, clause->handler_offset)->inst_c0);
12388                                         */
12389
12390                                         exc_ins = mono_emit_jit_icall (cfg, mono_thread_get_undeniable_exception, NULL);
12391
12392                                         NEW_BBLOCK (cfg, dont_throw);
12393
12394                                         /*
12395                                          * Currently, we always rethrow the abort exception, despite the 
12396                                          * fact that this is not correct. See thread6.cs for an example. 
12397                                          * But propagating the abort exception is more important than 
12398                                          * getting the sematics right.
12399                                          */
12400                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, exc_ins->dreg, 0);
12401                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, dont_throw);
12402                                         MONO_EMIT_NEW_UNALU (cfg, OP_THROW, -1, exc_ins->dreg);
12403
12404                                         MONO_START_BB (cfg, dont_throw);
12405                                 }
12406                         }
12407
12408 #ifdef ENABLE_LLVM
12409                         cfg->cbb->try_end = (intptr_t)(ip - header->code);
12410 #endif
12411
12412                         if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
12413                                 GList *tmp;
12414                                 MonoExceptionClause *clause;
12415
12416                                 for (tmp = handlers; tmp; tmp = tmp->next) {
12417                                         clause = (MonoExceptionClause *)tmp->data;
12418                                         tblock = cfg->cil_offset_to_bb [clause->handler_offset];
12419                                         g_assert (tblock);
12420                                         link_bblock (cfg, cfg->cbb, tblock);
12421                                         MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
12422                                         ins->inst_target_bb = tblock;
12423                                         ins->inst_eh_block = clause;
12424                                         MONO_ADD_INS (cfg->cbb, ins);
12425                                         cfg->cbb->has_call_handler = 1;
12426                                         if (COMPILE_LLVM (cfg)) {
12427                                                 MonoBasicBlock *target_bb;
12428
12429                                                 /* 
12430                                                  * Link the finally bblock with the target, since it will
12431                                                  * conceptually branch there.
12432                                                  */
12433                                                 GET_BBLOCK (cfg, tblock, cfg->cil_start + clause->handler_offset + clause->handler_len - 1);
12434                                                 GET_BBLOCK (cfg, target_bb, target);
12435                                                 link_bblock (cfg, tblock, target_bb);
12436                                         }
12437                                 }
12438                                 g_list_free (handlers);
12439                         } 
12440
12441                         MONO_INST_NEW (cfg, ins, OP_BR);
12442                         MONO_ADD_INS (cfg->cbb, ins);
12443                         GET_BBLOCK (cfg, tblock, target);
12444                         link_bblock (cfg, cfg->cbb, tblock);
12445                         ins->inst_target_bb = tblock;
12446
12447                         start_new_bblock = 1;
12448
12449                         if (*ip == CEE_LEAVE)
12450                                 ip += 5;
12451                         else
12452                                 ip += 2;
12453
12454                         break;
12455                 }
12456
12457                         /*
12458                          * Mono specific opcodes
12459                          */
12460                 case MONO_CUSTOM_PREFIX: {
12461
12462                         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
12463
12464                         CHECK_OPSIZE (2);
12465                         switch (ip [1]) {
12466                         case CEE_MONO_ICALL: {
12467                                 gpointer func;
12468                                 MonoJitICallInfo *info;
12469
12470                                 token = read32 (ip + 2);
12471                                 func = mono_method_get_wrapper_data (method, token);
12472                                 info = mono_find_jit_icall_by_addr (func);
12473                                 if (!info)
12474                                         g_error ("Could not find icall address in wrapper %s", mono_method_full_name (method, 1));
12475                                 g_assert (info);
12476
12477                                 CHECK_STACK (info->sig->param_count);
12478                                 sp -= info->sig->param_count;
12479
12480                                 ins = mono_emit_jit_icall (cfg, info->func, sp);
12481                                 if (!MONO_TYPE_IS_VOID (info->sig->ret))
12482                                         *sp++ = ins;
12483
12484                                 ip += 6;
12485                                 inline_costs += 10 * num_calls++;
12486
12487                                 break;
12488                         }
12489                         case CEE_MONO_LDPTR_CARD_TABLE:
12490                         case CEE_MONO_LDPTR_NURSERY_START:
12491                         case CEE_MONO_LDPTR_NURSERY_BITS:
12492                         case CEE_MONO_LDPTR_INT_REQ_FLAG: {
12493                                 CHECK_STACK_OVF (1);
12494
12495                                 switch (ip [1]) {
12496                                         case CEE_MONO_LDPTR_CARD_TABLE:
12497                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR, NULL);
12498                                                 break;
12499                                         case CEE_MONO_LDPTR_NURSERY_START:
12500                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_NURSERY_START, NULL);
12501                                                 break;
12502                                         case CEE_MONO_LDPTR_NURSERY_BITS:
12503                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_NURSERY_BITS, NULL);
12504                                                 break;
12505                                         case CEE_MONO_LDPTR_INT_REQ_FLAG:
12506                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG, NULL);
12507                                                 break;
12508                                 }
12509
12510                                 *sp++ = ins;
12511                                 ip += 2;
12512                                 inline_costs += 10 * num_calls++;
12513                                 break;
12514                         }
12515                         case CEE_MONO_LDPTR: {
12516                                 gpointer ptr;
12517
12518                                 CHECK_STACK_OVF (1);
12519                                 CHECK_OPSIZE (6);
12520                                 token = read32 (ip + 2);
12521
12522                                 ptr = mono_method_get_wrapper_data (method, token);
12523                                 EMIT_NEW_PCONST (cfg, ins, ptr);
12524                                 *sp++ = ins;
12525                                 ip += 6;
12526                                 inline_costs += 10 * num_calls++;
12527                                 /* Can't embed random pointers into AOT code */
12528                                 DISABLE_AOT (cfg);
12529                                 break;
12530                         }
12531                         case CEE_MONO_JIT_ICALL_ADDR: {
12532                                 MonoJitICallInfo *callinfo;
12533                                 gpointer ptr;
12534
12535                                 CHECK_STACK_OVF (1);
12536                                 CHECK_OPSIZE (6);
12537                                 token = read32 (ip + 2);
12538
12539                                 ptr = mono_method_get_wrapper_data (method, token);
12540                                 callinfo = mono_find_jit_icall_by_addr (ptr);
12541                                 g_assert (callinfo);
12542                                 EMIT_NEW_JIT_ICALL_ADDRCONST (cfg, ins, (char*)callinfo->name);
12543                                 *sp++ = ins;
12544                                 ip += 6;
12545                                 inline_costs += 10 * num_calls++;
12546                                 break;
12547                         }
12548                         case CEE_MONO_ICALL_ADDR: {
12549                                 MonoMethod *cmethod;
12550                                 gpointer ptr;
12551
12552                                 CHECK_STACK_OVF (1);
12553                                 CHECK_OPSIZE (6);
12554                                 token = read32 (ip + 2);
12555
12556                                 cmethod = (MonoMethod *)mono_method_get_wrapper_data (method, token);
12557
12558                                 if (cfg->compile_aot) {
12559                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, cmethod);
12560                                 } else {
12561                                         ptr = mono_lookup_internal_call (cmethod);
12562                                         g_assert (ptr);
12563                                         EMIT_NEW_PCONST (cfg, ins, ptr);
12564                                 }
12565                                 *sp++ = ins;
12566                                 ip += 6;
12567                                 break;
12568                         }
12569                         case CEE_MONO_VTADDR: {
12570                                 MonoInst *src_var, *src;
12571
12572                                 CHECK_STACK (1);
12573                                 --sp;
12574
12575                                 // FIXME:
12576                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
12577                                 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
12578                                 *sp++ = src;
12579                                 ip += 2;
12580                                 break;
12581                         }
12582                         case CEE_MONO_NEWOBJ: {
12583                                 MonoInst *iargs [2];
12584
12585                                 CHECK_STACK_OVF (1);
12586                                 CHECK_OPSIZE (6);
12587                                 token = read32 (ip + 2);
12588                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12589                                 mono_class_init (klass);
12590                                 NEW_DOMAINCONST (cfg, iargs [0]);
12591                                 MONO_ADD_INS (cfg->cbb, iargs [0]);
12592                                 NEW_CLASSCONST (cfg, iargs [1], klass);
12593                                 MONO_ADD_INS (cfg->cbb, iargs [1]);
12594                                 *sp++ = mono_emit_jit_icall (cfg, ves_icall_object_new, iargs);
12595                                 ip += 6;
12596                                 inline_costs += 10 * num_calls++;
12597                                 break;
12598                         }
12599                         case CEE_MONO_OBJADDR:
12600                                 CHECK_STACK (1);
12601                                 --sp;
12602                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
12603                                 ins->dreg = alloc_ireg_mp (cfg);
12604                                 ins->sreg1 = sp [0]->dreg;
12605                                 ins->type = STACK_MP;
12606                                 MONO_ADD_INS (cfg->cbb, ins);
12607                                 *sp++ = ins;
12608                                 ip += 2;
12609                                 break;
12610                         case CEE_MONO_LDNATIVEOBJ:
12611                                 /*
12612                                  * Similar to LDOBJ, but instead load the unmanaged 
12613                                  * representation of the vtype to the stack.
12614                                  */
12615                                 CHECK_STACK (1);
12616                                 CHECK_OPSIZE (6);
12617                                 --sp;
12618                                 token = read32 (ip + 2);
12619                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12620                                 g_assert (klass->valuetype);
12621                                 mono_class_init (klass);
12622
12623                                 {
12624                                         MonoInst *src, *dest, *temp;
12625
12626                                         src = sp [0];
12627                                         temp = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
12628                                         temp->backend.is_pinvoke = 1;
12629                                         EMIT_NEW_TEMPLOADA (cfg, dest, temp->inst_c0);
12630                                         mini_emit_stobj (cfg, dest, src, klass, TRUE);
12631
12632                                         EMIT_NEW_TEMPLOAD (cfg, dest, temp->inst_c0);
12633                                         dest->type = STACK_VTYPE;
12634                                         dest->klass = klass;
12635
12636                                         *sp ++ = dest;
12637                                         ip += 6;
12638                                 }
12639                                 break;
12640                         case CEE_MONO_RETOBJ: {
12641                                 /*
12642                                  * Same as RET, but return the native representation of a vtype
12643                                  * to the caller.
12644                                  */
12645                                 g_assert (cfg->ret);
12646                                 g_assert (mono_method_signature (method)->pinvoke); 
12647                                 CHECK_STACK (1);
12648                                 --sp;
12649                                 
12650                                 CHECK_OPSIZE (6);
12651                                 token = read32 (ip + 2);    
12652                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12653
12654                                 if (!cfg->vret_addr) {
12655                                         g_assert (cfg->ret_var_is_local);
12656
12657                                         EMIT_NEW_VARLOADA (cfg, ins, cfg->ret, cfg->ret->inst_vtype);
12658                                 } else {
12659                                         EMIT_NEW_RETLOADA (cfg, ins);
12660                                 }
12661                                 mini_emit_stobj (cfg, ins, sp [0], klass, TRUE);
12662                                 
12663                                 if (sp != stack_start)
12664                                         UNVERIFIED;
12665                                 
12666                                 MONO_INST_NEW (cfg, ins, OP_BR);
12667                                 ins->inst_target_bb = end_bblock;
12668                                 MONO_ADD_INS (cfg->cbb, ins);
12669                                 link_bblock (cfg, cfg->cbb, end_bblock);
12670                                 start_new_bblock = 1;
12671                                 ip += 6;
12672                                 break;
12673                         }
12674                         case CEE_MONO_CISINST:
12675                         case CEE_MONO_CCASTCLASS: {
12676                                 int token;
12677                                 CHECK_STACK (1);
12678                                 --sp;
12679                                 CHECK_OPSIZE (6);
12680                                 token = read32 (ip + 2);
12681                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12682                                 if (ip [1] == CEE_MONO_CISINST)
12683                                         ins = handle_cisinst (cfg, klass, sp [0]);
12684                                 else
12685                                         ins = handle_ccastclass (cfg, klass, sp [0]);
12686                                 *sp++ = ins;
12687                                 ip += 6;
12688                                 break;
12689                         }
12690                         case CEE_MONO_SAVE_LMF:
12691                         case CEE_MONO_RESTORE_LMF:
12692                                 ip += 2;
12693                                 break;
12694                         case CEE_MONO_CLASSCONST:
12695                                 CHECK_STACK_OVF (1);
12696                                 CHECK_OPSIZE (6);
12697                                 token = read32 (ip + 2);
12698                                 EMIT_NEW_CLASSCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
12699                                 *sp++ = ins;
12700                                 ip += 6;
12701                                 inline_costs += 10 * num_calls++;
12702                                 break;
12703                         case CEE_MONO_NOT_TAKEN:
12704                                 cfg->cbb->out_of_line = TRUE;
12705                                 ip += 2;
12706                                 break;
12707                         case CEE_MONO_TLS: {
12708                                 MonoTlsKey key;
12709
12710                                 CHECK_STACK_OVF (1);
12711                                 CHECK_OPSIZE (6);
12712                                 key = (MonoTlsKey)read32 (ip + 2);
12713                                 g_assert (key < TLS_KEY_NUM);
12714
12715                                 ins = mono_create_tls_get (cfg, key);
12716                                 if (!ins) {
12717                                         if (cfg->compile_aot) {
12718                                                 DISABLE_AOT (cfg);
12719                                                 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
12720                                                 ins->dreg = alloc_preg (cfg);
12721                                                 ins->type = STACK_PTR;
12722                                         } else {
12723                                                 g_assert_not_reached ();
12724                                         }
12725                                 }
12726                                 ins->type = STACK_PTR;
12727                                 MONO_ADD_INS (cfg->cbb, ins);
12728                                 *sp++ = ins;
12729                                 ip += 6;
12730                                 break;
12731                         }
12732                         case CEE_MONO_DYN_CALL: {
12733                                 MonoCallInst *call;
12734
12735                                 /* It would be easier to call a trampoline, but that would put an
12736                                  * extra frame on the stack, confusing exception handling. So
12737                                  * implement it inline using an opcode for now.
12738                                  */
12739
12740                                 if (!cfg->dyn_call_var) {
12741                                         cfg->dyn_call_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12742                                         /* prevent it from being register allocated */
12743                                         cfg->dyn_call_var->flags |= MONO_INST_VOLATILE;
12744                                 }
12745
12746                                 /* Has to use a call inst since it local regalloc expects it */
12747                                 MONO_INST_NEW_CALL (cfg, call, OP_DYN_CALL);
12748                                 ins = (MonoInst*)call;
12749                                 sp -= 2;
12750                                 ins->sreg1 = sp [0]->dreg;
12751                                 ins->sreg2 = sp [1]->dreg;
12752                                 MONO_ADD_INS (cfg->cbb, ins);
12753
12754                                 cfg->param_area = MAX (cfg->param_area, cfg->backend->dyn_call_param_area);
12755
12756                                 ip += 2;
12757                                 inline_costs += 10 * num_calls++;
12758
12759                                 break;
12760                         }
12761                         case CEE_MONO_MEMORY_BARRIER: {
12762                                 CHECK_OPSIZE (6);
12763                                 emit_memory_barrier (cfg, (int)read32 (ip + 2));
12764                                 ip += 6;
12765                                 break;
12766                         }
12767                         case CEE_MONO_ATOMIC_STORE_I4: {
12768                                 g_assert (mono_arch_opcode_supported (OP_ATOMIC_STORE_I4));
12769
12770                                 CHECK_OPSIZE (6);
12771                                 CHECK_STACK (2);
12772                                 sp -= 2;
12773
12774                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_STORE_I4);
12775                                 ins->dreg = sp [0]->dreg;
12776                                 ins->sreg1 = sp [1]->dreg;
12777                                 ins->backend.memory_barrier_kind = (int) read32 (ip + 2);
12778                                 MONO_ADD_INS (cfg->cbb, ins);
12779
12780                                 ip += 6;
12781                                 break;
12782                         }
12783                         case CEE_MONO_JIT_ATTACH: {
12784                                 MonoInst *args [16], *domain_ins;
12785                                 MonoInst *ad_ins, *jit_tls_ins;
12786                                 MonoBasicBlock *next_bb = NULL, *call_bb = NULL;
12787
12788                                 g_assert (!mono_threads_is_coop_enabled ());
12789
12790                                 cfg->orig_domain_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12791
12792                                 EMIT_NEW_PCONST (cfg, ins, NULL);
12793                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12794
12795                                 ad_ins = mono_get_domain_intrinsic (cfg);
12796                                 jit_tls_ins = mono_get_jit_tls_intrinsic (cfg);
12797
12798                                 if (cfg->backend->have_tls_get && ad_ins && jit_tls_ins) {
12799                                         NEW_BBLOCK (cfg, next_bb);
12800                                         NEW_BBLOCK (cfg, call_bb);
12801
12802                                         if (cfg->compile_aot) {
12803                                                 /* AOT code is only used in the root domain */
12804                                                 EMIT_NEW_PCONST (cfg, domain_ins, NULL);
12805                                         } else {
12806                                                 EMIT_NEW_PCONST (cfg, domain_ins, cfg->domain);
12807                                         }
12808                                         MONO_ADD_INS (cfg->cbb, ad_ins);
12809                                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, ad_ins->dreg, domain_ins->dreg);
12810                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, call_bb);
12811
12812                                         MONO_ADD_INS (cfg->cbb, jit_tls_ins);
12813                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, jit_tls_ins->dreg, 0);
12814                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, call_bb);
12815
12816                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, next_bb);
12817                                         MONO_START_BB (cfg, call_bb);
12818                                 }
12819
12820                                 /* AOT code is only used in the root domain */
12821                                 EMIT_NEW_PCONST (cfg, args [0], cfg->compile_aot ? NULL : cfg->domain);
12822                                 ins = mono_emit_jit_icall (cfg, mono_jit_thread_attach, args);
12823                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12824
12825                                 if (next_bb)
12826                                         MONO_START_BB (cfg, next_bb);
12827
12828
12829                                 ip += 2;
12830                                 break;
12831                         }
12832                         case CEE_MONO_JIT_DETACH: {
12833                                 MonoInst *args [16];
12834
12835                                 /* Restore the original domain */
12836                                 dreg = alloc_ireg (cfg);
12837                                 EMIT_NEW_UNALU (cfg, args [0], OP_MOVE, dreg, cfg->orig_domain_var->dreg);
12838                                 mono_emit_jit_icall (cfg, mono_jit_set_domain, args);
12839                                 ip += 2;
12840                                 break;
12841                         }
12842                         case CEE_MONO_CALLI_EXTRA_ARG: {
12843                                 MonoInst *addr;
12844                                 MonoMethodSignature *fsig;
12845                                 MonoInst *arg;
12846
12847                                 /*
12848                                  * This is the same as CEE_CALLI, but passes an additional argument
12849                                  * to the called method in llvmonly mode.
12850                                  * This is only used by delegate invoke wrappers to call the
12851                                  * actual delegate method.
12852                                  */
12853                                 g_assert (method->wrapper_type == MONO_WRAPPER_DELEGATE_INVOKE);
12854
12855                                 CHECK_OPSIZE (6);
12856                                 token = read32 (ip + 2);
12857
12858                                 ins = NULL;
12859
12860                                 cmethod = NULL;
12861                                 CHECK_STACK (1);
12862                                 --sp;
12863                                 addr = *sp;
12864                                 fsig = mini_get_signature (method, token, generic_context, &cfg->error);
12865                                 CHECK_CFG_ERROR;
12866
12867                                 if (cfg->llvm_only)
12868                                         cfg->signatures = g_slist_prepend_mempool (cfg->mempool, cfg->signatures, fsig);
12869
12870                                 n = fsig->param_count + fsig->hasthis + 1;
12871
12872                                 CHECK_STACK (n);
12873
12874                                 sp -= n;
12875                                 arg = sp [n - 1];
12876
12877                                 if (cfg->llvm_only) {
12878                                         /*
12879                                          * The lowest bit of 'arg' determines whenever the callee uses the gsharedvt
12880                                          * cconv. This is set by mono_init_delegate ().
12881                                          */
12882                                         if (cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig)) {
12883                                                 MonoInst *callee = addr;
12884                                                 MonoInst *call, *localloc_ins;
12885                                                 MonoBasicBlock *is_gsharedvt_bb, *end_bb;
12886                                                 int low_bit_reg = alloc_preg (cfg);
12887
12888                                                 NEW_BBLOCK (cfg, is_gsharedvt_bb);
12889                                                 NEW_BBLOCK (cfg, end_bb);
12890
12891                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, low_bit_reg, arg->dreg, 1);
12892                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_bit_reg, 0);
12893                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, is_gsharedvt_bb);
12894
12895                                                 /* Normal case: callee uses a normal cconv, have to add an out wrapper */
12896                                                 addr = emit_get_rgctx_sig (cfg, context_used,
12897                                                                                                    fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
12898                                                 /*
12899                                                  * ADDR points to a gsharedvt-out wrapper, have to pass <callee, arg> as an extra arg.
12900                                                  */
12901                                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
12902                                                 ins->dreg = alloc_preg (cfg);
12903                                                 ins->inst_imm = 2 * SIZEOF_VOID_P;
12904                                                 MONO_ADD_INS (cfg->cbb, ins);
12905                                                 localloc_ins = ins;
12906                                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12907                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, 0, callee->dreg);
12908                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, SIZEOF_VOID_P, arg->dreg);
12909
12910                                                 call = emit_extra_arg_calli (cfg, fsig, sp, localloc_ins->dreg, addr);
12911                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12912
12913                                                 /* Gsharedvt case: callee uses a gsharedvt cconv, no conversion is needed */
12914                                                 MONO_START_BB (cfg, is_gsharedvt_bb);
12915                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PXOR_IMM, arg->dreg, arg->dreg, 1);
12916                                                 ins = emit_extra_arg_calli (cfg, fsig, sp, arg->dreg, callee);
12917                                                 ins->dreg = call->dreg;
12918
12919                                                 MONO_START_BB (cfg, end_bb);
12920                                         } else {
12921                                                 /* Caller uses a normal calling conv */
12922
12923                                                 MonoInst *callee = addr;
12924                                                 MonoInst *call, *localloc_ins;
12925                                                 MonoBasicBlock *is_gsharedvt_bb, *end_bb;
12926                                                 int low_bit_reg = alloc_preg (cfg);
12927
12928                                                 NEW_BBLOCK (cfg, is_gsharedvt_bb);
12929                                                 NEW_BBLOCK (cfg, end_bb);
12930
12931                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, low_bit_reg, arg->dreg, 1);
12932                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_bit_reg, 0);
12933                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, is_gsharedvt_bb);
12934
12935                                                 /* Normal case: callee uses a normal cconv, no conversion is needed */
12936                                                 call = emit_extra_arg_calli (cfg, fsig, sp, arg->dreg, callee);
12937                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12938                                                 /* Gsharedvt case: callee uses a gsharedvt cconv, have to add an in wrapper */
12939                                                 MONO_START_BB (cfg, is_gsharedvt_bb);
12940                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PXOR_IMM, arg->dreg, arg->dreg, 1);
12941                                                 NEW_AOTCONST (cfg, addr, MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER, fsig);
12942                                                 MONO_ADD_INS (cfg->cbb, addr);
12943                                                 /*
12944                                                  * ADDR points to a gsharedvt-in wrapper, have to pass <callee, arg> as an extra arg.
12945                                                  */
12946                                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
12947                                                 ins->dreg = alloc_preg (cfg);
12948                                                 ins->inst_imm = 2 * SIZEOF_VOID_P;
12949                                                 MONO_ADD_INS (cfg->cbb, ins);
12950                                                 localloc_ins = ins;
12951                                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12952                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, 0, callee->dreg);
12953                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, SIZEOF_VOID_P, arg->dreg);
12954
12955                                                 ins = emit_extra_arg_calli (cfg, fsig, sp, localloc_ins->dreg, addr);
12956                                                 ins->dreg = call->dreg;
12957                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12958
12959                                                 MONO_START_BB (cfg, end_bb);
12960                                         }
12961                                 } else {
12962                                         /* Same as CEE_CALLI */
12963                                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
12964                                                 /*
12965                                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
12966                                                  */
12967                                                 MonoInst *callee = addr;
12968
12969                                                 addr = emit_get_rgctx_sig (cfg, context_used,
12970                                                                                                    fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
12971                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
12972                                         } else {
12973                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
12974                                         }
12975                                 }
12976
12977                                 if (!MONO_TYPE_IS_VOID (fsig->ret))
12978                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
12979
12980                                 CHECK_CFG_EXCEPTION;
12981
12982                                 ip += 6;
12983                                 ins_flag = 0;
12984                                 constrained_class = NULL;
12985                                 break;
12986                         }
12987                         case CEE_MONO_LDDOMAIN:
12988                                 CHECK_STACK_OVF (1);
12989                                 EMIT_NEW_PCONST (cfg, ins, cfg->compile_aot ? NULL : cfg->domain);
12990                                 ip += 2;
12991                                 *sp++ = ins;
12992                                 break;
12993                         case CEE_MONO_GET_LAST_ERROR:
12994                                 CHECK_OPSIZE (2);
12995                                 CHECK_STACK_OVF (1);
12996
12997                                 MONO_INST_NEW (cfg, ins, OP_GET_LAST_ERROR);
12998                                 ins->dreg = alloc_dreg (cfg, STACK_I4);
12999                                 ins->type = STACK_I4;
13000                                 MONO_ADD_INS (cfg->cbb, ins);
13001
13002                                 ip += 2;
13003                                 *sp++ = ins;
13004                                 break;
13005                         default:
13006                                 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
13007                                 break;
13008                         }
13009                         break;
13010                 }
13011
13012                 case CEE_PREFIX1: {
13013                         CHECK_OPSIZE (2);
13014                         switch (ip [1]) {
13015                         case CEE_ARGLIST: {
13016                                 /* somewhat similar to LDTOKEN */
13017                                 MonoInst *addr, *vtvar;
13018                                 CHECK_STACK_OVF (1);
13019                                 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL); 
13020
13021                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
13022                                 EMIT_NEW_UNALU (cfg, ins, OP_ARGLIST, -1, addr->dreg);
13023
13024                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
13025                                 ins->type = STACK_VTYPE;
13026                                 ins->klass = mono_defaults.argumenthandle_class;
13027                                 *sp++ = ins;
13028                                 ip += 2;
13029                                 break;
13030                         }
13031                         case CEE_CEQ:
13032                         case CEE_CGT:
13033                         case CEE_CGT_UN:
13034                         case CEE_CLT:
13035                         case CEE_CLT_UN: {
13036                                 MonoInst *cmp, *arg1, *arg2;
13037
13038                                 CHECK_STACK (2);
13039                                 sp -= 2;
13040                                 arg1 = sp [0];
13041                                 arg2 = sp [1];
13042
13043                                 /*
13044                                  * The following transforms:
13045                                  *    CEE_CEQ    into OP_CEQ
13046                                  *    CEE_CGT    into OP_CGT
13047                                  *    CEE_CGT_UN into OP_CGT_UN
13048                                  *    CEE_CLT    into OP_CLT
13049                                  *    CEE_CLT_UN into OP_CLT_UN
13050                                  */
13051                                 MONO_INST_NEW (cfg, cmp, (OP_CEQ - CEE_CEQ) + ip [1]);
13052
13053                                 MONO_INST_NEW (cfg, ins, cmp->opcode);
13054                                 cmp->sreg1 = arg1->dreg;
13055                                 cmp->sreg2 = arg2->dreg;
13056                                 type_from_op (cfg, cmp, arg1, arg2);
13057                                 CHECK_TYPE (cmp);
13058                                 add_widen_op (cfg, cmp, &arg1, &arg2);
13059                                 if ((arg1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((arg1->type == STACK_PTR) || (arg1->type == STACK_OBJ) || (arg1->type == STACK_MP))))
13060                                         cmp->opcode = OP_LCOMPARE;
13061                                 else if (arg1->type == STACK_R4)
13062                                         cmp->opcode = OP_RCOMPARE;
13063                                 else if (arg1->type == STACK_R8)
13064                                         cmp->opcode = OP_FCOMPARE;
13065                                 else
13066                                         cmp->opcode = OP_ICOMPARE;
13067                                 MONO_ADD_INS (cfg->cbb, cmp);
13068                                 ins->type = STACK_I4;
13069                                 ins->dreg = alloc_dreg (cfg, (MonoStackType)ins->type);
13070                                 type_from_op (cfg, ins, arg1, arg2);
13071
13072                                 if (cmp->opcode == OP_FCOMPARE || cmp->opcode == OP_RCOMPARE) {
13073                                         /*
13074                                          * The backends expect the fceq opcodes to do the
13075                                          * comparison too.
13076                                          */
13077                                         ins->sreg1 = cmp->sreg1;
13078                                         ins->sreg2 = cmp->sreg2;
13079                                         NULLIFY_INS (cmp);
13080                                 }
13081                                 MONO_ADD_INS (cfg->cbb, ins);
13082                                 *sp++ = ins;
13083                                 ip += 2;
13084                                 break;
13085                         }
13086                         case CEE_LDFTN: {
13087                                 MonoInst *argconst;
13088                                 MonoMethod *cil_method;
13089
13090                                 CHECK_STACK_OVF (1);
13091                                 CHECK_OPSIZE (6);
13092                                 n = read32 (ip + 2);
13093                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
13094                                 CHECK_CFG_ERROR;
13095
13096                                 mono_class_init (cmethod->klass);
13097
13098                                 mono_save_token_info (cfg, image, n, cmethod);
13099
13100                                 context_used = mini_method_check_context_used (cfg, cmethod);
13101
13102                                 cil_method = cmethod;
13103                                 if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
13104                                         emit_method_access_failure (cfg, method, cil_method);
13105
13106                                 if (mono_security_core_clr_enabled ())
13107                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
13108
13109                                 /* 
13110                                  * Optimize the common case of ldftn+delegate creation
13111                                  */
13112                                 if ((sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 6) && (ip [6] == CEE_NEWOBJ)) {
13113                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
13114                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
13115                                                 MonoInst *target_ins, *handle_ins;
13116                                                 MonoMethod *invoke;
13117                                                 int invoke_context_used;
13118
13119                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
13120                                                 if (!invoke || !mono_method_signature (invoke))
13121                                                         LOAD_ERROR;
13122
13123                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
13124
13125                                                 target_ins = sp [-1];
13126
13127                                                 if (mono_security_core_clr_enabled ())
13128                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
13129
13130                                                 if (!(cmethod->flags & METHOD_ATTRIBUTE_STATIC)) {
13131                                                         /*LAME IMPL: We must not add a null check for virtual invoke delegates.*/
13132                                                         if (mono_method_signature (invoke)->param_count == mono_method_signature (cmethod)->param_count) {
13133                                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, target_ins->dreg, 0);
13134                                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "ArgumentException");
13135                                                         }
13136                                                 }
13137
13138                                                 /* FIXME: SGEN support */
13139                                                 if (invoke_context_used == 0 || cfg->llvm_only) {
13140                                                         ip += 6;
13141                                                         if (cfg->verbose_level > 3)
13142                                                                 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));
13143                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, FALSE))) {
13144                                                                 sp --;
13145                                                                 *sp = handle_ins;
13146                                                                 CHECK_CFG_EXCEPTION;
13147                                                                 ip += 5;
13148                                                                 sp ++;
13149                                                                 break;
13150                                                         }
13151                                                         ip -= 6;
13152                                                 }
13153                                         }
13154                                 }
13155
13156                                 argconst = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD);
13157                                 ins = mono_emit_jit_icall (cfg, mono_ldftn, &argconst);
13158                                 *sp++ = ins;
13159                                 
13160                                 ip += 6;
13161                                 inline_costs += 10 * num_calls++;
13162                                 break;
13163                         }
13164                         case CEE_LDVIRTFTN: {
13165                                 MonoInst *args [2];
13166
13167                                 CHECK_STACK (1);
13168                                 CHECK_OPSIZE (6);
13169                                 n = read32 (ip + 2);
13170                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
13171                                 CHECK_CFG_ERROR;
13172
13173                                 mono_class_init (cmethod->klass);
13174  
13175                                 context_used = mini_method_check_context_used (cfg, cmethod);
13176
13177                                 if (mono_security_core_clr_enabled ())
13178                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
13179
13180                                 /*
13181                                  * Optimize the common case of ldvirtftn+delegate creation
13182                                  */
13183                                 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)) {
13184                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
13185                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
13186                                                 MonoInst *target_ins, *handle_ins;
13187                                                 MonoMethod *invoke;
13188                                                 int invoke_context_used;
13189                                                 gboolean is_virtual = cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL;
13190
13191                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
13192                                                 if (!invoke || !mono_method_signature (invoke))
13193                                                         LOAD_ERROR;
13194
13195                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
13196
13197                                                 target_ins = sp [-1];
13198
13199                                                 if (mono_security_core_clr_enabled ())
13200                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
13201
13202                                                 /* FIXME: SGEN support */
13203                                                 if (invoke_context_used == 0 || cfg->llvm_only) {
13204                                                         ip += 6;
13205                                                         if (cfg->verbose_level > 3)
13206                                                                 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));
13207                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, is_virtual))) {
13208                                                                 sp -= 2;
13209                                                                 *sp = handle_ins;
13210                                                                 CHECK_CFG_EXCEPTION;
13211                                                                 ip += 5;
13212                                                                 sp ++;
13213                                                                 break;
13214                                                         }
13215                                                         ip -= 6;
13216                                                 }
13217                                         }
13218                                 }
13219
13220                                 --sp;
13221                                 args [0] = *sp;
13222
13223                                 args [1] = emit_get_rgctx_method (cfg, context_used,
13224                                                                                                   cmethod, MONO_RGCTX_INFO_METHOD);
13225
13226                                 if (context_used)
13227                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn_gshared, args);
13228                                 else
13229                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn, args);
13230
13231                                 ip += 6;
13232                                 inline_costs += 10 * num_calls++;
13233                                 break;
13234                         }
13235                         case CEE_LDARG:
13236                                 CHECK_STACK_OVF (1);
13237                                 CHECK_OPSIZE (4);
13238                                 n = read16 (ip + 2);
13239                                 CHECK_ARG (n);
13240                                 EMIT_NEW_ARGLOAD (cfg, ins, n);
13241                                 *sp++ = ins;
13242                                 ip += 4;
13243                                 break;
13244                         case CEE_LDARGA:
13245                                 CHECK_STACK_OVF (1);
13246                                 CHECK_OPSIZE (4);
13247                                 n = read16 (ip + 2);
13248                                 CHECK_ARG (n);
13249                                 NEW_ARGLOADA (cfg, ins, n);
13250                                 MONO_ADD_INS (cfg->cbb, ins);
13251                                 *sp++ = ins;
13252                                 ip += 4;
13253                                 break;
13254                         case CEE_STARG:
13255                                 CHECK_STACK (1);
13256                                 --sp;
13257                                 CHECK_OPSIZE (4);
13258                                 n = read16 (ip + 2);
13259                                 CHECK_ARG (n);
13260                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
13261                                         UNVERIFIED;
13262                                 EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
13263                                 ip += 4;
13264                                 break;
13265                         case CEE_LDLOC:
13266                                 CHECK_STACK_OVF (1);
13267                                 CHECK_OPSIZE (4);
13268                                 n = read16 (ip + 2);
13269                                 CHECK_LOCAL (n);
13270                                 EMIT_NEW_LOCLOAD (cfg, ins, n);
13271                                 *sp++ = ins;
13272                                 ip += 4;
13273                                 break;
13274                         case CEE_LDLOCA: {
13275                                 unsigned char *tmp_ip;
13276                                 CHECK_STACK_OVF (1);
13277                                 CHECK_OPSIZE (4);
13278                                 n = read16 (ip + 2);
13279                                 CHECK_LOCAL (n);
13280
13281                                 if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 2))) {
13282                                         ip = tmp_ip;
13283                                         inline_costs += 1;
13284                                         break;
13285                                 }                       
13286                                 
13287                                 EMIT_NEW_LOCLOADA (cfg, ins, n);
13288                                 *sp++ = ins;
13289                                 ip += 4;
13290                                 break;
13291                         }
13292                         case CEE_STLOC:
13293                                 CHECK_STACK (1);
13294                                 --sp;
13295                                 CHECK_OPSIZE (4);
13296                                 n = read16 (ip + 2);
13297                                 CHECK_LOCAL (n);
13298                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
13299                                         UNVERIFIED;
13300                                 emit_stloc_ir (cfg, sp, header, n);
13301                                 ip += 4;
13302                                 inline_costs += 1;
13303                                 break;
13304                         case CEE_LOCALLOC: {
13305                                 CHECK_STACK (1);
13306                                 MonoBasicBlock *non_zero_bb, *end_bb;
13307                                 int alloc_ptr = alloc_preg (cfg);
13308                                 --sp;
13309                                 if (sp != stack_start) 
13310                                         UNVERIFIED;
13311                                 if (cfg->method != method) 
13312                                         /* 
13313                                          * Inlining this into a loop in a parent could lead to 
13314                                          * stack overflows which is different behavior than the
13315                                          * non-inlined case, thus disable inlining in this case.
13316                                          */
13317                                         INLINE_FAILURE("localloc");
13318
13319                                 NEW_BBLOCK (cfg, non_zero_bb);
13320                                 NEW_BBLOCK (cfg, end_bb);
13321
13322                                 /* if size != zero */
13323                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
13324                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, non_zero_bb);
13325
13326                                 //size is zero, so result is NULL
13327                                 MONO_EMIT_NEW_PCONST (cfg, alloc_ptr, NULL);
13328                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
13329
13330                                 MONO_START_BB (cfg, non_zero_bb);
13331                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
13332                                 ins->dreg = alloc_ptr;
13333                                 ins->sreg1 = sp [0]->dreg;
13334                                 ins->type = STACK_PTR;
13335                                 MONO_ADD_INS (cfg->cbb, ins);
13336
13337                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
13338                                 if (init_locals)
13339                                         ins->flags |= MONO_INST_INIT;
13340
13341                                 MONO_START_BB (cfg, end_bb);
13342                                 EMIT_NEW_UNALU (cfg, ins, OP_MOVE, alloc_preg (cfg), alloc_ptr);
13343                                 ins->type = STACK_PTR;
13344
13345                                 *sp++ = ins;
13346                                 ip += 2;
13347                                 break;
13348                         }
13349                         case CEE_ENDFILTER: {
13350                                 MonoExceptionClause *clause, *nearest;
13351                                 int cc;
13352
13353                                 CHECK_STACK (1);
13354                                 --sp;
13355                                 if ((sp != stack_start) || (sp [0]->type != STACK_I4)) 
13356                                         UNVERIFIED;
13357                                 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
13358                                 ins->sreg1 = (*sp)->dreg;
13359                                 MONO_ADD_INS (cfg->cbb, ins);
13360                                 start_new_bblock = 1;
13361                                 ip += 2;
13362
13363                                 nearest = NULL;
13364                                 for (cc = 0; cc < header->num_clauses; ++cc) {
13365                                         clause = &header->clauses [cc];
13366                                         if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
13367                                                 ((ip - header->code) > clause->data.filter_offset && (ip - header->code) <= clause->handler_offset) &&
13368                                             (!nearest || (clause->data.filter_offset < nearest->data.filter_offset)))
13369                                                 nearest = clause;
13370                                 }
13371                                 g_assert (nearest);
13372                                 if ((ip - header->code) != nearest->handler_offset)
13373                                         UNVERIFIED;
13374
13375                                 break;
13376                         }
13377                         case CEE_UNALIGNED_:
13378                                 ins_flag |= MONO_INST_UNALIGNED;
13379                                 /* FIXME: record alignment? we can assume 1 for now */
13380                                 CHECK_OPSIZE (3);
13381                                 ip += 3;
13382                                 break;
13383                         case CEE_VOLATILE_:
13384                                 ins_flag |= MONO_INST_VOLATILE;
13385                                 ip += 2;
13386                                 break;
13387                         case CEE_TAIL_:
13388                                 ins_flag   |= MONO_INST_TAILCALL;
13389                                 cfg->flags |= MONO_CFG_HAS_TAIL;
13390                                 /* Can't inline tail calls at this time */
13391                                 inline_costs += 100000;
13392                                 ip += 2;
13393                                 break;
13394                         case CEE_INITOBJ:
13395                                 CHECK_STACK (1);
13396                                 --sp;
13397                                 CHECK_OPSIZE (6);
13398                                 token = read32 (ip + 2);
13399                                 klass = mini_get_class (method, token, generic_context);
13400                                 CHECK_TYPELOAD (klass);
13401                                 if (generic_class_is_reference_type (cfg, klass))
13402                                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, sp [0]->dreg, 0, 0);
13403                                 else
13404                                         mini_emit_initobj (cfg, *sp, NULL, klass);
13405                                 ip += 6;
13406                                 inline_costs += 1;
13407                                 break;
13408                         case CEE_CONSTRAINED_:
13409                                 CHECK_OPSIZE (6);
13410                                 token = read32 (ip + 2);
13411                                 constrained_class = mini_get_class (method, token, generic_context);
13412                                 CHECK_TYPELOAD (constrained_class);
13413                                 ip += 6;
13414                                 break;
13415                         case CEE_CPBLK:
13416                         case CEE_INITBLK: {
13417                                 MonoInst *iargs [3];
13418                                 CHECK_STACK (3);
13419                                 sp -= 3;
13420
13421                                 /* Skip optimized paths for volatile operations. */
13422                                 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)) {
13423                                         mini_emit_memcpy (cfg, sp [0]->dreg, 0, sp [1]->dreg, 0, sp [2]->inst_c0, 0);
13424                                 } 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)) {
13425                                         /* emit_memset only works when val == 0 */
13426                                         mini_emit_memset (cfg, sp [0]->dreg, 0, sp [2]->inst_c0, sp [1]->inst_c0, 0);
13427                                 } else {
13428                                         MonoInst *call;
13429                                         iargs [0] = sp [0];
13430                                         iargs [1] = sp [1];
13431                                         iargs [2] = sp [2];
13432                                         if (ip [1] == CEE_CPBLK) {
13433                                                 /*
13434                                                  * FIXME: It's unclear whether we should be emitting both the acquire
13435                                                  * and release barriers for cpblk. It is technically both a load and
13436                                                  * store operation, so it seems like that's the sensible thing to do.
13437                                                  *
13438                                                  * FIXME: We emit full barriers on both sides of the operation for
13439                                                  * simplicity. We should have a separate atomic memcpy method instead.
13440                                                  */
13441                                                 MonoMethod *memcpy_method = get_memcpy_method ();
13442
13443                                                 if (ins_flag & MONO_INST_VOLATILE)
13444                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
13445
13446                                                 call = mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
13447                                                 call->flags |= ins_flag;
13448
13449                                                 if (ins_flag & MONO_INST_VOLATILE)
13450                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
13451                                         } else {
13452                                                 MonoMethod *memset_method = get_memset_method ();
13453                                                 if (ins_flag & MONO_INST_VOLATILE) {
13454                                                         /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
13455                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
13456                                                 }
13457                                                 call = mono_emit_method_call (cfg, memset_method, iargs, NULL);
13458                                                 call->flags |= ins_flag;
13459                                         }
13460                                 }
13461                                 ip += 2;
13462                                 ins_flag = 0;
13463                                 inline_costs += 1;
13464                                 break;
13465                         }
13466                         case CEE_NO_:
13467                                 CHECK_OPSIZE (3);
13468                                 if (ip [2] & 0x1)
13469                                         ins_flag |= MONO_INST_NOTYPECHECK;
13470                                 if (ip [2] & 0x2)
13471                                         ins_flag |= MONO_INST_NORANGECHECK;
13472                                 /* we ignore the no-nullcheck for now since we
13473                                  * really do it explicitly only when doing callvirt->call
13474                                  */
13475                                 ip += 3;
13476                                 break;
13477                         case CEE_RETHROW: {
13478                                 MonoInst *load;
13479                                 int handler_offset = -1;
13480
13481                                 for (i = 0; i < header->num_clauses; ++i) {
13482                                         MonoExceptionClause *clause = &header->clauses [i];
13483                                         if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
13484                                                 handler_offset = clause->handler_offset;
13485                                                 break;
13486                                         }
13487                                 }
13488
13489                                 cfg->cbb->flags |= BB_EXCEPTION_UNSAFE;
13490
13491                                 if (handler_offset == -1)
13492                                         UNVERIFIED;
13493
13494                                 EMIT_NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
13495                                 MONO_INST_NEW (cfg, ins, OP_RETHROW);
13496                                 ins->sreg1 = load->dreg;
13497                                 MONO_ADD_INS (cfg->cbb, ins);
13498
13499                                 MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
13500                                 MONO_ADD_INS (cfg->cbb, ins);
13501
13502                                 sp = stack_start;
13503                                 link_bblock (cfg, cfg->cbb, end_bblock);
13504                                 start_new_bblock = 1;
13505                                 ip += 2;
13506                                 break;
13507                         }
13508                         case CEE_SIZEOF: {
13509                                 guint32 val;
13510                                 int ialign;
13511
13512                                 CHECK_STACK_OVF (1);
13513                                 CHECK_OPSIZE (6);
13514                                 token = read32 (ip + 2);
13515                                 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC && !image_is_dynamic (method->klass->image) && !generic_context) {
13516                                         MonoType *type = mono_type_create_from_typespec_checked (image, token, &cfg->error);
13517                                         CHECK_CFG_ERROR;
13518
13519                                         val = mono_type_size (type, &ialign);
13520                                 } else {
13521                                         MonoClass *klass = mini_get_class (method, token, generic_context);
13522                                         CHECK_TYPELOAD (klass);
13523
13524                                         val = mono_type_size (&klass->byval_arg, &ialign);
13525
13526                                         if (mini_is_gsharedvt_klass (klass))
13527                                                 GSHAREDVT_FAILURE (*ip);
13528                                 }
13529                                 EMIT_NEW_ICONST (cfg, ins, val);
13530                                 *sp++= ins;
13531                                 ip += 6;
13532                                 break;
13533                         }
13534                         case CEE_REFANYTYPE: {
13535                                 MonoInst *src_var, *src;
13536
13537                                 GSHAREDVT_FAILURE (*ip);
13538
13539                                 CHECK_STACK (1);
13540                                 --sp;
13541
13542                                 // FIXME:
13543                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
13544                                 if (!src_var)
13545                                         src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
13546                                 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
13547                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &mono_defaults.typehandle_class->byval_arg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type));
13548                                 *sp++ = ins;
13549                                 ip += 2;
13550                                 break;
13551                         }
13552                         case CEE_READONLY_:
13553                                 readonly = TRUE;
13554                                 ip += 2;
13555                                 break;
13556
13557                         case CEE_UNUSED56:
13558                         case CEE_UNUSED57:
13559                         case CEE_UNUSED70:
13560                         case CEE_UNUSED:
13561                         case CEE_UNUSED99:
13562                                 UNVERIFIED;
13563                                 
13564                         default:
13565                                 g_warning ("opcode 0xfe 0x%02x not handled", ip [1]);
13566                                 UNVERIFIED;
13567                         }
13568                         break;
13569                 }
13570                 case CEE_UNUSED58:
13571                 case CEE_UNUSED1:
13572                         UNVERIFIED;
13573
13574                 default:
13575                         g_warning ("opcode 0x%02x not handled", *ip);
13576                         UNVERIFIED;
13577                 }
13578         }
13579         if (start_new_bblock != 1)
13580                 UNVERIFIED;
13581
13582         cfg->cbb->cil_length = ip - cfg->cbb->cil_code;
13583         if (cfg->cbb->next_bb) {
13584                 /* This could already be set because of inlining, #693905 */
13585                 MonoBasicBlock *bb = cfg->cbb;
13586
13587                 while (bb->next_bb)
13588                         bb = bb->next_bb;
13589                 bb->next_bb = end_bblock;
13590         } else {
13591                 cfg->cbb->next_bb = end_bblock;
13592         }
13593
13594         if (cfg->method == method && cfg->domainvar) {
13595                 MonoInst *store;
13596                 MonoInst *get_domain;
13597
13598                 cfg->cbb = init_localsbb;
13599
13600                 if ((get_domain = mono_get_domain_intrinsic (cfg))) {
13601                         MONO_ADD_INS (cfg->cbb, get_domain);
13602                 } else {
13603                         get_domain = mono_emit_jit_icall (cfg, mono_domain_get, NULL);
13604                 }
13605                 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, get_domain);
13606                 MONO_ADD_INS (cfg->cbb, store);
13607         }
13608
13609 #if defined(TARGET_POWERPC) || defined(TARGET_X86)
13610         if (cfg->compile_aot)
13611                 /* FIXME: The plt slots require a GOT var even if the method doesn't use it */
13612                 mono_get_got_var (cfg);
13613 #endif
13614
13615         if (cfg->method == method && cfg->got_var)
13616                 mono_emit_load_got_addr (cfg);
13617
13618         if (init_localsbb) {
13619                 cfg->cbb = init_localsbb;
13620                 cfg->ip = NULL;
13621                 for (i = 0; i < header->num_locals; ++i) {
13622                         emit_init_local (cfg, i, header->locals [i], init_locals);
13623                 }
13624         }
13625
13626         if (cfg->init_ref_vars && cfg->method == method) {
13627                 /* Emit initialization for ref vars */
13628                 // FIXME: Avoid duplication initialization for IL locals.
13629                 for (i = 0; i < cfg->num_varinfo; ++i) {
13630                         MonoInst *ins = cfg->varinfo [i];
13631
13632                         if (ins->opcode == OP_LOCAL && ins->type == STACK_OBJ)
13633                                 MONO_EMIT_NEW_PCONST (cfg, ins->dreg, NULL);
13634                 }
13635         }
13636
13637         if (cfg->lmf_var && cfg->method == method && !cfg->llvm_only) {
13638                 cfg->cbb = init_localsbb;
13639                 emit_push_lmf (cfg);
13640         }
13641
13642         cfg->cbb = init_localsbb;
13643         emit_instrumentation_call (cfg, mono_profiler_method_enter);
13644
13645         if (seq_points) {
13646                 MonoBasicBlock *bb;
13647
13648                 /*
13649                  * Make seq points at backward branch targets interruptable.
13650                  */
13651                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
13652                         if (bb->code && bb->in_count > 1 && bb->code->opcode == OP_SEQ_POINT)
13653                                 bb->code->flags |= MONO_INST_SINGLE_STEP_LOC;
13654         }
13655
13656         /* Add a sequence point for method entry/exit events */
13657         if (seq_points && cfg->gen_sdb_seq_points) {
13658                 NEW_SEQ_POINT (cfg, ins, METHOD_ENTRY_IL_OFFSET, FALSE);
13659                 MONO_ADD_INS (init_localsbb, ins);
13660                 NEW_SEQ_POINT (cfg, ins, METHOD_EXIT_IL_OFFSET, FALSE);
13661                 MONO_ADD_INS (cfg->bb_exit, ins);
13662         }
13663
13664         /*
13665          * Add seq points for IL offsets which have line number info, but wasn't generated a seq point during JITting because
13666          * the code they refer to was dead (#11880).
13667          */
13668         if (sym_seq_points) {
13669                 for (i = 0; i < header->code_size; ++i) {
13670                         if (mono_bitset_test_fast (seq_point_locs, i) && !mono_bitset_test_fast (seq_point_set_locs, i)) {
13671                                 MonoInst *ins;
13672
13673                                 NEW_SEQ_POINT (cfg, ins, i, FALSE);
13674                                 mono_add_seq_point (cfg, NULL, ins, SEQ_POINT_NATIVE_OFFSET_DEAD_CODE);
13675                         }
13676                 }
13677         }
13678
13679         cfg->ip = NULL;
13680
13681         if (cfg->method == method) {
13682                 MonoBasicBlock *bb;
13683                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13684                         bb->region = mono_find_block_region (cfg, bb->real_offset);
13685                         if (cfg->spvars)
13686                                 mono_create_spvar_for_region (cfg, bb->region);
13687                         if (cfg->verbose_level > 2)
13688                                 printf ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
13689                 }
13690         } else {
13691                 MonoBasicBlock *bb;
13692                 /* get_most_deep_clause () in mini-llvm.c depends on this for inlined bblocks */
13693                 for (bb = start_bblock; bb != end_bblock; bb  = bb->next_bb) {
13694                         bb->real_offset = inline_offset;
13695                 }
13696         }
13697
13698         if (inline_costs < 0) {
13699                 char *mname;
13700
13701                 /* Method is too large */
13702                 mname = mono_method_full_name (method, TRUE);
13703                 mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("Method %s is too complex.", mname));
13704                 g_free (mname);
13705         }
13706
13707         if ((cfg->verbose_level > 2) && (cfg->method == method)) 
13708                 mono_print_code (cfg, "AFTER METHOD-TO-IR");
13709
13710         goto cleanup;
13711
13712 mono_error_exit:
13713         g_assert (!mono_error_ok (&cfg->error));
13714         goto cleanup;
13715  
13716  exception_exit:
13717         g_assert (cfg->exception_type != MONO_EXCEPTION_NONE);
13718         goto cleanup;
13719
13720  unverified:
13721         set_exception_type_from_invalid_il (cfg, method, ip);
13722         goto cleanup;
13723
13724  cleanup:
13725         g_slist_free (class_inits);
13726         mono_basic_block_free (original_bb);
13727         cfg->dont_inline = g_list_remove (cfg->dont_inline, method);
13728         if (cfg->exception_type)
13729                 return -1;
13730         else
13731                 return inline_costs;
13732 }
13733
13734 static int
13735 store_membase_reg_to_store_membase_imm (int opcode)
13736 {
13737         switch (opcode) {
13738         case OP_STORE_MEMBASE_REG:
13739                 return OP_STORE_MEMBASE_IMM;
13740         case OP_STOREI1_MEMBASE_REG:
13741                 return OP_STOREI1_MEMBASE_IMM;
13742         case OP_STOREI2_MEMBASE_REG:
13743                 return OP_STOREI2_MEMBASE_IMM;
13744         case OP_STOREI4_MEMBASE_REG:
13745                 return OP_STOREI4_MEMBASE_IMM;
13746         case OP_STOREI8_MEMBASE_REG:
13747                 return OP_STOREI8_MEMBASE_IMM;
13748         default:
13749                 g_assert_not_reached ();
13750         }
13751
13752         return -1;
13753 }               
13754
13755 int
13756 mono_op_to_op_imm (int opcode)
13757 {
13758         switch (opcode) {
13759         case OP_IADD:
13760                 return OP_IADD_IMM;
13761         case OP_ISUB:
13762                 return OP_ISUB_IMM;
13763         case OP_IDIV:
13764                 return OP_IDIV_IMM;
13765         case OP_IDIV_UN:
13766                 return OP_IDIV_UN_IMM;
13767         case OP_IREM:
13768                 return OP_IREM_IMM;
13769         case OP_IREM_UN:
13770                 return OP_IREM_UN_IMM;
13771         case OP_IMUL:
13772                 return OP_IMUL_IMM;
13773         case OP_IAND:
13774                 return OP_IAND_IMM;
13775         case OP_IOR:
13776                 return OP_IOR_IMM;
13777         case OP_IXOR:
13778                 return OP_IXOR_IMM;
13779         case OP_ISHL:
13780                 return OP_ISHL_IMM;
13781         case OP_ISHR:
13782                 return OP_ISHR_IMM;
13783         case OP_ISHR_UN:
13784                 return OP_ISHR_UN_IMM;
13785
13786         case OP_LADD:
13787                 return OP_LADD_IMM;
13788         case OP_LSUB:
13789                 return OP_LSUB_IMM;
13790         case OP_LAND:
13791                 return OP_LAND_IMM;
13792         case OP_LOR:
13793                 return OP_LOR_IMM;
13794         case OP_LXOR:
13795                 return OP_LXOR_IMM;
13796         case OP_LSHL:
13797                 return OP_LSHL_IMM;
13798         case OP_LSHR:
13799                 return OP_LSHR_IMM;
13800         case OP_LSHR_UN:
13801                 return OP_LSHR_UN_IMM;
13802 #if SIZEOF_REGISTER == 8
13803         case OP_LREM:
13804                 return OP_LREM_IMM;
13805 #endif
13806
13807         case OP_COMPARE:
13808                 return OP_COMPARE_IMM;
13809         case OP_ICOMPARE:
13810                 return OP_ICOMPARE_IMM;
13811         case OP_LCOMPARE:
13812                 return OP_LCOMPARE_IMM;
13813
13814         case OP_STORE_MEMBASE_REG:
13815                 return OP_STORE_MEMBASE_IMM;
13816         case OP_STOREI1_MEMBASE_REG:
13817                 return OP_STOREI1_MEMBASE_IMM;
13818         case OP_STOREI2_MEMBASE_REG:
13819                 return OP_STOREI2_MEMBASE_IMM;
13820         case OP_STOREI4_MEMBASE_REG:
13821                 return OP_STOREI4_MEMBASE_IMM;
13822
13823 #if defined(TARGET_X86) || defined (TARGET_AMD64)
13824         case OP_X86_PUSH:
13825                 return OP_X86_PUSH_IMM;
13826         case OP_X86_COMPARE_MEMBASE_REG:
13827                 return OP_X86_COMPARE_MEMBASE_IMM;
13828 #endif
13829 #if defined(TARGET_AMD64)
13830         case OP_AMD64_ICOMPARE_MEMBASE_REG:
13831                 return OP_AMD64_ICOMPARE_MEMBASE_IMM;
13832 #endif
13833         case OP_VOIDCALL_REG:
13834                 return OP_VOIDCALL;
13835         case OP_CALL_REG:
13836                 return OP_CALL;
13837         case OP_LCALL_REG:
13838                 return OP_LCALL;
13839         case OP_FCALL_REG:
13840                 return OP_FCALL;
13841         case OP_LOCALLOC:
13842                 return OP_LOCALLOC_IMM;
13843         }
13844
13845         return -1;
13846 }
13847
13848 static int
13849 ldind_to_load_membase (int opcode)
13850 {
13851         switch (opcode) {
13852         case CEE_LDIND_I1:
13853                 return OP_LOADI1_MEMBASE;
13854         case CEE_LDIND_U1:
13855                 return OP_LOADU1_MEMBASE;
13856         case CEE_LDIND_I2:
13857                 return OP_LOADI2_MEMBASE;
13858         case CEE_LDIND_U2:
13859                 return OP_LOADU2_MEMBASE;
13860         case CEE_LDIND_I4:
13861                 return OP_LOADI4_MEMBASE;
13862         case CEE_LDIND_U4:
13863                 return OP_LOADU4_MEMBASE;
13864         case CEE_LDIND_I:
13865                 return OP_LOAD_MEMBASE;
13866         case CEE_LDIND_REF:
13867                 return OP_LOAD_MEMBASE;
13868         case CEE_LDIND_I8:
13869                 return OP_LOADI8_MEMBASE;
13870         case CEE_LDIND_R4:
13871                 return OP_LOADR4_MEMBASE;
13872         case CEE_LDIND_R8:
13873                 return OP_LOADR8_MEMBASE;
13874         default:
13875                 g_assert_not_reached ();
13876         }
13877
13878         return -1;
13879 }
13880
13881 static int
13882 stind_to_store_membase (int opcode)
13883 {
13884         switch (opcode) {
13885         case CEE_STIND_I1:
13886                 return OP_STOREI1_MEMBASE_REG;
13887         case CEE_STIND_I2:
13888                 return OP_STOREI2_MEMBASE_REG;
13889         case CEE_STIND_I4:
13890                 return OP_STOREI4_MEMBASE_REG;
13891         case CEE_STIND_I:
13892         case CEE_STIND_REF:
13893                 return OP_STORE_MEMBASE_REG;
13894         case CEE_STIND_I8:
13895                 return OP_STOREI8_MEMBASE_REG;
13896         case CEE_STIND_R4:
13897                 return OP_STORER4_MEMBASE_REG;
13898         case CEE_STIND_R8:
13899                 return OP_STORER8_MEMBASE_REG;
13900         default:
13901                 g_assert_not_reached ();
13902         }
13903
13904         return -1;
13905 }
13906
13907 int
13908 mono_load_membase_to_load_mem (int opcode)
13909 {
13910         // FIXME: Add a MONO_ARCH_HAVE_LOAD_MEM macro
13911 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13912         switch (opcode) {
13913         case OP_LOAD_MEMBASE:
13914                 return OP_LOAD_MEM;
13915         case OP_LOADU1_MEMBASE:
13916                 return OP_LOADU1_MEM;
13917         case OP_LOADU2_MEMBASE:
13918                 return OP_LOADU2_MEM;
13919         case OP_LOADI4_MEMBASE:
13920                 return OP_LOADI4_MEM;
13921         case OP_LOADU4_MEMBASE:
13922                 return OP_LOADU4_MEM;
13923 #if SIZEOF_REGISTER == 8
13924         case OP_LOADI8_MEMBASE:
13925                 return OP_LOADI8_MEM;
13926 #endif
13927         }
13928 #endif
13929
13930         return -1;
13931 }
13932
13933 static inline int
13934 op_to_op_dest_membase (int store_opcode, int opcode)
13935 {
13936 #if defined(TARGET_X86)
13937         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG)))
13938                 return -1;
13939
13940         switch (opcode) {
13941         case OP_IADD:
13942                 return OP_X86_ADD_MEMBASE_REG;
13943         case OP_ISUB:
13944                 return OP_X86_SUB_MEMBASE_REG;
13945         case OP_IAND:
13946                 return OP_X86_AND_MEMBASE_REG;
13947         case OP_IOR:
13948                 return OP_X86_OR_MEMBASE_REG;
13949         case OP_IXOR:
13950                 return OP_X86_XOR_MEMBASE_REG;
13951         case OP_ADD_IMM:
13952         case OP_IADD_IMM:
13953                 return OP_X86_ADD_MEMBASE_IMM;
13954         case OP_SUB_IMM:
13955         case OP_ISUB_IMM:
13956                 return OP_X86_SUB_MEMBASE_IMM;
13957         case OP_AND_IMM:
13958         case OP_IAND_IMM:
13959                 return OP_X86_AND_MEMBASE_IMM;
13960         case OP_OR_IMM:
13961         case OP_IOR_IMM:
13962                 return OP_X86_OR_MEMBASE_IMM;
13963         case OP_XOR_IMM:
13964         case OP_IXOR_IMM:
13965                 return OP_X86_XOR_MEMBASE_IMM;
13966         case OP_MOVE:
13967                 return OP_NOP;
13968         }
13969 #endif
13970
13971 #if defined(TARGET_AMD64)
13972         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG) || (store_opcode == OP_STOREI8_MEMBASE_REG)))
13973                 return -1;
13974
13975         switch (opcode) {
13976         case OP_IADD:
13977                 return OP_X86_ADD_MEMBASE_REG;
13978         case OP_ISUB:
13979                 return OP_X86_SUB_MEMBASE_REG;
13980         case OP_IAND:
13981                 return OP_X86_AND_MEMBASE_REG;
13982         case OP_IOR:
13983                 return OP_X86_OR_MEMBASE_REG;
13984         case OP_IXOR:
13985                 return OP_X86_XOR_MEMBASE_REG;
13986         case OP_IADD_IMM:
13987                 return OP_X86_ADD_MEMBASE_IMM;
13988         case OP_ISUB_IMM:
13989                 return OP_X86_SUB_MEMBASE_IMM;
13990         case OP_IAND_IMM:
13991                 return OP_X86_AND_MEMBASE_IMM;
13992         case OP_IOR_IMM:
13993                 return OP_X86_OR_MEMBASE_IMM;
13994         case OP_IXOR_IMM:
13995                 return OP_X86_XOR_MEMBASE_IMM;
13996         case OP_LADD:
13997                 return OP_AMD64_ADD_MEMBASE_REG;
13998         case OP_LSUB:
13999                 return OP_AMD64_SUB_MEMBASE_REG;
14000         case OP_LAND:
14001                 return OP_AMD64_AND_MEMBASE_REG;
14002         case OP_LOR:
14003                 return OP_AMD64_OR_MEMBASE_REG;
14004         case OP_LXOR:
14005                 return OP_AMD64_XOR_MEMBASE_REG;
14006         case OP_ADD_IMM:
14007         case OP_LADD_IMM:
14008                 return OP_AMD64_ADD_MEMBASE_IMM;
14009         case OP_SUB_IMM:
14010         case OP_LSUB_IMM:
14011                 return OP_AMD64_SUB_MEMBASE_IMM;
14012         case OP_AND_IMM:
14013         case OP_LAND_IMM:
14014                 return OP_AMD64_AND_MEMBASE_IMM;
14015         case OP_OR_IMM:
14016         case OP_LOR_IMM:
14017                 return OP_AMD64_OR_MEMBASE_IMM;
14018         case OP_XOR_IMM:
14019         case OP_LXOR_IMM:
14020                 return OP_AMD64_XOR_MEMBASE_IMM;
14021         case OP_MOVE:
14022                 return OP_NOP;
14023         }
14024 #endif
14025
14026         return -1;
14027 }
14028
14029 static inline int
14030 op_to_op_store_membase (int store_opcode, int opcode)
14031 {
14032 #if defined(TARGET_X86) || defined(TARGET_AMD64)
14033         switch (opcode) {
14034         case OP_ICEQ:
14035                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
14036                         return OP_X86_SETEQ_MEMBASE;
14037         case OP_CNE:
14038                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
14039                         return OP_X86_SETNE_MEMBASE;
14040         }
14041 #endif
14042
14043         return -1;
14044 }
14045
14046 static inline int
14047 op_to_op_src1_membase (MonoCompile *cfg, int load_opcode, int opcode)
14048 {
14049 #ifdef TARGET_X86
14050         /* FIXME: This has sign extension issues */
14051         /*
14052         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
14053                 return OP_X86_COMPARE_MEMBASE8_IMM;
14054         */
14055
14056         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
14057                 return -1;
14058
14059         switch (opcode) {
14060         case OP_X86_PUSH:
14061                 return OP_X86_PUSH_MEMBASE;
14062         case OP_COMPARE_IMM:
14063         case OP_ICOMPARE_IMM:
14064                 return OP_X86_COMPARE_MEMBASE_IMM;
14065         case OP_COMPARE:
14066         case OP_ICOMPARE:
14067                 return OP_X86_COMPARE_MEMBASE_REG;
14068         }
14069 #endif
14070
14071 #ifdef TARGET_AMD64
14072         /* FIXME: This has sign extension issues */
14073         /*
14074         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
14075                 return OP_X86_COMPARE_MEMBASE8_IMM;
14076         */
14077
14078         switch (opcode) {
14079         case OP_X86_PUSH:
14080                 if ((load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32) || (load_opcode == OP_LOADI8_MEMBASE))
14081                         return OP_X86_PUSH_MEMBASE;
14082                 break;
14083                 /* FIXME: This only works for 32 bit immediates
14084         case OP_COMPARE_IMM:
14085         case OP_LCOMPARE_IMM:
14086                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
14087                         return OP_AMD64_COMPARE_MEMBASE_IMM;
14088                 */
14089         case OP_ICOMPARE_IMM:
14090                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
14091                         return OP_AMD64_ICOMPARE_MEMBASE_IMM;
14092                 break;
14093         case OP_COMPARE:
14094         case OP_LCOMPARE:
14095                 if (cfg->backend->ilp32 && load_opcode == OP_LOAD_MEMBASE)
14096                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
14097                 if ((load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32) || (load_opcode == OP_LOADI8_MEMBASE))
14098                         return OP_AMD64_COMPARE_MEMBASE_REG;
14099                 break;
14100         case OP_ICOMPARE:
14101                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
14102                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
14103                 break;
14104         }
14105 #endif
14106
14107         return -1;
14108 }
14109
14110 static inline int
14111 op_to_op_src2_membase (MonoCompile *cfg, int load_opcode, int opcode)
14112 {
14113 #ifdef TARGET_X86
14114         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
14115                 return -1;
14116         
14117         switch (opcode) {
14118         case OP_COMPARE:
14119         case OP_ICOMPARE:
14120                 return OP_X86_COMPARE_REG_MEMBASE;
14121         case OP_IADD:
14122                 return OP_X86_ADD_REG_MEMBASE;
14123         case OP_ISUB:
14124                 return OP_X86_SUB_REG_MEMBASE;
14125         case OP_IAND:
14126                 return OP_X86_AND_REG_MEMBASE;
14127         case OP_IOR:
14128                 return OP_X86_OR_REG_MEMBASE;
14129         case OP_IXOR:
14130                 return OP_X86_XOR_REG_MEMBASE;
14131         }
14132 #endif
14133
14134 #ifdef TARGET_AMD64
14135         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE && cfg->backend->ilp32)) {
14136                 switch (opcode) {
14137                 case OP_ICOMPARE:
14138                         return OP_AMD64_ICOMPARE_REG_MEMBASE;
14139                 case OP_IADD:
14140                         return OP_X86_ADD_REG_MEMBASE;
14141                 case OP_ISUB:
14142                         return OP_X86_SUB_REG_MEMBASE;
14143                 case OP_IAND:
14144                         return OP_X86_AND_REG_MEMBASE;
14145                 case OP_IOR:
14146                         return OP_X86_OR_REG_MEMBASE;
14147                 case OP_IXOR:
14148                         return OP_X86_XOR_REG_MEMBASE;
14149                 }
14150         } else if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32)) {
14151                 switch (opcode) {
14152                 case OP_COMPARE:
14153                 case OP_LCOMPARE:
14154                         return OP_AMD64_COMPARE_REG_MEMBASE;
14155                 case OP_LADD:
14156                         return OP_AMD64_ADD_REG_MEMBASE;
14157                 case OP_LSUB:
14158                         return OP_AMD64_SUB_REG_MEMBASE;
14159                 case OP_LAND:
14160                         return OP_AMD64_AND_REG_MEMBASE;
14161                 case OP_LOR:
14162                         return OP_AMD64_OR_REG_MEMBASE;
14163                 case OP_LXOR:
14164                         return OP_AMD64_XOR_REG_MEMBASE;
14165                 }
14166         }
14167 #endif
14168
14169         return -1;
14170 }
14171
14172 int
14173 mono_op_to_op_imm_noemul (int opcode)
14174 {
14175         switch (opcode) {
14176 #if SIZEOF_REGISTER == 4 && !defined(MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS)
14177         case OP_LSHR:
14178         case OP_LSHL:
14179         case OP_LSHR_UN:
14180                 return -1;
14181 #endif
14182 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
14183         case OP_IDIV:
14184         case OP_IDIV_UN:
14185         case OP_IREM:
14186         case OP_IREM_UN:
14187                 return -1;
14188 #endif
14189 #if defined(MONO_ARCH_EMULATE_MUL_DIV)
14190         case OP_IMUL:
14191                 return -1;
14192 #endif
14193         default:
14194                 return mono_op_to_op_imm (opcode);
14195         }
14196 }
14197
14198 /**
14199  * mono_handle_global_vregs:
14200  *
14201  *   Make vregs used in more than one bblock 'global', i.e. allocate a variable
14202  * for them.
14203  */
14204 void
14205 mono_handle_global_vregs (MonoCompile *cfg)
14206 {
14207         gint32 *vreg_to_bb;
14208         MonoBasicBlock *bb;
14209         int i, pos;
14210
14211         vreg_to_bb = (gint32 *)mono_mempool_alloc0 (cfg->mempool, sizeof (gint32*) * cfg->next_vreg + 1);
14212
14213 #ifdef MONO_ARCH_SIMD_INTRINSICS
14214         if (cfg->uses_simd_intrinsics)
14215                 mono_simd_simplify_indirection (cfg);
14216 #endif
14217
14218         /* Find local vregs used in more than one bb */
14219         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
14220                 MonoInst *ins = bb->code;       
14221                 int block_num = bb->block_num;
14222
14223                 if (cfg->verbose_level > 2)
14224                         printf ("\nHANDLE-GLOBAL-VREGS BLOCK %d:\n", bb->block_num);
14225
14226                 cfg->cbb = bb;
14227                 for (; ins; ins = ins->next) {
14228                         const char *spec = INS_INFO (ins->opcode);
14229                         int regtype = 0, regindex;
14230                         gint32 prev_bb;
14231
14232                         if (G_UNLIKELY (cfg->verbose_level > 2))
14233                                 mono_print_ins (ins);
14234
14235                         g_assert (ins->opcode >= MONO_CEE_LAST);
14236
14237                         for (regindex = 0; regindex < 4; regindex ++) {
14238                                 int vreg = 0;
14239
14240                                 if (regindex == 0) {
14241                                         regtype = spec [MONO_INST_DEST];
14242                                         if (regtype == ' ')
14243                                                 continue;
14244                                         vreg = ins->dreg;
14245                                 } else if (regindex == 1) {
14246                                         regtype = spec [MONO_INST_SRC1];
14247                                         if (regtype == ' ')
14248                                                 continue;
14249                                         vreg = ins->sreg1;
14250                                 } else if (regindex == 2) {
14251                                         regtype = spec [MONO_INST_SRC2];
14252                                         if (regtype == ' ')
14253                                                 continue;
14254                                         vreg = ins->sreg2;
14255                                 } else if (regindex == 3) {
14256                                         regtype = spec [MONO_INST_SRC3];
14257                                         if (regtype == ' ')
14258                                                 continue;
14259                                         vreg = ins->sreg3;
14260                                 }
14261
14262 #if SIZEOF_REGISTER == 4
14263                                 /* In the LLVM case, the long opcodes are not decomposed */
14264                                 if (regtype == 'l' && !COMPILE_LLVM (cfg)) {
14265                                         /*
14266                                          * Since some instructions reference the original long vreg,
14267                                          * and some reference the two component vregs, it is quite hard
14268                                          * to determine when it needs to be global. So be conservative.
14269                                          */
14270                                         if (!get_vreg_to_inst (cfg, vreg)) {
14271                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
14272
14273                                                 if (cfg->verbose_level > 2)
14274                                                         printf ("LONG VREG R%d made global.\n", vreg);
14275                                         }
14276
14277                                         /*
14278                                          * Make the component vregs volatile since the optimizations can
14279                                          * get confused otherwise.
14280                                          */
14281                                         get_vreg_to_inst (cfg, MONO_LVREG_LS (vreg))->flags |= MONO_INST_VOLATILE;
14282                                         get_vreg_to_inst (cfg, MONO_LVREG_MS (vreg))->flags |= MONO_INST_VOLATILE;
14283                                 }
14284 #endif
14285
14286                                 g_assert (vreg != -1);
14287
14288                                 prev_bb = vreg_to_bb [vreg];
14289                                 if (prev_bb == 0) {
14290                                         /* 0 is a valid block num */
14291                                         vreg_to_bb [vreg] = block_num + 1;
14292                                 } else if ((prev_bb != block_num + 1) && (prev_bb != -1)) {
14293                                         if (((regtype == 'i' && (vreg < MONO_MAX_IREGS))) || (regtype == 'f' && (vreg < MONO_MAX_FREGS)))
14294                                                 continue;
14295
14296                                         if (!get_vreg_to_inst (cfg, vreg)) {
14297                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
14298                                                         printf ("VREG R%d used in BB%d and BB%d made global.\n", vreg, vreg_to_bb [vreg], block_num);
14299
14300                                                 switch (regtype) {
14301                                                 case 'i':
14302                                                         if (vreg_is_ref (cfg, vreg))
14303                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL, vreg);
14304                                                         else
14305                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL, vreg);
14306                                                         break;
14307                                                 case 'l':
14308                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
14309                                                         break;
14310                                                 case 'f':
14311                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL, vreg);
14312                                                         break;
14313                                                 case 'v':
14314                                                         mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, vreg);
14315                                                         break;
14316                                                 default:
14317                                                         g_assert_not_reached ();
14318                                                 }
14319                                         }
14320
14321                                         /* Flag as having been used in more than one bb */
14322                                         vreg_to_bb [vreg] = -1;
14323                                 }
14324                         }
14325                 }
14326         }
14327
14328         /* If a variable is used in only one bblock, convert it into a local vreg */
14329         for (i = 0; i < cfg->num_varinfo; i++) {
14330                 MonoInst *var = cfg->varinfo [i];
14331                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
14332
14333                 switch (var->type) {
14334                 case STACK_I4:
14335                 case STACK_OBJ:
14336                 case STACK_PTR:
14337                 case STACK_MP:
14338                 case STACK_VTYPE:
14339 #if SIZEOF_REGISTER == 8
14340                 case STACK_I8:
14341 #endif
14342 #if !defined(TARGET_X86)
14343                 /* Enabling this screws up the fp stack on x86 */
14344                 case STACK_R8:
14345 #endif
14346                         if (mono_arch_is_soft_float ())
14347                                 break;
14348
14349                         /*
14350                         if (var->type == STACK_VTYPE && cfg->gsharedvt && mini_is_gsharedvt_variable_type (var->inst_vtype))
14351                                 break;
14352                         */
14353
14354                         /* Arguments are implicitly global */
14355                         /* Putting R4 vars into registers doesn't work currently */
14356                         /* The gsharedvt vars are implicitly referenced by ldaddr opcodes, but those opcodes are only generated later */
14357                         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) {
14358                                 /* 
14359                                  * Make that the variable's liveness interval doesn't contain a call, since
14360                                  * that would cause the lvreg to be spilled, making the whole optimization
14361                                  * useless.
14362                                  */
14363                                 /* This is too slow for JIT compilation */
14364 #if 0
14365                                 if (cfg->compile_aot && vreg_to_bb [var->dreg]) {
14366                                         MonoInst *ins;
14367                                         int def_index, call_index, ins_index;
14368                                         gboolean spilled = FALSE;
14369
14370                                         def_index = -1;
14371                                         call_index = -1;
14372                                         ins_index = 0;
14373                                         for (ins = vreg_to_bb [var->dreg]->code; ins; ins = ins->next) {
14374                                                 const char *spec = INS_INFO (ins->opcode);
14375
14376                                                 if ((spec [MONO_INST_DEST] != ' ') && (ins->dreg == var->dreg))
14377                                                         def_index = ins_index;
14378
14379                                                 if (((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg)) ||
14380                                                         ((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg))) {
14381                                                         if (call_index > def_index) {
14382                                                                 spilled = TRUE;
14383                                                                 break;
14384                                                         }
14385                                                 }
14386
14387                                                 if (MONO_IS_CALL (ins))
14388                                                         call_index = ins_index;
14389
14390                                                 ins_index ++;
14391                                         }
14392
14393                                         if (spilled)
14394                                                 break;
14395                                 }
14396 #endif
14397
14398                                 if (G_UNLIKELY (cfg->verbose_level > 2))
14399                                         printf ("CONVERTED R%d(%d) TO VREG.\n", var->dreg, vmv->idx);
14400                                 var->flags |= MONO_INST_IS_DEAD;
14401                                 cfg->vreg_to_inst [var->dreg] = NULL;
14402                         }
14403                         break;
14404                 }
14405         }
14406
14407         /* 
14408          * Compress the varinfo and vars tables so the liveness computation is faster and
14409          * takes up less space.
14410          */
14411         pos = 0;
14412         for (i = 0; i < cfg->num_varinfo; ++i) {
14413                 MonoInst *var = cfg->varinfo [i];
14414                 if (pos < i && cfg->locals_start == i)
14415                         cfg->locals_start = pos;
14416                 if (!(var->flags & MONO_INST_IS_DEAD)) {
14417                         if (pos < i) {
14418                                 cfg->varinfo [pos] = cfg->varinfo [i];
14419                                 cfg->varinfo [pos]->inst_c0 = pos;
14420                                 memcpy (&cfg->vars [pos], &cfg->vars [i], sizeof (MonoMethodVar));
14421                                 cfg->vars [pos].idx = pos;
14422 #if SIZEOF_REGISTER == 4
14423                                 if (cfg->varinfo [pos]->type == STACK_I8) {
14424                                         /* Modify the two component vars too */
14425                                         MonoInst *var1;
14426
14427                                         var1 = get_vreg_to_inst (cfg, MONO_LVREG_LS (cfg->varinfo [pos]->dreg));
14428                                         var1->inst_c0 = pos;
14429                                         var1 = get_vreg_to_inst (cfg, MONO_LVREG_MS (cfg->varinfo [pos]->dreg));
14430                                         var1->inst_c0 = pos;
14431                                 }
14432 #endif
14433                         }
14434                         pos ++;
14435                 }
14436         }
14437         cfg->num_varinfo = pos;
14438         if (cfg->locals_start > cfg->num_varinfo)
14439                 cfg->locals_start = cfg->num_varinfo;
14440 }
14441
14442 /*
14443  * mono_allocate_gsharedvt_vars:
14444  *
14445  *   Allocate variables with gsharedvt types to entries in the MonoGSharedVtMethodRuntimeInfo.entries array.
14446  * Initialize cfg->gsharedvt_vreg_to_idx with the mapping between vregs and indexes.
14447  */
14448 void
14449 mono_allocate_gsharedvt_vars (MonoCompile *cfg)
14450 {
14451         int i;
14452
14453         cfg->gsharedvt_vreg_to_idx = (int *)mono_mempool_alloc0 (cfg->mempool, sizeof (int) * cfg->next_vreg);
14454
14455         for (i = 0; i < cfg->num_varinfo; ++i) {
14456                 MonoInst *ins = cfg->varinfo [i];
14457                 int idx;
14458
14459                 if (mini_is_gsharedvt_variable_type (ins->inst_vtype)) {
14460                         if (i >= cfg->locals_start) {
14461                                 /* Local */
14462                                 idx = get_gsharedvt_info_slot (cfg, ins->inst_vtype, MONO_RGCTX_INFO_LOCAL_OFFSET);
14463                                 cfg->gsharedvt_vreg_to_idx [ins->dreg] = idx + 1;
14464                                 ins->opcode = OP_GSHAREDVT_LOCAL;
14465                                 ins->inst_imm = idx;
14466                         } else {
14467                                 /* Arg */
14468                                 cfg->gsharedvt_vreg_to_idx [ins->dreg] = -1;
14469                                 ins->opcode = OP_GSHAREDVT_ARG_REGOFFSET;
14470                         }
14471                 }
14472         }
14473 }
14474
14475 /**
14476  * mono_spill_global_vars:
14477  *
14478  *   Generate spill code for variables which are not allocated to registers, 
14479  * and replace vregs with their allocated hregs. *need_local_opts is set to TRUE if
14480  * code is generated which could be optimized by the local optimization passes.
14481  */
14482 void
14483 mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
14484 {
14485         MonoBasicBlock *bb;
14486         char spec2 [16];
14487         int orig_next_vreg;
14488         guint32 *vreg_to_lvreg;
14489         guint32 *lvregs;
14490         guint32 i, lvregs_len;
14491         gboolean dest_has_lvreg = FALSE;
14492         MonoStackType stacktypes [128];
14493         MonoInst **live_range_start, **live_range_end;
14494         MonoBasicBlock **live_range_start_bb, **live_range_end_bb;
14495
14496         *need_local_opts = FALSE;
14497
14498         memset (spec2, 0, sizeof (spec2));
14499
14500         /* FIXME: Move this function to mini.c */
14501         stacktypes ['i'] = STACK_PTR;
14502         stacktypes ['l'] = STACK_I8;
14503         stacktypes ['f'] = STACK_R8;
14504 #ifdef MONO_ARCH_SIMD_INTRINSICS
14505         stacktypes ['x'] = STACK_VTYPE;
14506 #endif
14507
14508 #if SIZEOF_REGISTER == 4
14509         /* Create MonoInsts for longs */
14510         for (i = 0; i < cfg->num_varinfo; i++) {
14511                 MonoInst *ins = cfg->varinfo [i];
14512
14513                 if ((ins->opcode != OP_REGVAR) && !(ins->flags & MONO_INST_IS_DEAD)) {
14514                         switch (ins->type) {
14515                         case STACK_R8:
14516                         case STACK_I8: {
14517                                 MonoInst *tree;
14518
14519                                 if (ins->type == STACK_R8 && !COMPILE_SOFT_FLOAT (cfg))
14520                                         break;
14521
14522                                 g_assert (ins->opcode == OP_REGOFFSET);
14523
14524                                 tree = get_vreg_to_inst (cfg, MONO_LVREG_LS (ins->dreg));
14525                                 g_assert (tree);
14526                                 tree->opcode = OP_REGOFFSET;
14527                                 tree->inst_basereg = ins->inst_basereg;
14528                                 tree->inst_offset = ins->inst_offset + MINI_LS_WORD_OFFSET;
14529
14530                                 tree = get_vreg_to_inst (cfg, MONO_LVREG_MS (ins->dreg));
14531                                 g_assert (tree);
14532                                 tree->opcode = OP_REGOFFSET;
14533                                 tree->inst_basereg = ins->inst_basereg;
14534                                 tree->inst_offset = ins->inst_offset + MINI_MS_WORD_OFFSET;
14535                                 break;
14536                         }
14537                         default:
14538                                 break;
14539                         }
14540                 }
14541         }
14542 #endif
14543
14544         if (cfg->compute_gc_maps) {
14545                 /* registers need liveness info even for !non refs */
14546                 for (i = 0; i < cfg->num_varinfo; i++) {
14547                         MonoInst *ins = cfg->varinfo [i];
14548
14549                         if (ins->opcode == OP_REGVAR)
14550                                 ins->flags |= MONO_INST_GC_TRACK;
14551                 }
14552         }
14553                 
14554         /* FIXME: widening and truncation */
14555
14556         /*
14557          * As an optimization, when a variable allocated to the stack is first loaded into 
14558          * an lvreg, we will remember the lvreg and use it the next time instead of loading
14559          * the variable again.
14560          */
14561         orig_next_vreg = cfg->next_vreg;
14562         vreg_to_lvreg = (guint32 *)mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * cfg->next_vreg);
14563         lvregs = (guint32 *)mono_mempool_alloc (cfg->mempool, sizeof (guint32) * 1024);
14564         lvregs_len = 0;
14565
14566         /* 
14567          * These arrays contain the first and last instructions accessing a given
14568          * variable.
14569          * Since we emit bblocks in the same order we process them here, and we
14570          * don't split live ranges, these will precisely describe the live range of
14571          * the variable, i.e. the instruction range where a valid value can be found
14572          * in the variables location.
14573          * The live range is computed using the liveness info computed by the liveness pass.
14574          * We can't use vmv->range, since that is an abstract live range, and we need
14575          * one which is instruction precise.
14576          * FIXME: Variables used in out-of-line bblocks have a hole in their live range.
14577          */
14578         /* FIXME: Only do this if debugging info is requested */
14579         live_range_start = g_new0 (MonoInst*, cfg->next_vreg);
14580         live_range_end = g_new0 (MonoInst*, cfg->next_vreg);
14581         live_range_start_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
14582         live_range_end_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
14583         
14584         /* Add spill loads/stores */
14585         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
14586                 MonoInst *ins;
14587
14588                 if (cfg->verbose_level > 2)
14589                         printf ("\nSPILL BLOCK %d:\n", bb->block_num);
14590
14591                 /* Clear vreg_to_lvreg array */
14592                 for (i = 0; i < lvregs_len; i++)
14593                         vreg_to_lvreg [lvregs [i]] = 0;
14594                 lvregs_len = 0;
14595
14596                 cfg->cbb = bb;
14597                 MONO_BB_FOR_EACH_INS (bb, ins) {
14598                         const char *spec = INS_INFO (ins->opcode);
14599                         int regtype, srcindex, sreg, tmp_reg, prev_dreg, num_sregs;
14600                         gboolean store, no_lvreg;
14601                         int sregs [MONO_MAX_SRC_REGS];
14602
14603                         if (G_UNLIKELY (cfg->verbose_level > 2))
14604                                 mono_print_ins (ins);
14605
14606                         if (ins->opcode == OP_NOP)
14607                                 continue;
14608
14609                         /* 
14610                          * We handle LDADDR here as well, since it can only be decomposed
14611                          * when variable addresses are known.
14612                          */
14613                         if (ins->opcode == OP_LDADDR) {
14614                                 MonoInst *var = (MonoInst *)ins->inst_p0;
14615
14616                                 if (var->opcode == OP_VTARG_ADDR) {
14617                                         /* Happens on SPARC/S390 where vtypes are passed by reference */
14618                                         MonoInst *vtaddr = var->inst_left;
14619                                         if (vtaddr->opcode == OP_REGVAR) {
14620                                                 ins->opcode = OP_MOVE;
14621                                                 ins->sreg1 = vtaddr->dreg;
14622                                         }
14623                                         else if (var->inst_left->opcode == OP_REGOFFSET) {
14624                                                 ins->opcode = OP_LOAD_MEMBASE;
14625                                                 ins->inst_basereg = vtaddr->inst_basereg;
14626                                                 ins->inst_offset = vtaddr->inst_offset;
14627                                         } else
14628                                                 NOT_IMPLEMENTED;
14629                                 } else if (cfg->gsharedvt && cfg->gsharedvt_vreg_to_idx [var->dreg] < 0) {
14630                                         /* gsharedvt arg passed by ref */
14631                                         g_assert (var->opcode == OP_GSHAREDVT_ARG_REGOFFSET);
14632
14633                                         ins->opcode = OP_LOAD_MEMBASE;
14634                                         ins->inst_basereg = var->inst_basereg;
14635                                         ins->inst_offset = var->inst_offset;
14636                                 } else if (cfg->gsharedvt && cfg->gsharedvt_vreg_to_idx [var->dreg]) {
14637                                         MonoInst *load, *load2, *load3;
14638                                         int idx = cfg->gsharedvt_vreg_to_idx [var->dreg] - 1;
14639                                         int reg1, reg2, reg3;
14640                                         MonoInst *info_var = cfg->gsharedvt_info_var;
14641                                         MonoInst *locals_var = cfg->gsharedvt_locals_var;
14642
14643                                         /*
14644                                          * gsharedvt local.
14645                                          * Compute the address of the local as gsharedvt_locals_var + gsharedvt_info_var->locals_offsets [idx].
14646                                          */
14647
14648                                         g_assert (var->opcode == OP_GSHAREDVT_LOCAL);
14649
14650                                         g_assert (info_var);
14651                                         g_assert (locals_var);
14652
14653                                         /* Mark the instruction used to compute the locals var as used */
14654                                         cfg->gsharedvt_locals_var_ins = NULL;
14655
14656                                         /* Load the offset */
14657                                         if (info_var->opcode == OP_REGOFFSET) {
14658                                                 reg1 = alloc_ireg (cfg);
14659                                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, reg1, info_var->inst_basereg, info_var->inst_offset);
14660                                         } else if (info_var->opcode == OP_REGVAR) {
14661                                                 load = NULL;
14662                                                 reg1 = info_var->dreg;
14663                                         } else {
14664                                                 g_assert_not_reached ();
14665                                         }
14666                                         reg2 = alloc_ireg (cfg);
14667                                         NEW_LOAD_MEMBASE (cfg, load2, OP_LOADI4_MEMBASE, reg2, reg1, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
14668                                         /* Load the locals area address */
14669                                         reg3 = alloc_ireg (cfg);
14670                                         if (locals_var->opcode == OP_REGOFFSET) {
14671                                                 NEW_LOAD_MEMBASE (cfg, load3, OP_LOAD_MEMBASE, reg3, locals_var->inst_basereg, locals_var->inst_offset);
14672                                         } else if (locals_var->opcode == OP_REGVAR) {
14673                                                 NEW_UNALU (cfg, load3, OP_MOVE, reg3, locals_var->dreg);
14674                                         } else {
14675                                                 g_assert_not_reached ();
14676                                         }
14677                                         /* Compute the address */
14678                                         ins->opcode = OP_PADD;
14679                                         ins->sreg1 = reg3;
14680                                         ins->sreg2 = reg2;
14681
14682                                         mono_bblock_insert_before_ins (bb, ins, load3);
14683                                         mono_bblock_insert_before_ins (bb, load3, load2);
14684                                         if (load)
14685                                                 mono_bblock_insert_before_ins (bb, load2, load);
14686                                 } else {
14687                                         g_assert (var->opcode == OP_REGOFFSET);
14688
14689                                         ins->opcode = OP_ADD_IMM;
14690                                         ins->sreg1 = var->inst_basereg;
14691                                         ins->inst_imm = var->inst_offset;
14692                                 }
14693
14694                                 *need_local_opts = TRUE;
14695                                 spec = INS_INFO (ins->opcode);
14696                         }
14697
14698                         if (ins->opcode < MONO_CEE_LAST) {
14699                                 mono_print_ins (ins);
14700                                 g_assert_not_reached ();
14701                         }
14702
14703                         /*
14704                          * Store opcodes have destbasereg in the dreg, but in reality, it is an
14705                          * src register.
14706                          * FIXME:
14707                          */
14708                         if (MONO_IS_STORE_MEMBASE (ins)) {
14709                                 tmp_reg = ins->dreg;
14710                                 ins->dreg = ins->sreg2;
14711                                 ins->sreg2 = tmp_reg;
14712                                 store = TRUE;
14713
14714                                 spec2 [MONO_INST_DEST] = ' ';
14715                                 spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14716                                 spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14717                                 spec2 [MONO_INST_SRC3] = ' ';
14718                                 spec = spec2;
14719                         } else if (MONO_IS_STORE_MEMINDEX (ins))
14720                                 g_assert_not_reached ();
14721                         else
14722                                 store = FALSE;
14723                         no_lvreg = FALSE;
14724
14725                         if (G_UNLIKELY (cfg->verbose_level > 2)) {
14726                                 printf ("\t %.3s %d", spec, ins->dreg);
14727                                 num_sregs = mono_inst_get_src_registers (ins, sregs);
14728                                 for (srcindex = 0; srcindex < num_sregs; ++srcindex)
14729                                         printf (" %d", sregs [srcindex]);
14730                                 printf ("\n");
14731                         }
14732
14733                         /***************/
14734                         /*    DREG     */
14735                         /***************/
14736                         regtype = spec [MONO_INST_DEST];
14737                         g_assert (((ins->dreg == -1) && (regtype == ' ')) || ((ins->dreg != -1) && (regtype != ' ')));
14738                         prev_dreg = -1;
14739
14740                         if ((ins->dreg != -1) && get_vreg_to_inst (cfg, ins->dreg)) {
14741                                 MonoInst *var = get_vreg_to_inst (cfg, ins->dreg);
14742                                 MonoInst *store_ins;
14743                                 int store_opcode;
14744                                 MonoInst *def_ins = ins;
14745                                 int dreg = ins->dreg; /* The original vreg */
14746
14747                                 store_opcode = mono_type_to_store_membase (cfg, var->inst_vtype);
14748
14749                                 if (var->opcode == OP_REGVAR) {
14750                                         ins->dreg = var->dreg;
14751                                 } 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)) {
14752                                         /* 
14753                                          * Instead of emitting a load+store, use a _membase opcode.
14754                                          */
14755                                         g_assert (var->opcode == OP_REGOFFSET);
14756                                         if (ins->opcode == OP_MOVE) {
14757                                                 NULLIFY_INS (ins);
14758                                                 def_ins = NULL;
14759                                         } else {
14760                                                 ins->opcode = op_to_op_dest_membase (store_opcode, ins->opcode);
14761                                                 ins->inst_basereg = var->inst_basereg;
14762                                                 ins->inst_offset = var->inst_offset;
14763                                                 ins->dreg = -1;
14764                                         }
14765                                         spec = INS_INFO (ins->opcode);
14766                                 } else {
14767                                         guint32 lvreg;
14768
14769                                         g_assert (var->opcode == OP_REGOFFSET);
14770
14771                                         prev_dreg = ins->dreg;
14772
14773                                         /* Invalidate any previous lvreg for this vreg */
14774                                         vreg_to_lvreg [ins->dreg] = 0;
14775
14776                                         lvreg = 0;
14777
14778                                         if (COMPILE_SOFT_FLOAT (cfg) && store_opcode == OP_STORER8_MEMBASE_REG) {
14779                                                 regtype = 'l';
14780                                                 store_opcode = OP_STOREI8_MEMBASE_REG;
14781                                         }
14782
14783                                         ins->dreg = alloc_dreg (cfg, stacktypes [regtype]);
14784
14785 #if SIZEOF_REGISTER != 8
14786                                         if (regtype == 'l') {
14787                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET, MONO_LVREG_LS (ins->dreg));
14788                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14789                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET, MONO_LVREG_MS (ins->dreg));
14790                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14791                                                 def_ins = store_ins;
14792                                         }
14793                                         else
14794 #endif
14795                                         {
14796                                                 g_assert (store_opcode != OP_STOREV_MEMBASE);
14797
14798                                                 /* Try to fuse the store into the instruction itself */
14799                                                 /* FIXME: Add more instructions */
14800                                                 if (!lvreg && ((ins->opcode == OP_ICONST) || ((ins->opcode == OP_I8CONST) && (ins->inst_c0 == 0)))) {
14801                                                         ins->opcode = store_membase_reg_to_store_membase_imm (store_opcode);
14802                                                         ins->inst_imm = ins->inst_c0;
14803                                                         ins->inst_destbasereg = var->inst_basereg;
14804                                                         ins->inst_offset = var->inst_offset;
14805                                                         spec = INS_INFO (ins->opcode);
14806                                                 } else if (!lvreg && ((ins->opcode == OP_MOVE) || (ins->opcode == OP_FMOVE) || (ins->opcode == OP_LMOVE) || (ins->opcode == OP_RMOVE))) {
14807                                                         ins->opcode = store_opcode;
14808                                                         ins->inst_destbasereg = var->inst_basereg;
14809                                                         ins->inst_offset = var->inst_offset;
14810
14811                                                         no_lvreg = TRUE;
14812
14813                                                         tmp_reg = ins->dreg;
14814                                                         ins->dreg = ins->sreg2;
14815                                                         ins->sreg2 = tmp_reg;
14816                                                         store = TRUE;
14817
14818                                                         spec2 [MONO_INST_DEST] = ' ';
14819                                                         spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14820                                                         spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14821                                                         spec2 [MONO_INST_SRC3] = ' ';
14822                                                         spec = spec2;
14823                                                 } else if (!lvreg && (op_to_op_store_membase (store_opcode, ins->opcode) != -1)) {
14824                                                         // FIXME: The backends expect the base reg to be in inst_basereg
14825                                                         ins->opcode = op_to_op_store_membase (store_opcode, ins->opcode);
14826                                                         ins->dreg = -1;
14827                                                         ins->inst_basereg = var->inst_basereg;
14828                                                         ins->inst_offset = var->inst_offset;
14829                                                         spec = INS_INFO (ins->opcode);
14830                                                 } else {
14831                                                         /* printf ("INS: "); mono_print_ins (ins); */
14832                                                         /* Create a store instruction */
14833                                                         NEW_STORE_MEMBASE (cfg, store_ins, store_opcode, var->inst_basereg, var->inst_offset, ins->dreg);
14834
14835                                                         /* Insert it after the instruction */
14836                                                         mono_bblock_insert_after_ins (bb, ins, store_ins);
14837
14838                                                         def_ins = store_ins;
14839
14840                                                         /* 
14841                                                          * We can't assign ins->dreg to var->dreg here, since the
14842                                                          * sregs could use it. So set a flag, and do it after
14843                                                          * the sregs.
14844                                                          */
14845                                                         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)))
14846                                                                 dest_has_lvreg = TRUE;
14847                                                 }
14848                                         }
14849                                 }
14850
14851                                 if (def_ins && !live_range_start [dreg]) {
14852                                         live_range_start [dreg] = def_ins;
14853                                         live_range_start_bb [dreg] = bb;
14854                                 }
14855
14856                                 if (cfg->compute_gc_maps && def_ins && (var->flags & MONO_INST_GC_TRACK)) {
14857                                         MonoInst *tmp;
14858
14859                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
14860                                         tmp->inst_c1 = dreg;
14861                                         mono_bblock_insert_after_ins (bb, def_ins, tmp);
14862                                 }
14863                         }
14864
14865                         /************/
14866                         /*  SREGS   */
14867                         /************/
14868                         num_sregs = mono_inst_get_src_registers (ins, sregs);
14869                         for (srcindex = 0; srcindex < 3; ++srcindex) {
14870                                 regtype = spec [MONO_INST_SRC1 + srcindex];
14871                                 sreg = sregs [srcindex];
14872
14873                                 g_assert (((sreg == -1) && (regtype == ' ')) || ((sreg != -1) && (regtype != ' ')));
14874                                 if ((sreg != -1) && get_vreg_to_inst (cfg, sreg)) {
14875                                         MonoInst *var = get_vreg_to_inst (cfg, sreg);
14876                                         MonoInst *use_ins = ins;
14877                                         MonoInst *load_ins;
14878                                         guint32 load_opcode;
14879
14880                                         if (var->opcode == OP_REGVAR) {
14881                                                 sregs [srcindex] = var->dreg;
14882                                                 //mono_inst_set_src_registers (ins, sregs);
14883                                                 live_range_end [sreg] = use_ins;
14884                                                 live_range_end_bb [sreg] = bb;
14885
14886                                                 if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14887                                                         MonoInst *tmp;
14888
14889                                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14890                                                         /* var->dreg is a hreg */
14891                                                         tmp->inst_c1 = sreg;
14892                                                         mono_bblock_insert_after_ins (bb, ins, tmp);
14893                                                 }
14894
14895                                                 continue;
14896                                         }
14897
14898                                         g_assert (var->opcode == OP_REGOFFSET);
14899                                                 
14900                                         load_opcode = mono_type_to_load_membase (cfg, var->inst_vtype);
14901
14902                                         g_assert (load_opcode != OP_LOADV_MEMBASE);
14903
14904                                         if (vreg_to_lvreg [sreg]) {
14905                                                 g_assert (vreg_to_lvreg [sreg] != -1);
14906
14907                                                 /* The variable is already loaded to an lvreg */
14908                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
14909                                                         printf ("\t\tUse lvreg R%d for R%d.\n", vreg_to_lvreg [sreg], sreg);
14910                                                 sregs [srcindex] = vreg_to_lvreg [sreg];
14911                                                 //mono_inst_set_src_registers (ins, sregs);
14912                                                 continue;
14913                                         }
14914
14915                                         /* Try to fuse the load into the instruction */
14916                                         if ((srcindex == 0) && (op_to_op_src1_membase (cfg, load_opcode, ins->opcode) != -1)) {
14917                                                 ins->opcode = op_to_op_src1_membase (cfg, load_opcode, ins->opcode);
14918                                                 sregs [0] = var->inst_basereg;
14919                                                 //mono_inst_set_src_registers (ins, sregs);
14920                                                 ins->inst_offset = var->inst_offset;
14921                                         } else if ((srcindex == 1) && (op_to_op_src2_membase (cfg, load_opcode, ins->opcode) != -1)) {
14922                                                 ins->opcode = op_to_op_src2_membase (cfg, load_opcode, ins->opcode);
14923                                                 sregs [1] = var->inst_basereg;
14924                                                 //mono_inst_set_src_registers (ins, sregs);
14925                                                 ins->inst_offset = var->inst_offset;
14926                                         } else {
14927                                                 if (MONO_IS_REAL_MOVE (ins)) {
14928                                                         ins->opcode = OP_NOP;
14929                                                         sreg = ins->dreg;
14930                                                 } else {
14931                                                         //printf ("%d ", srcindex); mono_print_ins (ins);
14932
14933                                                         sreg = alloc_dreg (cfg, stacktypes [regtype]);
14934
14935                                                         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) {
14936                                                                 if (var->dreg == prev_dreg) {
14937                                                                         /*
14938                                                                          * sreg refers to the value loaded by the load
14939                                                                          * emitted below, but we need to use ins->dreg
14940                                                                          * since it refers to the store emitted earlier.
14941                                                                          */
14942                                                                         sreg = ins->dreg;
14943                                                                 }
14944                                                                 g_assert (sreg != -1);
14945                                                                 vreg_to_lvreg [var->dreg] = sreg;
14946                                                                 g_assert (lvregs_len < 1024);
14947                                                                 lvregs [lvregs_len ++] = var->dreg;
14948                                                         }
14949                                                 }
14950
14951                                                 sregs [srcindex] = sreg;
14952                                                 //mono_inst_set_src_registers (ins, sregs);
14953
14954 #if SIZEOF_REGISTER != 8
14955                                                 if (regtype == 'l') {
14956                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, MONO_LVREG_MS (sreg), var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET);
14957                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14958                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, MONO_LVREG_LS (sreg), var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET);
14959                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14960                                                         use_ins = load_ins;
14961                                                 }
14962                                                 else
14963 #endif
14964                                                 {
14965 #if SIZEOF_REGISTER == 4
14966                                                         g_assert (load_opcode != OP_LOADI8_MEMBASE);
14967 #endif
14968                                                         NEW_LOAD_MEMBASE (cfg, load_ins, load_opcode, sreg, var->inst_basereg, var->inst_offset);
14969                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14970                                                         use_ins = load_ins;
14971                                                 }
14972                                         }
14973
14974                                         if (var->dreg < orig_next_vreg) {
14975                                                 live_range_end [var->dreg] = use_ins;
14976                                                 live_range_end_bb [var->dreg] = bb;
14977                                         }
14978
14979                                         if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14980                                                 MonoInst *tmp;
14981
14982                                                 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14983                                                 tmp->inst_c1 = var->dreg;
14984                                                 mono_bblock_insert_after_ins (bb, ins, tmp);
14985                                         }
14986                                 }
14987                         }
14988                         mono_inst_set_src_registers (ins, sregs);
14989
14990                         if (dest_has_lvreg) {
14991                                 g_assert (ins->dreg != -1);
14992                                 vreg_to_lvreg [prev_dreg] = ins->dreg;
14993                                 g_assert (lvregs_len < 1024);
14994                                 lvregs [lvregs_len ++] = prev_dreg;
14995                                 dest_has_lvreg = FALSE;
14996                         }
14997
14998                         if (store) {
14999                                 tmp_reg = ins->dreg;
15000                                 ins->dreg = ins->sreg2;
15001                                 ins->sreg2 = tmp_reg;
15002                         }
15003
15004                         if (MONO_IS_CALL (ins)) {
15005                                 /* Clear vreg_to_lvreg array */
15006                                 for (i = 0; i < lvregs_len; i++)
15007                                         vreg_to_lvreg [lvregs [i]] = 0;
15008                                 lvregs_len = 0;
15009                         } else if (ins->opcode == OP_NOP) {
15010                                 ins->dreg = -1;
15011                                 MONO_INST_NULLIFY_SREGS (ins);
15012                         }
15013
15014                         if (cfg->verbose_level > 2)
15015                                 mono_print_ins_index (1, ins);
15016                 }
15017
15018                 /* Extend the live range based on the liveness info */
15019                 if (cfg->compute_precise_live_ranges && bb->live_out_set && bb->code) {
15020                         for (i = 0; i < cfg->num_varinfo; i ++) {
15021                                 MonoMethodVar *vi = MONO_VARINFO (cfg, i);
15022
15023                                 if (vreg_is_volatile (cfg, vi->vreg))
15024                                         /* The liveness info is incomplete */
15025                                         continue;
15026
15027                                 if (mono_bitset_test_fast (bb->live_in_set, i) && !live_range_start [vi->vreg]) {
15028                                         /* Live from at least the first ins of this bb */
15029                                         live_range_start [vi->vreg] = bb->code;
15030                                         live_range_start_bb [vi->vreg] = bb;
15031                                 }
15032
15033                                 if (mono_bitset_test_fast (bb->live_out_set, i)) {
15034                                         /* Live at least until the last ins of this bb */
15035                                         live_range_end [vi->vreg] = bb->last_ins;
15036                                         live_range_end_bb [vi->vreg] = bb;
15037                                 }
15038                         }
15039                 }
15040         }
15041         
15042         /*
15043          * Emit LIVERANGE_START/LIVERANGE_END opcodes, the backend will implement them
15044          * by storing the current native offset into MonoMethodVar->live_range_start/end.
15045          */
15046         if (cfg->backend->have_liverange_ops && cfg->compute_precise_live_ranges && cfg->comp_done & MONO_COMP_LIVENESS) {
15047                 for (i = 0; i < cfg->num_varinfo; ++i) {
15048                         int vreg = MONO_VARINFO (cfg, i)->vreg;
15049                         MonoInst *ins;
15050
15051                         if (live_range_start [vreg]) {
15052                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_START);
15053                                 ins->inst_c0 = i;
15054                                 ins->inst_c1 = vreg;
15055                                 mono_bblock_insert_after_ins (live_range_start_bb [vreg], live_range_start [vreg], ins);
15056                         }
15057                         if (live_range_end [vreg]) {
15058                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_END);
15059                                 ins->inst_c0 = i;
15060                                 ins->inst_c1 = vreg;
15061                                 if (live_range_end [vreg] == live_range_end_bb [vreg]->last_ins)
15062                                         mono_add_ins_to_end (live_range_end_bb [vreg], ins);
15063                                 else
15064                                         mono_bblock_insert_after_ins (live_range_end_bb [vreg], live_range_end [vreg], ins);
15065                         }
15066                 }
15067         }
15068
15069         if (cfg->gsharedvt_locals_var_ins) {
15070                 /* Nullify if unused */
15071                 cfg->gsharedvt_locals_var_ins->opcode = OP_PCONST;
15072                 cfg->gsharedvt_locals_var_ins->inst_imm = 0;
15073         }
15074
15075         g_free (live_range_start);
15076         g_free (live_range_end);
15077         g_free (live_range_start_bb);
15078         g_free (live_range_end_bb);
15079 }
15080
15081 static void
15082 mono_decompose_typecheck (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins)
15083 {
15084         MonoInst *ret, *move, *source;
15085         MonoClass *klass = ins->klass;
15086         int context_used = mini_class_check_context_used (cfg, klass);
15087         int is_isinst = ins->opcode == OP_ISINST;
15088         g_assert (is_isinst || ins->opcode == OP_CASTCLASS);
15089         source = get_vreg_to_inst (cfg, ins->sreg1);
15090         if (!source || source == (MonoInst *) -1)
15091                 source = mono_compile_create_var_for_vreg (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL, ins->sreg1);
15092         g_assert (source && source != (MonoInst *) -1);
15093
15094         MonoBasicBlock *first_bb;
15095         NEW_BBLOCK (cfg, first_bb);
15096         cfg->cbb = first_bb;
15097
15098         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
15099                 if (is_isinst)
15100                         ret = emit_isinst_with_cache_nonshared (cfg, source, klass);
15101                 else
15102                         ret = emit_castclass_with_cache_nonshared (cfg, source, klass);
15103         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
15104                 MonoInst *iargs [1];
15105                 int costs;
15106
15107                 iargs [0] = source;
15108                 if (is_isinst) {
15109                         MonoMethod *wrapper = mono_marshal_get_isinst (klass);
15110                         costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), iargs, 0, 0, TRUE);
15111                 } else {
15112                         MonoMethod *wrapper = mono_marshal_get_castclass (klass);
15113                         save_cast_details (cfg, klass, source->dreg, TRUE);
15114                         costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), iargs, 0, 0, TRUE);
15115                         reset_cast_details (cfg);
15116                 }
15117                 g_assert (costs > 0);
15118                 ret = iargs [0];
15119         } else {
15120                 if (is_isinst)
15121                         ret = handle_isinst (cfg, klass, source, context_used);
15122                 else
15123                         ret = handle_castclass (cfg, klass, source, context_used);
15124         }
15125         EMIT_NEW_UNALU (cfg, move, OP_MOVE, ins->dreg, ret->dreg);
15126
15127         g_assert (cfg->cbb->code || first_bb->code);
15128         MonoInst *prev = ins->prev;
15129         mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
15130 }
15131
15132 void
15133 mono_decompose_typechecks (MonoCompile *cfg)
15134 {
15135         for (MonoBasicBlock *bb = cfg->bb_entry; bb; bb = bb->next_bb) {
15136                 MonoInst *ins;
15137                 MONO_BB_FOR_EACH_INS (bb, ins) {
15138                         switch (ins->opcode) {
15139                         case OP_ISINST:
15140                         case OP_CASTCLASS:
15141                                 mono_decompose_typecheck (cfg, bb, ins);
15142                                 break;
15143                         }
15144                 }
15145         }
15146 }
15147
15148
15149 /**
15150  * FIXME:
15151  * - use 'iadd' instead of 'int_add'
15152  * - handling ovf opcodes: decompose in method_to_ir.
15153  * - unify iregs/fregs
15154  *   -> partly done, the missing parts are:
15155  *   - a more complete unification would involve unifying the hregs as well, so
15156  *     code wouldn't need if (fp) all over the place. but that would mean the hregs
15157  *     would no longer map to the machine hregs, so the code generators would need to
15158  *     be modified. Also, on ia64 for example, niregs + nfregs > 256 -> bitmasks
15159  *     wouldn't work any more. Duplicating the code in mono_local_regalloc () into
15160  *     fp/non-fp branches speeds it up by about 15%.
15161  * - use sext/zext opcodes instead of shifts
15162  * - add OP_ICALL
15163  * - get rid of TEMPLOADs if possible and use vregs instead
15164  * - clean up usage of OP_P/OP_ opcodes
15165  * - cleanup usage of DUMMY_USE
15166  * - cleanup the setting of ins->type for MonoInst's which are pushed on the 
15167  *   stack
15168  * - set the stack type and allocate a dreg in the EMIT_NEW macros
15169  * - get rid of all the <foo>2 stuff when the new JIT is ready.
15170  * - make sure handle_stack_args () is called before the branch is emitted
15171  * - when the new IR is done, get rid of all unused stuff
15172  * - COMPARE/BEQ as separate instructions or unify them ?
15173  *   - keeping them separate allows specialized compare instructions like
15174  *     compare_imm, compare_membase
15175  *   - most back ends unify fp compare+branch, fp compare+ceq
15176  * - integrate mono_save_args into inline_method
15177  * - get rid of the empty bblocks created by MONO_EMIT_NEW_BRACH_BLOCK2
15178  * - handle long shift opts on 32 bit platforms somehow: they require 
15179  *   3 sregs (2 for arg1 and 1 for arg2)
15180  * - make byref a 'normal' type.
15181  * - use vregs for bb->out_stacks if possible, handle_global_vreg will make them a
15182  *   variable if needed.
15183  * - do not start a new IL level bblock when cfg->cbb is changed by a function call
15184  *   like inline_method.
15185  * - remove inlining restrictions
15186  * - fix LNEG and enable cfold of INEG
15187  * - generalize x86 optimizations like ldelema as a peephole optimization
15188  * - add store_mem_imm for amd64
15189  * - optimize the loading of the interruption flag in the managed->native wrappers
15190  * - avoid special handling of OP_NOP in passes
15191  * - move code inserting instructions into one function/macro.
15192  * - try a coalescing phase after liveness analysis
15193  * - add float -> vreg conversion + local optimizations on !x86
15194  * - figure out how to handle decomposed branches during optimizations, ie.
15195  *   compare+branch, op_jump_table+op_br etc.
15196  * - promote RuntimeXHandles to vregs
15197  * - vtype cleanups:
15198  *   - add a NEW_VARLOADA_VREG macro
15199  * - the vtype optimizations are blocked by the LDADDR opcodes generated for 
15200  *   accessing vtype fields.
15201  * - get rid of I8CONST on 64 bit platforms
15202  * - dealing with the increase in code size due to branches created during opcode
15203  *   decomposition:
15204  *   - use extended basic blocks
15205  *     - all parts of the JIT
15206  *     - handle_global_vregs () && local regalloc
15207  *   - avoid introducing global vregs during decomposition, like 'vtable' in isinst
15208  * - sources of increase in code size:
15209  *   - vtypes
15210  *   - long compares
15211  *   - isinst and castclass
15212  *   - lvregs not allocated to global registers even if used multiple times
15213  * - call cctors outside the JIT, to make -v output more readable and JIT timings more
15214  *   meaningful.
15215  * - check for fp stack leakage in other opcodes too. (-> 'exceptions' optimization)
15216  * - add all micro optimizations from the old JIT
15217  * - put tree optimizations into the deadce pass
15218  * - decompose op_start_handler/op_endfilter/op_endfinally earlier using an arch
15219  *   specific function.
15220  * - unify the float comparison opcodes with the other comparison opcodes, i.e.
15221  *   fcompare + branchCC.
15222  * - create a helper function for allocating a stack slot, taking into account 
15223  *   MONO_CFG_HAS_SPILLUP.
15224  * - merge r68207.
15225  * - merge the ia64 switch changes.
15226  * - optimize mono_regstate2_alloc_int/float.
15227  * - fix the pessimistic handling of variables accessed in exception handler blocks.
15228  * - need to write a tree optimization pass, but the creation of trees is difficult, i.e.
15229  *   parts of the tree could be separated by other instructions, killing the tree
15230  *   arguments, or stores killing loads etc. Also, should we fold loads into other
15231  *   instructions if the result of the load is used multiple times ?
15232  * - make the REM_IMM optimization in mini-x86.c arch-independent.
15233  * - LAST MERGE: 108395.
15234  * - when returning vtypes in registers, generate IR and append it to the end of the
15235  *   last bb instead of doing it in the epilog.
15236  * - change the store opcodes so they use sreg1 instead of dreg to store the base register.
15237  */
15238
15239 /*
15240
15241 NOTES
15242 -----
15243
15244 - When to decompose opcodes:
15245   - earlier: this makes some optimizations hard to implement, since the low level IR
15246   no longer contains the neccessary information. But it is easier to do.
15247   - later: harder to implement, enables more optimizations.
15248 - Branches inside bblocks:
15249   - created when decomposing complex opcodes. 
15250     - branches to another bblock: harmless, but not tracked by the branch 
15251       optimizations, so need to branch to a label at the start of the bblock.
15252     - branches to inside the same bblock: very problematic, trips up the local
15253       reg allocator. Can be fixed by spitting the current bblock, but that is a
15254       complex operation, since some local vregs can become global vregs etc.
15255 - Local/global vregs:
15256   - local vregs: temporary vregs used inside one bblock. Assigned to hregs by the
15257     local register allocator.
15258   - global vregs: used in more than one bblock. Have an associated MonoMethodVar
15259     structure, created by mono_create_var (). Assigned to hregs or the stack by
15260     the global register allocator.
15261 - When to do optimizations like alu->alu_imm:
15262   - earlier -> saves work later on since the IR will be smaller/simpler
15263   - later -> can work on more instructions
15264 - Handling of valuetypes:
15265   - When a vtype is pushed on the stack, a new temporary is created, an 
15266     instruction computing its address (LDADDR) is emitted and pushed on
15267     the stack. Need to optimize cases when the vtype is used immediately as in
15268     argument passing, stloc etc.
15269 - Instead of the to_end stuff in the old JIT, simply call the function handling
15270   the values on the stack before emitting the last instruction of the bb.
15271 */
15272
15273 #endif /* DISABLE_JIT */