[jit] Remove silly debug spew.
[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 GList*
665 mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *target, int type)
666 {
667         MonoMethodHeader *header = cfg->header;
668         MonoExceptionClause *clause;
669         int i;
670         GList *res = NULL;
671
672         for (i = 0; i < header->num_clauses; ++i) {
673                 clause = &header->clauses [i];
674                 if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) && 
675                     (!MONO_OFFSET_IN_CLAUSE (clause, (target - header->code)))) {
676                         if (clause->flags == type)
677                                 res = g_list_append (res, clause);
678                 }
679         }
680         return res;
681 }
682
683 static void
684 mono_create_spvar_for_region (MonoCompile *cfg, int region)
685 {
686         MonoInst *var;
687
688         var = (MonoInst *)g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
689         if (var)
690                 return;
691
692         var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
693         /* prevent it from being register allocated */
694         var->flags |= MONO_INST_VOLATILE;
695
696         g_hash_table_insert (cfg->spvars, GINT_TO_POINTER (region), var);
697 }
698
699 MonoInst *
700 mono_find_exvar_for_offset (MonoCompile *cfg, int offset)
701 {
702         return (MonoInst *)g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
703 }
704
705 static MonoInst*
706 mono_create_exvar_for_offset (MonoCompile *cfg, int offset)
707 {
708         MonoInst *var;
709
710         var = (MonoInst *)g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
711         if (var)
712                 return var;
713
714         var = mono_compile_create_var (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL);
715         /* prevent it from being register allocated */
716         var->flags |= MONO_INST_VOLATILE;
717
718         g_hash_table_insert (cfg->exvars, GINT_TO_POINTER (offset), var);
719
720         return var;
721 }
722
723 /*
724  * Returns the type used in the eval stack when @type is loaded.
725  * FIXME: return a MonoType/MonoClass for the byref and VALUETYPE cases.
726  */
727 void
728 type_to_eval_stack_type (MonoCompile *cfg, MonoType *type, MonoInst *inst)
729 {
730         MonoClass *klass;
731
732         type = mini_get_underlying_type (type);
733         inst->klass = klass = mono_class_from_mono_type (type);
734         if (type->byref) {
735                 inst->type = STACK_MP;
736                 return;
737         }
738
739 handle_enum:
740         switch (type->type) {
741         case MONO_TYPE_VOID:
742                 inst->type = STACK_INV;
743                 return;
744         case MONO_TYPE_I1:
745         case MONO_TYPE_U1:
746         case MONO_TYPE_I2:
747         case MONO_TYPE_U2:
748         case MONO_TYPE_I4:
749         case MONO_TYPE_U4:
750                 inst->type = STACK_I4;
751                 return;
752         case MONO_TYPE_I:
753         case MONO_TYPE_U:
754         case MONO_TYPE_PTR:
755         case MONO_TYPE_FNPTR:
756                 inst->type = STACK_PTR;
757                 return;
758         case MONO_TYPE_CLASS:
759         case MONO_TYPE_STRING:
760         case MONO_TYPE_OBJECT:
761         case MONO_TYPE_SZARRAY:
762         case MONO_TYPE_ARRAY:    
763                 inst->type = STACK_OBJ;
764                 return;
765         case MONO_TYPE_I8:
766         case MONO_TYPE_U8:
767                 inst->type = STACK_I8;
768                 return;
769         case MONO_TYPE_R4:
770                 inst->type = cfg->r4_stack_type;
771                 break;
772         case MONO_TYPE_R8:
773                 inst->type = STACK_R8;
774                 return;
775         case MONO_TYPE_VALUETYPE:
776                 if (type->data.klass->enumtype) {
777                         type = mono_class_enum_basetype (type->data.klass);
778                         goto handle_enum;
779                 } else {
780                         inst->klass = klass;
781                         inst->type = STACK_VTYPE;
782                         return;
783                 }
784         case MONO_TYPE_TYPEDBYREF:
785                 inst->klass = mono_defaults.typed_reference_class;
786                 inst->type = STACK_VTYPE;
787                 return;
788         case MONO_TYPE_GENERICINST:
789                 type = &type->data.generic_class->container_class->byval_arg;
790                 goto handle_enum;
791         case MONO_TYPE_VAR:
792         case MONO_TYPE_MVAR:
793                 g_assert (cfg->gshared);
794                 if (mini_is_gsharedvt_type (type)) {
795                         g_assert (cfg->gsharedvt);
796                         inst->type = STACK_VTYPE;
797                 } else {
798                         type_to_eval_stack_type (cfg, mini_get_underlying_type (type), inst);
799                 }
800                 return;
801         default:
802                 g_error ("unknown type 0x%02x in eval stack type", type->type);
803         }
804 }
805
806 /*
807  * The following tables are used to quickly validate the IL code in type_from_op ().
808  */
809 static const char
810 bin_num_table [STACK_MAX] [STACK_MAX] = {
811         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
812         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
813         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
814         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
815         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8,  STACK_INV, STACK_INV, STACK_INV, STACK_R8},
816         {STACK_INV, STACK_MP,  STACK_INV, STACK_MP,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV},
817         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
818         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
819         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8, STACK_INV, STACK_INV, STACK_INV, STACK_R4}
820 };
821
822 static const char 
823 neg_table [] = {
824         STACK_INV, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_INV, STACK_INV, STACK_INV, STACK_R4
825 };
826
827 /* reduce the size of this table */
828 static const char
829 bin_int_table [STACK_MAX] [STACK_MAX] = {
830         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
831         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
832         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
833         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
834         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
835         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
836         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
837         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
838 };
839
840 static const char
841 bin_comp_table [STACK_MAX] [STACK_MAX] = {
842 /*      Inv i  L  p  F  &  O  vt r4 */
843         {0},
844         {0, 1, 0, 1, 0, 0, 0, 0}, /* i, int32 */
845         {0, 0, 1, 0, 0, 0, 0, 0}, /* L, int64 */
846         {0, 1, 0, 1, 0, 2, 4, 0}, /* p, ptr */
847         {0, 0, 0, 0, 1, 0, 0, 0, 1}, /* F, R8 */
848         {0, 0, 0, 2, 0, 1, 0, 0}, /* &, managed pointer */
849         {0, 0, 0, 4, 0, 0, 3, 0}, /* O, reference */
850         {0, 0, 0, 0, 0, 0, 0, 0}, /* vt value type */
851         {0, 0, 0, 0, 1, 0, 0, 0, 1}, /* r, r4 */
852 };
853
854 /* reduce the size of this table */
855 static const char
856 shift_table [STACK_MAX] [STACK_MAX] = {
857         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
858         {STACK_INV, STACK_I4,  STACK_INV, STACK_I4,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
859         {STACK_INV, STACK_I8,  STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
860         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
861         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
862         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
863         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
864         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
865 };
866
867 /*
868  * Tables to map from the non-specific opcode to the matching
869  * type-specific opcode.
870  */
871 /* handles from CEE_ADD to CEE_SHR_UN (CEE_REM_UN for floats) */
872 static const guint16
873 binops_op_map [STACK_MAX] = {
874         0, OP_IADD-CEE_ADD, OP_LADD-CEE_ADD, OP_PADD-CEE_ADD, OP_FADD-CEE_ADD, OP_PADD-CEE_ADD, 0, 0, OP_RADD-CEE_ADD
875 };
876
877 /* handles from CEE_NEG to CEE_CONV_U8 */
878 static const guint16
879 unops_op_map [STACK_MAX] = {
880         0, OP_INEG-CEE_NEG, OP_LNEG-CEE_NEG, OP_PNEG-CEE_NEG, OP_FNEG-CEE_NEG, OP_PNEG-CEE_NEG, 0, 0, OP_RNEG-CEE_NEG
881 };
882
883 /* handles from CEE_CONV_U2 to CEE_SUB_OVF_UN */
884 static const guint16
885 ovfops_op_map [STACK_MAX] = {
886         0, OP_ICONV_TO_U2-CEE_CONV_U2, OP_LCONV_TO_U2-CEE_CONV_U2, OP_PCONV_TO_U2-CEE_CONV_U2, OP_FCONV_TO_U2-CEE_CONV_U2, OP_PCONV_TO_U2-CEE_CONV_U2, OP_PCONV_TO_U2-CEE_CONV_U2, 0, OP_RCONV_TO_U2-CEE_CONV_U2
887 };
888
889 /* handles from CEE_CONV_OVF_I1_UN to CEE_CONV_OVF_U_UN */
890 static const guint16
891 ovf2ops_op_map [STACK_MAX] = {
892         0, OP_ICONV_TO_OVF_I1_UN-CEE_CONV_OVF_I1_UN, OP_LCONV_TO_OVF_I1_UN-CEE_CONV_OVF_I1_UN, OP_PCONV_TO_OVF_I1_UN-CEE_CONV_OVF_I1_UN, OP_FCONV_TO_OVF_I1_UN-CEE_CONV_OVF_I1_UN, OP_PCONV_TO_OVF_I1_UN-CEE_CONV_OVF_I1_UN, 0, 0, OP_RCONV_TO_OVF_I1_UN-CEE_CONV_OVF_I1_UN
893 };
894
895 /* handles from CEE_CONV_OVF_I1 to CEE_CONV_OVF_U8 */
896 static const guint16
897 ovf3ops_op_map [STACK_MAX] = {
898         0, OP_ICONV_TO_OVF_I1-CEE_CONV_OVF_I1, OP_LCONV_TO_OVF_I1-CEE_CONV_OVF_I1, OP_PCONV_TO_OVF_I1-CEE_CONV_OVF_I1, OP_FCONV_TO_OVF_I1-CEE_CONV_OVF_I1, OP_PCONV_TO_OVF_I1-CEE_CONV_OVF_I1, 0, 0, OP_RCONV_TO_OVF_I1-CEE_CONV_OVF_I1
899 };
900
901 /* handles from CEE_BEQ to CEE_BLT_UN */
902 static const guint16
903 beqops_op_map [STACK_MAX] = {
904         0, OP_IBEQ-CEE_BEQ, OP_LBEQ-CEE_BEQ, OP_PBEQ-CEE_BEQ, OP_FBEQ-CEE_BEQ, OP_PBEQ-CEE_BEQ, OP_PBEQ-CEE_BEQ, 0, OP_FBEQ-CEE_BEQ
905 };
906
907 /* handles from CEE_CEQ to CEE_CLT_UN */
908 static const guint16
909 ceqops_op_map [STACK_MAX] = {
910         0, OP_ICEQ-OP_CEQ, OP_LCEQ-OP_CEQ, OP_PCEQ-OP_CEQ, OP_FCEQ-OP_CEQ, OP_PCEQ-OP_CEQ, OP_PCEQ-OP_CEQ, 0, OP_RCEQ-OP_CEQ
911 };
912
913 /*
914  * Sets ins->type (the type on the eval stack) according to the
915  * type of the opcode and the arguments to it.
916  * Invalid IL code is marked by setting ins->type to the invalid value STACK_INV.
917  *
918  * FIXME: this function sets ins->type unconditionally in some cases, but
919  * it should set it to invalid for some types (a conv.x on an object)
920  */
921 static void
922 type_from_op (MonoCompile *cfg, MonoInst *ins, MonoInst *src1, MonoInst *src2)
923 {
924         switch (ins->opcode) {
925         /* binops */
926         case CEE_ADD:
927         case CEE_SUB:
928         case CEE_MUL:
929         case CEE_DIV:
930         case CEE_REM:
931                 /* FIXME: check unverifiable args for STACK_MP */
932                 ins->type = bin_num_table [src1->type] [src2->type];
933                 ins->opcode += binops_op_map [ins->type];
934                 break;
935         case CEE_DIV_UN:
936         case CEE_REM_UN:
937         case CEE_AND:
938         case CEE_OR:
939         case CEE_XOR:
940                 ins->type = bin_int_table [src1->type] [src2->type];
941                 ins->opcode += binops_op_map [ins->type];
942                 break;
943         case CEE_SHL:
944         case CEE_SHR:
945         case CEE_SHR_UN:
946                 ins->type = shift_table [src1->type] [src2->type];
947                 ins->opcode += binops_op_map [ins->type];
948                 break;
949         case OP_COMPARE:
950         case OP_LCOMPARE:
951         case OP_ICOMPARE:
952                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
953                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
954                         ins->opcode = OP_LCOMPARE;
955                 else if (src1->type == STACK_R4)
956                         ins->opcode = OP_RCOMPARE;
957                 else if (src1->type == STACK_R8)
958                         ins->opcode = OP_FCOMPARE;
959                 else
960                         ins->opcode = OP_ICOMPARE;
961                 break;
962         case OP_ICOMPARE_IMM:
963                 ins->type = bin_comp_table [src1->type] [src1->type] ? STACK_I4 : STACK_INV;
964                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
965                         ins->opcode = OP_LCOMPARE_IMM;          
966                 break;
967         case CEE_BEQ:
968         case CEE_BGE:
969         case CEE_BGT:
970         case CEE_BLE:
971         case CEE_BLT:
972         case CEE_BNE_UN:
973         case CEE_BGE_UN:
974         case CEE_BGT_UN:
975         case CEE_BLE_UN:
976         case CEE_BLT_UN:
977                 ins->opcode += beqops_op_map [src1->type];
978                 break;
979         case OP_CEQ:
980                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
981                 ins->opcode += ceqops_op_map [src1->type];
982                 break;
983         case OP_CGT:
984         case OP_CGT_UN:
985         case OP_CLT:
986         case OP_CLT_UN:
987                 ins->type = (bin_comp_table [src1->type] [src2->type] & 1) ? STACK_I4: STACK_INV;
988                 ins->opcode += ceqops_op_map [src1->type];
989                 break;
990         /* unops */
991         case CEE_NEG:
992                 ins->type = neg_table [src1->type];
993                 ins->opcode += unops_op_map [ins->type];
994                 break;
995         case CEE_NOT:
996                 if (src1->type >= STACK_I4 && src1->type <= STACK_PTR)
997                         ins->type = src1->type;
998                 else
999                         ins->type = STACK_INV;
1000                 ins->opcode += unops_op_map [ins->type];
1001                 break;
1002         case CEE_CONV_I1:
1003         case CEE_CONV_I2:
1004         case CEE_CONV_I4:
1005         case CEE_CONV_U4:
1006                 ins->type = STACK_I4;
1007                 ins->opcode += unops_op_map [src1->type];
1008                 break;
1009         case CEE_CONV_R_UN:
1010                 ins->type = STACK_R8;
1011                 switch (src1->type) {
1012                 case STACK_I4:
1013                 case STACK_PTR:
1014                         ins->opcode = OP_ICONV_TO_R_UN;
1015                         break;
1016                 case STACK_I8:
1017                         ins->opcode = OP_LCONV_TO_R_UN; 
1018                         break;
1019                 }
1020                 break;
1021         case CEE_CONV_OVF_I1:
1022         case CEE_CONV_OVF_U1:
1023         case CEE_CONV_OVF_I2:
1024         case CEE_CONV_OVF_U2:
1025         case CEE_CONV_OVF_I4:
1026         case CEE_CONV_OVF_U4:
1027                 ins->type = STACK_I4;
1028                 ins->opcode += ovf3ops_op_map [src1->type];
1029                 break;
1030         case CEE_CONV_OVF_I_UN:
1031         case CEE_CONV_OVF_U_UN:
1032                 ins->type = STACK_PTR;
1033                 ins->opcode += ovf2ops_op_map [src1->type];
1034                 break;
1035         case CEE_CONV_OVF_I1_UN:
1036         case CEE_CONV_OVF_I2_UN:
1037         case CEE_CONV_OVF_I4_UN:
1038         case CEE_CONV_OVF_U1_UN:
1039         case CEE_CONV_OVF_U2_UN:
1040         case CEE_CONV_OVF_U4_UN:
1041                 ins->type = STACK_I4;
1042                 ins->opcode += ovf2ops_op_map [src1->type];
1043                 break;
1044         case CEE_CONV_U:
1045                 ins->type = STACK_PTR;
1046                 switch (src1->type) {
1047                 case STACK_I4:
1048                         ins->opcode = OP_ICONV_TO_U;
1049                         break;
1050                 case STACK_PTR:
1051                 case STACK_MP:
1052 #if SIZEOF_VOID_P == 8
1053                         ins->opcode = OP_LCONV_TO_U;
1054 #else
1055                         ins->opcode = OP_MOVE;
1056 #endif
1057                         break;
1058                 case STACK_I8:
1059                         ins->opcode = OP_LCONV_TO_U;
1060                         break;
1061                 case STACK_R8:
1062                         ins->opcode = OP_FCONV_TO_U;
1063                         break;
1064                 }
1065                 break;
1066         case CEE_CONV_I8:
1067         case CEE_CONV_U8:
1068                 ins->type = STACK_I8;
1069                 ins->opcode += unops_op_map [src1->type];
1070                 break;
1071         case CEE_CONV_OVF_I8:
1072         case CEE_CONV_OVF_U8:
1073                 ins->type = STACK_I8;
1074                 ins->opcode += ovf3ops_op_map [src1->type];
1075                 break;
1076         case CEE_CONV_OVF_U8_UN:
1077         case CEE_CONV_OVF_I8_UN:
1078                 ins->type = STACK_I8;
1079                 ins->opcode += ovf2ops_op_map [src1->type];
1080                 break;
1081         case CEE_CONV_R4:
1082                 ins->type = cfg->r4_stack_type;
1083                 ins->opcode += unops_op_map [src1->type];
1084                 break;
1085         case CEE_CONV_R8:
1086                 ins->type = STACK_R8;
1087                 ins->opcode += unops_op_map [src1->type];
1088                 break;
1089         case OP_CKFINITE:
1090                 ins->type = STACK_R8;           
1091                 break;
1092         case CEE_CONV_U2:
1093         case CEE_CONV_U1:
1094                 ins->type = STACK_I4;
1095                 ins->opcode += ovfops_op_map [src1->type];
1096                 break;
1097         case CEE_CONV_I:
1098         case CEE_CONV_OVF_I:
1099         case CEE_CONV_OVF_U:
1100                 ins->type = STACK_PTR;
1101                 ins->opcode += ovfops_op_map [src1->type];
1102                 break;
1103         case CEE_ADD_OVF:
1104         case CEE_ADD_OVF_UN:
1105         case CEE_MUL_OVF:
1106         case CEE_MUL_OVF_UN:
1107         case CEE_SUB_OVF:
1108         case CEE_SUB_OVF_UN:
1109                 ins->type = bin_num_table [src1->type] [src2->type];
1110                 ins->opcode += ovfops_op_map [src1->type];
1111                 if (ins->type == STACK_R8)
1112                         ins->type = STACK_INV;
1113                 break;
1114         case OP_LOAD_MEMBASE:
1115                 ins->type = STACK_PTR;
1116                 break;
1117         case OP_LOADI1_MEMBASE:
1118         case OP_LOADU1_MEMBASE:
1119         case OP_LOADI2_MEMBASE:
1120         case OP_LOADU2_MEMBASE:
1121         case OP_LOADI4_MEMBASE:
1122         case OP_LOADU4_MEMBASE:
1123                 ins->type = STACK_PTR;
1124                 break;
1125         case OP_LOADI8_MEMBASE:
1126                 ins->type = STACK_I8;
1127                 break;
1128         case OP_LOADR4_MEMBASE:
1129                 ins->type = cfg->r4_stack_type;
1130                 break;
1131         case OP_LOADR8_MEMBASE:
1132                 ins->type = STACK_R8;
1133                 break;
1134         default:
1135                 g_error ("opcode 0x%04x not handled in type from op", ins->opcode);
1136                 break;
1137         }
1138
1139         if (ins->type == STACK_MP)
1140                 ins->klass = mono_defaults.object_class;
1141 }
1142
1143 static const char 
1144 ldind_type [] = {
1145         STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_R8, STACK_OBJ
1146 };
1147
1148 #if 0
1149
1150 static const char
1151 param_table [STACK_MAX] [STACK_MAX] = {
1152         {0},
1153 };
1154
1155 static int
1156 check_values_to_signature (MonoInst *args, MonoType *this_ins, MonoMethodSignature *sig)
1157 {
1158         int i;
1159
1160         if (sig->hasthis) {
1161                 switch (args->type) {
1162                 case STACK_I4:
1163                 case STACK_I8:
1164                 case STACK_R8:
1165                 case STACK_VTYPE:
1166                 case STACK_INV:
1167                         return 0;
1168                 }
1169                 args++;
1170         }
1171         for (i = 0; i < sig->param_count; ++i) {
1172                 switch (args [i].type) {
1173                 case STACK_INV:
1174                         return 0;
1175                 case STACK_MP:
1176                         if (!sig->params [i]->byref)
1177                                 return 0;
1178                         continue;
1179                 case STACK_OBJ:
1180                         if (sig->params [i]->byref)
1181                                 return 0;
1182                         switch (sig->params [i]->type) {
1183                         case MONO_TYPE_CLASS:
1184                         case MONO_TYPE_STRING:
1185                         case MONO_TYPE_OBJECT:
1186                         case MONO_TYPE_SZARRAY:
1187                         case MONO_TYPE_ARRAY:
1188                                 break;
1189                         default:
1190                                 return 0;
1191                         }
1192                         continue;
1193                 case STACK_R8:
1194                         if (sig->params [i]->byref)
1195                                 return 0;
1196                         if (sig->params [i]->type != MONO_TYPE_R4 && sig->params [i]->type != MONO_TYPE_R8)
1197                                 return 0;
1198                         continue;
1199                 case STACK_PTR:
1200                 case STACK_I4:
1201                 case STACK_I8:
1202                 case STACK_VTYPE:
1203                         break;
1204                 }
1205                 /*if (!param_table [args [i].type] [sig->params [i]->type])
1206                         return 0;*/
1207         }
1208         return 1;
1209 }
1210 #endif
1211
1212 /*
1213  * When we need a pointer to the current domain many times in a method, we
1214  * call mono_domain_get() once and we store the result in a local variable.
1215  * This function returns the variable that represents the MonoDomain*.
1216  */
1217 inline static MonoInst *
1218 mono_get_domainvar (MonoCompile *cfg)
1219 {
1220         if (!cfg->domainvar)
1221                 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1222         return cfg->domainvar;
1223 }
1224
1225 /*
1226  * The got_var contains the address of the Global Offset Table when AOT 
1227  * compiling.
1228  */
1229 MonoInst *
1230 mono_get_got_var (MonoCompile *cfg)
1231 {
1232         if (!cfg->compile_aot || !cfg->backend->need_got_var)
1233                 return NULL;
1234         if (!cfg->got_var) {
1235                 cfg->got_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1236         }
1237         return cfg->got_var;
1238 }
1239
1240 static MonoInst *
1241 mono_get_vtable_var (MonoCompile *cfg)
1242 {
1243         g_assert (cfg->gshared);
1244
1245         if (!cfg->rgctx_var) {
1246                 cfg->rgctx_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1247                 /* force the var to be stack allocated */
1248                 cfg->rgctx_var->flags |= MONO_INST_VOLATILE;
1249         }
1250
1251         return cfg->rgctx_var;
1252 }
1253
1254 static MonoType*
1255 type_from_stack_type (MonoInst *ins) {
1256         switch (ins->type) {
1257         case STACK_I4: return &mono_defaults.int32_class->byval_arg;
1258         case STACK_I8: return &mono_defaults.int64_class->byval_arg;
1259         case STACK_PTR: return &mono_defaults.int_class->byval_arg;
1260         case STACK_R4: return &mono_defaults.single_class->byval_arg;
1261         case STACK_R8: return &mono_defaults.double_class->byval_arg;
1262         case STACK_MP:
1263                 return &ins->klass->this_arg;
1264         case STACK_OBJ: return &mono_defaults.object_class->byval_arg;
1265         case STACK_VTYPE: return &ins->klass->byval_arg;
1266         default:
1267                 g_error ("stack type %d to monotype not handled\n", ins->type);
1268         }
1269         return NULL;
1270 }
1271
1272 static G_GNUC_UNUSED int
1273 type_to_stack_type (MonoCompile *cfg, MonoType *t)
1274 {
1275         t = mono_type_get_underlying_type (t);
1276         switch (t->type) {
1277         case MONO_TYPE_I1:
1278         case MONO_TYPE_U1:
1279         case MONO_TYPE_I2:
1280         case MONO_TYPE_U2:
1281         case MONO_TYPE_I4:
1282         case MONO_TYPE_U4:
1283                 return STACK_I4;
1284         case MONO_TYPE_I:
1285         case MONO_TYPE_U:
1286         case MONO_TYPE_PTR:
1287         case MONO_TYPE_FNPTR:
1288                 return STACK_PTR;
1289         case MONO_TYPE_CLASS:
1290         case MONO_TYPE_STRING:
1291         case MONO_TYPE_OBJECT:
1292         case MONO_TYPE_SZARRAY:
1293         case MONO_TYPE_ARRAY:    
1294                 return STACK_OBJ;
1295         case MONO_TYPE_I8:
1296         case MONO_TYPE_U8:
1297                 return STACK_I8;
1298         case MONO_TYPE_R4:
1299                 return cfg->r4_stack_type;
1300         case MONO_TYPE_R8:
1301                 return STACK_R8;
1302         case MONO_TYPE_VALUETYPE:
1303         case MONO_TYPE_TYPEDBYREF:
1304                 return STACK_VTYPE;
1305         case MONO_TYPE_GENERICINST:
1306                 if (mono_type_generic_inst_is_valuetype (t))
1307                         return STACK_VTYPE;
1308                 else
1309                         return STACK_OBJ;
1310                 break;
1311         default:
1312                 g_assert_not_reached ();
1313         }
1314
1315         return -1;
1316 }
1317
1318 static MonoClass*
1319 array_access_to_klass (int opcode)
1320 {
1321         switch (opcode) {
1322         case CEE_LDELEM_U1:
1323                 return mono_defaults.byte_class;
1324         case CEE_LDELEM_U2:
1325                 return mono_defaults.uint16_class;
1326         case CEE_LDELEM_I:
1327         case CEE_STELEM_I:
1328                 return mono_defaults.int_class;
1329         case CEE_LDELEM_I1:
1330         case CEE_STELEM_I1:
1331                 return mono_defaults.sbyte_class;
1332         case CEE_LDELEM_I2:
1333         case CEE_STELEM_I2:
1334                 return mono_defaults.int16_class;
1335         case CEE_LDELEM_I4:
1336         case CEE_STELEM_I4:
1337                 return mono_defaults.int32_class;
1338         case CEE_LDELEM_U4:
1339                 return mono_defaults.uint32_class;
1340         case CEE_LDELEM_I8:
1341         case CEE_STELEM_I8:
1342                 return mono_defaults.int64_class;
1343         case CEE_LDELEM_R4:
1344         case CEE_STELEM_R4:
1345                 return mono_defaults.single_class;
1346         case CEE_LDELEM_R8:
1347         case CEE_STELEM_R8:
1348                 return mono_defaults.double_class;
1349         case CEE_LDELEM_REF:
1350         case CEE_STELEM_REF:
1351                 return mono_defaults.object_class;
1352         default:
1353                 g_assert_not_reached ();
1354         }
1355         return NULL;
1356 }
1357
1358 /*
1359  * We try to share variables when possible
1360  */
1361 static MonoInst *
1362 mono_compile_get_interface_var (MonoCompile *cfg, int slot, MonoInst *ins)
1363 {
1364         MonoInst *res;
1365         int pos, vnum;
1366
1367         /* inlining can result in deeper stacks */ 
1368         if (slot >= cfg->header->max_stack)
1369                 return mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1370
1371         pos = ins->type - 1 + slot * STACK_MAX;
1372
1373         switch (ins->type) {
1374         case STACK_I4:
1375         case STACK_I8:
1376         case STACK_R8:
1377         case STACK_PTR:
1378         case STACK_MP:
1379         case STACK_OBJ:
1380                 if ((vnum = cfg->intvars [pos]))
1381                         return cfg->varinfo [vnum];
1382                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1383                 cfg->intvars [pos] = res->inst_c0;
1384                 break;
1385         default:
1386                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1387         }
1388         return res;
1389 }
1390
1391 static void
1392 mono_save_token_info (MonoCompile *cfg, MonoImage *image, guint32 token, gpointer key)
1393 {
1394         /* 
1395          * Don't use this if a generic_context is set, since that means AOT can't
1396          * look up the method using just the image+token.
1397          * table == 0 means this is a reference made from a wrapper.
1398          */
1399         if (cfg->compile_aot && !cfg->generic_context && (mono_metadata_token_table (token) > 0)) {
1400                 MonoJumpInfoToken *jump_info_token = (MonoJumpInfoToken *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoToken));
1401                 jump_info_token->image = image;
1402                 jump_info_token->token = token;
1403                 g_hash_table_insert (cfg->token_info_hash, key, jump_info_token);
1404         }
1405 }
1406
1407 /*
1408  * This function is called to handle items that are left on the evaluation stack
1409  * at basic block boundaries. What happens is that we save the values to local variables
1410  * and we reload them later when first entering the target basic block (with the
1411  * handle_loaded_temps () function).
1412  * A single joint point will use the same variables (stored in the array bb->out_stack or
1413  * bb->in_stack, if the basic block is before or after the joint point).
1414  *
1415  * This function needs to be called _before_ emitting the last instruction of
1416  * the bb (i.e. before emitting a branch).
1417  * If the stack merge fails at a join point, cfg->unverifiable is set.
1418  */
1419 static void
1420 handle_stack_args (MonoCompile *cfg, MonoInst **sp, int count)
1421 {
1422         int i, bindex;
1423         MonoBasicBlock *bb = cfg->cbb;
1424         MonoBasicBlock *outb;
1425         MonoInst *inst, **locals;
1426         gboolean found;
1427
1428         if (!count)
1429                 return;
1430         if (cfg->verbose_level > 3)
1431                 printf ("%d item(s) on exit from B%d\n", count, bb->block_num);
1432         if (!bb->out_scount) {
1433                 bb->out_scount = count;
1434                 //printf ("bblock %d has out:", bb->block_num);
1435                 found = FALSE;
1436                 for (i = 0; i < bb->out_count; ++i) {
1437                         outb = bb->out_bb [i];
1438                         /* exception handlers are linked, but they should not be considered for stack args */
1439                         if (outb->flags & BB_EXCEPTION_HANDLER)
1440                                 continue;
1441                         //printf (" %d", outb->block_num);
1442                         if (outb->in_stack) {
1443                                 found = TRUE;
1444                                 bb->out_stack = outb->in_stack;
1445                                 break;
1446                         }
1447                 }
1448                 //printf ("\n");
1449                 if (!found) {
1450                         bb->out_stack = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * count);
1451                         for (i = 0; i < count; ++i) {
1452                                 /* 
1453                                  * try to reuse temps already allocated for this purpouse, if they occupy the same
1454                                  * stack slot and if they are of the same type.
1455                                  * This won't cause conflicts since if 'local' is used to 
1456                                  * store one of the values in the in_stack of a bblock, then
1457                                  * the same variable will be used for the same outgoing stack 
1458                                  * slot as well. 
1459                                  * This doesn't work when inlining methods, since the bblocks
1460                                  * in the inlined methods do not inherit their in_stack from
1461                                  * the bblock they are inlined to. See bug #58863 for an
1462                                  * example.
1463                                  */
1464                                 if (cfg->inlined_method)
1465                                         bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
1466                                 else
1467                                         bb->out_stack [i] = mono_compile_get_interface_var (cfg, i, sp [i]);
1468                         }
1469                 }
1470         }
1471
1472         for (i = 0; i < bb->out_count; ++i) {
1473                 outb = bb->out_bb [i];
1474                 /* exception handlers are linked, but they should not be considered for stack args */
1475                 if (outb->flags & BB_EXCEPTION_HANDLER)
1476                         continue;
1477                 if (outb->in_scount) {
1478                         if (outb->in_scount != bb->out_scount) {
1479                                 cfg->unverifiable = TRUE;
1480                                 return;
1481                         }
1482                         continue; /* check they are the same locals */
1483                 }
1484                 outb->in_scount = count;
1485                 outb->in_stack = bb->out_stack;
1486         }
1487
1488         locals = bb->out_stack;
1489         cfg->cbb = bb;
1490         for (i = 0; i < count; ++i) {
1491                 EMIT_NEW_TEMPSTORE (cfg, inst, locals [i]->inst_c0, sp [i]);
1492                 inst->cil_code = sp [i]->cil_code;
1493                 sp [i] = locals [i];
1494                 if (cfg->verbose_level > 3)
1495                         printf ("storing %d to temp %d\n", i, (int)locals [i]->inst_c0);
1496         }
1497
1498         /*
1499          * It is possible that the out bblocks already have in_stack assigned, and
1500          * the in_stacks differ. In this case, we will store to all the different 
1501          * in_stacks.
1502          */
1503
1504         found = TRUE;
1505         bindex = 0;
1506         while (found) {
1507                 /* Find a bblock which has a different in_stack */
1508                 found = FALSE;
1509                 while (bindex < bb->out_count) {
1510                         outb = bb->out_bb [bindex];
1511                         /* exception handlers are linked, but they should not be considered for stack args */
1512                         if (outb->flags & BB_EXCEPTION_HANDLER) {
1513                                 bindex++;
1514                                 continue;
1515                         }
1516                         if (outb->in_stack != locals) {
1517                                 for (i = 0; i < count; ++i) {
1518                                         EMIT_NEW_TEMPSTORE (cfg, inst, outb->in_stack [i]->inst_c0, sp [i]);
1519                                         inst->cil_code = sp [i]->cil_code;
1520                                         sp [i] = locals [i];
1521                                         if (cfg->verbose_level > 3)
1522                                                 printf ("storing %d to temp %d\n", i, (int)outb->in_stack [i]->inst_c0);
1523                                 }
1524                                 locals = outb->in_stack;
1525                                 found = TRUE;
1526                                 break;
1527                         }
1528                         bindex ++;
1529                 }
1530         }
1531 }
1532
1533 static MonoInst*
1534 emit_runtime_constant (MonoCompile *cfg, MonoJumpInfoType patch_type, gpointer data)
1535 {
1536         MonoInst *ins;
1537
1538         if (cfg->compile_aot) {
1539                 EMIT_NEW_AOTCONST (cfg, ins, patch_type, data);
1540         } else {
1541                 MonoJumpInfo ji;
1542                 gpointer target;
1543                 MonoError error;
1544
1545                 ji.type = patch_type;
1546                 ji.data.target = data;
1547                 target = mono_resolve_patch_target (NULL, cfg->domain, NULL, &ji, FALSE, &error);
1548                 mono_error_assert_ok (&error);
1549
1550                 EMIT_NEW_PCONST (cfg, ins, target);
1551         }
1552         return ins;
1553 }
1554
1555 static void
1556 mini_emit_interface_bitmap_check (MonoCompile *cfg, int intf_bit_reg, int base_reg, int offset, MonoClass *klass)
1557 {
1558         int ibitmap_reg = alloc_preg (cfg);
1559 #ifdef COMPRESSED_INTERFACE_BITMAP
1560         MonoInst *args [2];
1561         MonoInst *res, *ins;
1562         NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, ibitmap_reg, base_reg, offset);
1563         MONO_ADD_INS (cfg->cbb, ins);
1564         args [0] = ins;
1565         args [1] = emit_runtime_constant (cfg, MONO_PATCH_INFO_IID, klass);
1566         res = mono_emit_jit_icall (cfg, mono_class_interface_match, args);
1567         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, intf_bit_reg, res->dreg);
1568 #else
1569         int ibitmap_byte_reg = alloc_preg (cfg);
1570
1571         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, ibitmap_reg, base_reg, offset);
1572
1573         if (cfg->compile_aot) {
1574                 int iid_reg = alloc_preg (cfg);
1575                 int shifted_iid_reg = alloc_preg (cfg);
1576                 int ibitmap_byte_address_reg = alloc_preg (cfg);
1577                 int masked_iid_reg = alloc_preg (cfg);
1578                 int iid_one_bit_reg = alloc_preg (cfg);
1579                 int iid_bit_reg = alloc_preg (cfg);
1580                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1581                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, shifted_iid_reg, iid_reg, 3);
1582                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, ibitmap_byte_address_reg, ibitmap_reg, shifted_iid_reg);
1583                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, ibitmap_byte_reg, ibitmap_byte_address_reg, 0);
1584                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, masked_iid_reg, iid_reg, 7);
1585                 MONO_EMIT_NEW_ICONST (cfg, iid_one_bit_reg, 1);
1586                 MONO_EMIT_NEW_BIALU (cfg, OP_ISHL, iid_bit_reg, iid_one_bit_reg, masked_iid_reg);
1587                 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, intf_bit_reg, ibitmap_byte_reg, iid_bit_reg);
1588         } else {
1589                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, ibitmap_byte_reg, ibitmap_reg, klass->interface_id >> 3);
1590                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, intf_bit_reg, ibitmap_byte_reg, 1 << (klass->interface_id & 7));
1591         }
1592 #endif
1593 }
1594
1595 /* 
1596  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoClass
1597  * stored in "klass_reg" implements the interface "klass".
1598  */
1599 static void
1600 mini_emit_load_intf_bit_reg_class (MonoCompile *cfg, int intf_bit_reg, int klass_reg, MonoClass *klass)
1601 {
1602         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, interface_bitmap), klass);
1603 }
1604
1605 /* 
1606  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoVTable
1607  * stored in "vtable_reg" implements the interface "klass".
1608  */
1609 static void
1610 mini_emit_load_intf_bit_reg_vtable (MonoCompile *cfg, int intf_bit_reg, int vtable_reg, MonoClass *klass)
1611 {
1612         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, interface_bitmap), klass);
1613 }
1614
1615 /* 
1616  * Emit code which checks whenever the interface id of @klass is smaller than
1617  * than the value given by max_iid_reg.
1618 */
1619 static void
1620 mini_emit_max_iid_check (MonoCompile *cfg, int max_iid_reg, MonoClass *klass,
1621                                                  MonoBasicBlock *false_target)
1622 {
1623         if (cfg->compile_aot) {
1624                 int iid_reg = alloc_preg (cfg);
1625                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1626                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, max_iid_reg, iid_reg);
1627         }
1628         else
1629                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, max_iid_reg, klass->interface_id);
1630         if (false_target)
1631                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1632         else
1633                 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1634 }
1635
1636 /* Same as above, but obtains max_iid from a vtable */
1637 static void
1638 mini_emit_max_iid_check_vtable (MonoCompile *cfg, int vtable_reg, MonoClass *klass,
1639                                                                  MonoBasicBlock *false_target)
1640 {
1641         int max_iid_reg = alloc_preg (cfg);
1642                 
1643         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, max_interface_id));
1644         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1645 }
1646
1647 /* Same as above, but obtains max_iid from a klass */
1648 static void
1649 mini_emit_max_iid_check_class (MonoCompile *cfg, int klass_reg, MonoClass *klass,
1650                                                                  MonoBasicBlock *false_target)
1651 {
1652         int max_iid_reg = alloc_preg (cfg);
1653
1654         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, max_interface_id));
1655         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1656 }
1657
1658 static void
1659 mini_emit_isninst_cast_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_ins, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1660 {
1661         int idepth_reg = alloc_preg (cfg);
1662         int stypes_reg = alloc_preg (cfg);
1663         int stype = alloc_preg (cfg);
1664
1665         mono_class_setup_supertypes (klass);
1666
1667         if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1668                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth));
1669                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1670                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1671         }
1672         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes));
1673         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1674         if (klass_ins) {
1675                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, klass_ins->dreg);
1676         } else if (cfg->compile_aot) {
1677                 int const_reg = alloc_preg (cfg);
1678                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1679                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, const_reg);
1680         } else {
1681                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, stype, klass);
1682         }
1683         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, true_target);
1684 }
1685
1686 static void
1687 mini_emit_isninst_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1688 {
1689         mini_emit_isninst_cast_inst (cfg, klass_reg, klass, NULL, false_target, true_target);
1690 }
1691
1692 static void
1693 mini_emit_iface_cast (MonoCompile *cfg, int vtable_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1694 {
1695         int intf_reg = alloc_preg (cfg);
1696
1697         mini_emit_max_iid_check_vtable (cfg, vtable_reg, klass, false_target);
1698         mini_emit_load_intf_bit_reg_vtable (cfg, intf_reg, vtable_reg, klass);
1699         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_reg, 0);
1700         if (true_target)
1701                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1702         else
1703                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");               
1704 }
1705
1706 /*
1707  * Variant of the above that takes a register to the class, not the vtable.
1708  */
1709 static void
1710 mini_emit_iface_class_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1711 {
1712         int intf_bit_reg = alloc_preg (cfg);
1713
1714         mini_emit_max_iid_check_class (cfg, klass_reg, klass, false_target);
1715         mini_emit_load_intf_bit_reg_class (cfg, intf_bit_reg, klass_reg, klass);
1716         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_bit_reg, 0);
1717         if (true_target)
1718                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1719         else
1720                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
1721 }
1722
1723 static inline void
1724 mini_emit_class_check_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_inst)
1725 {
1726         if (klass_inst) {
1727                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_inst->dreg);
1728         } else {
1729                 MonoInst *ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, klass);
1730                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, ins->dreg);
1731         }
1732         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1733 }
1734
1735 static inline void
1736 mini_emit_class_check (MonoCompile *cfg, int klass_reg, MonoClass *klass)
1737 {
1738         mini_emit_class_check_inst (cfg, klass_reg, klass, NULL);
1739 }
1740
1741 static inline void
1742 mini_emit_class_check_branch (MonoCompile *cfg, int klass_reg, MonoClass *klass, int branch_op, MonoBasicBlock *target)
1743 {
1744         if (cfg->compile_aot) {
1745                 int const_reg = alloc_preg (cfg);
1746                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1747                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, const_reg);
1748         } else {
1749                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
1750         }
1751         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, branch_op, target);
1752 }
1753
1754 static void
1755 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null);
1756         
1757 static void
1758 mini_emit_castclass_inst (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoInst *klass_inst, MonoBasicBlock *object_is_null)
1759 {
1760         if (klass->rank) {
1761                 int rank_reg = alloc_preg (cfg);
1762                 int eclass_reg = alloc_preg (cfg);
1763
1764                 g_assert (!klass_inst);
1765                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, rank));
1766                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
1767                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1768                 //              MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
1769                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
1770                 if (klass->cast_class == mono_defaults.object_class) {
1771                         int parent_reg = alloc_preg (cfg);
1772                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
1773                         mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, object_is_null);
1774                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1775                 } else if (klass->cast_class == mono_defaults.enum_class->parent) {
1776                         mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, object_is_null);
1777                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1778                 } else if (klass->cast_class == mono_defaults.enum_class) {
1779                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1780                 } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1781                         mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, NULL, NULL);
1782                 } else {
1783                         // Pass -1 as obj_reg to skip the check below for arrays of arrays
1784                         mini_emit_castclass (cfg, -1, eclass_reg, klass->cast_class, object_is_null);
1785                 }
1786
1787                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY) && (obj_reg != -1)) {
1788                         /* Check that the object is a vector too */
1789                         int bounds_reg = alloc_preg (cfg);
1790                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
1791                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
1792                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1793                 }
1794         } else {
1795                 int idepth_reg = alloc_preg (cfg);
1796                 int stypes_reg = alloc_preg (cfg);
1797                 int stype = alloc_preg (cfg);
1798
1799                 mono_class_setup_supertypes (klass);
1800
1801                 if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1802                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth));
1803                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1804                         MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1805                 }
1806                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes));
1807                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1808                 mini_emit_class_check_inst (cfg, stype, klass, klass_inst);
1809         }
1810 }
1811
1812 static void
1813 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null)
1814 {
1815         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, NULL, object_is_null);
1816 }
1817
1818 static void 
1819 mini_emit_memset (MonoCompile *cfg, int destreg, int offset, int size, int val, int align)
1820 {
1821         int val_reg;
1822
1823         g_assert (val == 0);
1824
1825         if (align == 0)
1826                 align = 4;
1827
1828         if ((size <= SIZEOF_REGISTER) && (size <= align)) {
1829                 switch (size) {
1830                 case 1:
1831                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, destreg, offset, val);
1832                         return;
1833                 case 2:
1834                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI2_MEMBASE_IMM, destreg, offset, val);
1835                         return;
1836                 case 4:
1837                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI4_MEMBASE_IMM, destreg, offset, val);
1838                         return;
1839 #if SIZEOF_REGISTER == 8
1840                 case 8:
1841                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI8_MEMBASE_IMM, destreg, offset, val);
1842                         return;
1843 #endif
1844                 }
1845         }
1846
1847         val_reg = alloc_preg (cfg);
1848
1849         if (SIZEOF_REGISTER == 8)
1850                 MONO_EMIT_NEW_I8CONST (cfg, val_reg, val);
1851         else
1852                 MONO_EMIT_NEW_ICONST (cfg, val_reg, val);
1853
1854         if (align < 4) {
1855                 /* This could be optimized further if neccesary */
1856                 while (size >= 1) {
1857                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1858                         offset += 1;
1859                         size -= 1;
1860                 }
1861                 return;
1862         }       
1863
1864         if (!cfg->backend->no_unaligned_access && SIZEOF_REGISTER == 8) {
1865                 if (offset % 8) {
1866                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1867                         offset += 4;
1868                         size -= 4;
1869                 }
1870                 while (size >= 8) {
1871                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, offset, val_reg);
1872                         offset += 8;
1873                         size -= 8;
1874                 }
1875         }       
1876
1877         while (size >= 4) {
1878                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1879                 offset += 4;
1880                 size -= 4;
1881         }
1882         while (size >= 2) {
1883                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, val_reg);
1884                 offset += 2;
1885                 size -= 2;
1886         }
1887         while (size >= 1) {
1888                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1889                 offset += 1;
1890                 size -= 1;
1891         }
1892 }
1893
1894 void 
1895 mini_emit_memcpy (MonoCompile *cfg, int destreg, int doffset, int srcreg, int soffset, int size, int align)
1896 {
1897         int cur_reg;
1898
1899         if (align == 0)
1900                 align = 4;
1901
1902         /*FIXME arbitrary hack to avoid unbound code expansion.*/
1903         g_assert (size < 10000);
1904
1905         if (align < 4) {
1906                 /* This could be optimized further if neccesary */
1907                 while (size >= 1) {
1908                         cur_reg = alloc_preg (cfg);
1909                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1910                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1911                         doffset += 1;
1912                         soffset += 1;
1913                         size -= 1;
1914                 }
1915         }
1916
1917         if (!cfg->backend->no_unaligned_access && SIZEOF_REGISTER == 8) {
1918                 while (size >= 8) {
1919                         cur_reg = alloc_preg (cfg);
1920                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI8_MEMBASE, cur_reg, srcreg, soffset);
1921                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, doffset, cur_reg);
1922                         doffset += 8;
1923                         soffset += 8;
1924                         size -= 8;
1925                 }
1926         }       
1927
1928         while (size >= 4) {
1929                 cur_reg = alloc_preg (cfg);
1930                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, cur_reg, srcreg, soffset);
1931                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, doffset, cur_reg);
1932                 doffset += 4;
1933                 soffset += 4;
1934                 size -= 4;
1935         }
1936         while (size >= 2) {
1937                 cur_reg = alloc_preg (cfg);
1938                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, cur_reg, srcreg, soffset);
1939                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, doffset, cur_reg);
1940                 doffset += 2;
1941                 soffset += 2;
1942                 size -= 2;
1943         }
1944         while (size >= 1) {
1945                 cur_reg = alloc_preg (cfg);
1946                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1947                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1948                 doffset += 1;
1949                 soffset += 1;
1950                 size -= 1;
1951         }
1952 }
1953
1954 static void
1955 emit_tls_set (MonoCompile *cfg, int sreg1, MonoTlsKey tls_key)
1956 {
1957         MonoInst *ins, *c;
1958
1959         if (cfg->compile_aot) {
1960                 EMIT_NEW_TLS_OFFSETCONST (cfg, c, tls_key);
1961                 MONO_INST_NEW (cfg, ins, OP_TLS_SET_REG);
1962                 ins->sreg1 = sreg1;
1963                 ins->sreg2 = c->dreg;
1964                 MONO_ADD_INS (cfg->cbb, ins);
1965         } else {
1966                 MONO_INST_NEW (cfg, ins, OP_TLS_SET);
1967                 ins->sreg1 = sreg1;
1968                 ins->inst_offset = mini_get_tls_offset (tls_key);
1969                 MONO_ADD_INS (cfg->cbb, ins);
1970         }
1971 }
1972
1973 /*
1974  * emit_push_lmf:
1975  *
1976  *   Emit IR to push the current LMF onto the LMF stack.
1977  */
1978 static void
1979 emit_push_lmf (MonoCompile *cfg)
1980 {
1981         /*
1982          * Emit IR to push the LMF:
1983          * lmf_addr = <lmf_addr from tls>
1984          * lmf->lmf_addr = lmf_addr
1985          * lmf->prev_lmf = *lmf_addr
1986          * *lmf_addr = lmf
1987          */
1988         int lmf_reg, prev_lmf_reg;
1989         MonoInst *ins, *lmf_ins;
1990
1991         if (!cfg->lmf_ir)
1992                 return;
1993
1994         if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
1995                 /* Load current lmf */
1996                 lmf_ins = mono_get_lmf_intrinsic (cfg);
1997                 g_assert (lmf_ins);
1998                 MONO_ADD_INS (cfg->cbb, lmf_ins);
1999                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2000                 lmf_reg = ins->dreg;
2001                 /* Save previous_lmf */
2002                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), lmf_ins->dreg);
2003                 /* Set new LMF */
2004                 emit_tls_set (cfg, lmf_reg, TLS_KEY_LMF);
2005         } else {
2006                 /*
2007                  * Store lmf_addr in a variable, so it can be allocated to a global register.
2008                  */
2009                 if (!cfg->lmf_addr_var)
2010                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2011
2012 #ifdef HOST_WIN32
2013                 ins = mono_get_jit_tls_intrinsic (cfg);
2014                 if (ins) {
2015                         int jit_tls_dreg = ins->dreg;
2016
2017                         MONO_ADD_INS (cfg->cbb, ins);
2018                         lmf_reg = alloc_preg (cfg);
2019                         EMIT_NEW_BIALU_IMM (cfg, lmf_ins, OP_PADD_IMM, lmf_reg, jit_tls_dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, lmf));
2020                 } else {
2021                         lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
2022                 }
2023 #else
2024                 lmf_ins = mono_get_lmf_addr_intrinsic (cfg);
2025                 if (lmf_ins) {
2026                         MONO_ADD_INS (cfg->cbb, lmf_ins);
2027                 } else {
2028 #ifdef TARGET_IOS
2029                         MonoInst *args [16], *jit_tls_ins, *ins;
2030
2031                         /* Inline mono_get_lmf_addr () */
2032                         /* jit_tls = pthread_getspecific (mono_jit_tls_id); lmf_addr = &jit_tls->lmf; */
2033
2034                         /* Load mono_jit_tls_id */
2035                         if (cfg->compile_aot)
2036                                 EMIT_NEW_AOTCONST (cfg, args [0], MONO_PATCH_INFO_JIT_TLS_ID, NULL);
2037                         else
2038                                 EMIT_NEW_ICONST (cfg, args [0], mono_jit_tls_id);
2039                         /* call pthread_getspecific () */
2040                         jit_tls_ins = mono_emit_jit_icall (cfg, pthread_getspecific, args);
2041                         /* lmf_addr = &jit_tls->lmf */
2042                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, cfg->lmf_addr_var->dreg, jit_tls_ins->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, lmf));
2043                         lmf_ins = ins;
2044 #else
2045                         lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
2046 #endif
2047                 }
2048 #endif
2049                 lmf_ins->dreg = cfg->lmf_addr_var->dreg;
2050
2051                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2052                 lmf_reg = ins->dreg;
2053
2054                 prev_lmf_reg = alloc_preg (cfg);
2055                 /* Save previous_lmf */
2056                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, cfg->lmf_addr_var->dreg, 0);
2057                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), prev_lmf_reg);
2058                 /* Set new lmf */
2059                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, cfg->lmf_addr_var->dreg, 0, lmf_reg);
2060         }
2061 }
2062
2063 /*
2064  * emit_pop_lmf:
2065  *
2066  *   Emit IR to pop the current LMF from the LMF stack.
2067  */
2068 static void
2069 emit_pop_lmf (MonoCompile *cfg)
2070 {
2071         int lmf_reg, lmf_addr_reg, prev_lmf_reg;
2072         MonoInst *ins;
2073
2074         if (!cfg->lmf_ir)
2075                 return;
2076
2077         EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2078         lmf_reg = ins->dreg;
2079
2080         if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
2081                 /* Load previous_lmf */
2082                 prev_lmf_reg = alloc_preg (cfg);
2083                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
2084                 /* Set new LMF */
2085                 emit_tls_set (cfg, prev_lmf_reg, TLS_KEY_LMF);
2086         } else {
2087                 /*
2088                  * Emit IR to pop the LMF:
2089                  * *(lmf->lmf_addr) = lmf->prev_lmf
2090                  */
2091                 /* This could be called before emit_push_lmf () */
2092                 if (!cfg->lmf_addr_var)
2093                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2094                 lmf_addr_reg = cfg->lmf_addr_var->dreg;
2095
2096                 prev_lmf_reg = alloc_preg (cfg);
2097                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
2098                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_addr_reg, 0, prev_lmf_reg);
2099         }
2100 }
2101
2102 static void
2103 emit_instrumentation_call (MonoCompile *cfg, void *func)
2104 {
2105         MonoInst *iargs [1];
2106
2107         /*
2108          * Avoid instrumenting inlined methods since it can
2109          * distort profiling results.
2110          */
2111         if (cfg->method != cfg->current_method)
2112                 return;
2113
2114         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE) {
2115                 EMIT_NEW_METHODCONST (cfg, iargs [0], cfg->method);
2116                 mono_emit_jit_icall (cfg, func, iargs);
2117         }
2118 }
2119
2120 static int
2121 ret_type_to_call_opcode (MonoCompile *cfg, MonoType *type, int calli, int virt)
2122 {
2123 handle_enum:
2124         type = mini_get_underlying_type (type);
2125         switch (type->type) {
2126         case MONO_TYPE_VOID:
2127                 return calli? OP_VOIDCALL_REG: virt? OP_VOIDCALL_MEMBASE: OP_VOIDCALL;
2128         case MONO_TYPE_I1:
2129         case MONO_TYPE_U1:
2130         case MONO_TYPE_I2:
2131         case MONO_TYPE_U2:
2132         case MONO_TYPE_I4:
2133         case MONO_TYPE_U4:
2134                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2135         case MONO_TYPE_I:
2136         case MONO_TYPE_U:
2137         case MONO_TYPE_PTR:
2138         case MONO_TYPE_FNPTR:
2139                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2140         case MONO_TYPE_CLASS:
2141         case MONO_TYPE_STRING:
2142         case MONO_TYPE_OBJECT:
2143         case MONO_TYPE_SZARRAY:
2144         case MONO_TYPE_ARRAY:    
2145                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2146         case MONO_TYPE_I8:
2147         case MONO_TYPE_U8:
2148                 return calli? OP_LCALL_REG: virt? OP_LCALL_MEMBASE: OP_LCALL;
2149         case MONO_TYPE_R4:
2150                 if (cfg->r4fp)
2151                         return calli? OP_RCALL_REG: virt? OP_RCALL_MEMBASE: OP_RCALL;
2152                 else
2153                         return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
2154         case MONO_TYPE_R8:
2155                 return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
2156         case MONO_TYPE_VALUETYPE:
2157                 if (type->data.klass->enumtype) {
2158                         type = mono_class_enum_basetype (type->data.klass);
2159                         goto handle_enum;
2160                 } else
2161                         return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2162         case MONO_TYPE_TYPEDBYREF:
2163                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2164         case MONO_TYPE_GENERICINST:
2165                 type = &type->data.generic_class->container_class->byval_arg;
2166                 goto handle_enum;
2167         case MONO_TYPE_VAR:
2168         case MONO_TYPE_MVAR:
2169                 /* gsharedvt */
2170                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2171         default:
2172                 g_error ("unknown type 0x%02x in ret_type_to_call_opcode", type->type);
2173         }
2174         return -1;
2175 }
2176
2177 //XXX this ignores if t is byref
2178 #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)))))
2179
2180 /*
2181  * target_type_is_incompatible:
2182  * @cfg: MonoCompile context
2183  *
2184  * Check that the item @arg on the evaluation stack can be stored
2185  * in the target type (can be a local, or field, etc).
2186  * The cfg arg can be used to check if we need verification or just
2187  * validity checks.
2188  *
2189  * Returns: non-0 value if arg can't be stored on a target.
2190  */
2191 static int
2192 target_type_is_incompatible (MonoCompile *cfg, MonoType *target, MonoInst *arg)
2193 {
2194         MonoType *simple_type;
2195         MonoClass *klass;
2196
2197         if (target->byref) {
2198                 /* FIXME: check that the pointed to types match */
2199                 if (arg->type == STACK_MP) {
2200                         /* This is needed to handle gshared types + ldaddr. We lower the types so we can handle enums and other typedef-like types. */
2201                         MonoClass *target_class_lowered = mono_class_from_mono_type (mini_get_underlying_type (&mono_class_from_mono_type (target)->byval_arg));
2202                         MonoClass *source_class_lowered = mono_class_from_mono_type (mini_get_underlying_type (&arg->klass->byval_arg));
2203
2204                         /* if the target is native int& or same type */
2205                         if (target->type == MONO_TYPE_I || target_class_lowered == source_class_lowered)
2206                                 return 0;
2207
2208                         /* Both are primitive type byrefs and the source points to a larger type that the destination */
2209                         if (MONO_TYPE_IS_PRIMITIVE_SCALAR (&target_class_lowered->byval_arg) && MONO_TYPE_IS_PRIMITIVE_SCALAR (&source_class_lowered->byval_arg) &&
2210                                 mono_class_instance_size (target_class_lowered) <= mono_class_instance_size (source_class_lowered))
2211                                 return 0;
2212                         return 1;
2213                 }
2214                 if (arg->type == STACK_PTR)
2215                         return 0;
2216                 return 1;
2217         }
2218
2219         simple_type = mini_get_underlying_type (target);
2220         switch (simple_type->type) {
2221         case MONO_TYPE_VOID:
2222                 return 1;
2223         case MONO_TYPE_I1:
2224         case MONO_TYPE_U1:
2225         case MONO_TYPE_I2:
2226         case MONO_TYPE_U2:
2227         case MONO_TYPE_I4:
2228         case MONO_TYPE_U4:
2229                 if (arg->type != STACK_I4 && arg->type != STACK_PTR)
2230                         return 1;
2231                 return 0;
2232         case MONO_TYPE_PTR:
2233                 /* STACK_MP is needed when setting pinned locals */
2234                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2235                         return 1;
2236                 return 0;
2237         case MONO_TYPE_I:
2238         case MONO_TYPE_U:
2239         case MONO_TYPE_FNPTR:
2240                 /* 
2241                  * Some opcodes like ldloca returns 'transient pointers' which can be stored in
2242                  * in native int. (#688008).
2243                  */
2244                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2245                         return 1;
2246                 return 0;
2247         case MONO_TYPE_CLASS:
2248         case MONO_TYPE_STRING:
2249         case MONO_TYPE_OBJECT:
2250         case MONO_TYPE_SZARRAY:
2251         case MONO_TYPE_ARRAY:    
2252                 if (arg->type != STACK_OBJ)
2253                         return 1;
2254                 /* FIXME: check type compatibility */
2255                 return 0;
2256         case MONO_TYPE_I8:
2257         case MONO_TYPE_U8:
2258                 if (arg->type != STACK_I8)
2259                         return 1;
2260                 return 0;
2261         case MONO_TYPE_R4:
2262                 if (arg->type != cfg->r4_stack_type)
2263                         return 1;
2264                 return 0;
2265         case MONO_TYPE_R8:
2266                 if (arg->type != STACK_R8)
2267                         return 1;
2268                 return 0;
2269         case MONO_TYPE_VALUETYPE:
2270                 if (arg->type != STACK_VTYPE)
2271                         return 1;
2272                 klass = mono_class_from_mono_type (simple_type);
2273                 if (klass != arg->klass)
2274                         return 1;
2275                 return 0;
2276         case MONO_TYPE_TYPEDBYREF:
2277                 if (arg->type != STACK_VTYPE)
2278                         return 1;
2279                 klass = mono_class_from_mono_type (simple_type);
2280                 if (klass != arg->klass)
2281                         return 1;
2282                 return 0;
2283         case MONO_TYPE_GENERICINST:
2284                 if (mono_type_generic_inst_is_valuetype (simple_type)) {
2285                         MonoClass *target_class;
2286                         if (arg->type != STACK_VTYPE)
2287                                 return 1;
2288                         klass = mono_class_from_mono_type (simple_type);
2289                         target_class = mono_class_from_mono_type (target);
2290                         /* The second cases is needed when doing partial sharing */
2291                         if (klass != arg->klass && target_class != arg->klass && target_class != mono_class_from_mono_type (mini_get_underlying_type (&arg->klass->byval_arg)))
2292                                 return 1;
2293                         return 0;
2294                 } else {
2295                         if (arg->type != STACK_OBJ)
2296                                 return 1;
2297                         /* FIXME: check type compatibility */
2298                         return 0;
2299                 }
2300         case MONO_TYPE_VAR:
2301         case MONO_TYPE_MVAR:
2302                 g_assert (cfg->gshared);
2303                 if (mini_type_var_is_vt (simple_type)) {
2304                         if (arg->type != STACK_VTYPE)
2305                                 return 1;
2306                 } else {
2307                         if (arg->type != STACK_OBJ)
2308                                 return 1;
2309                 }
2310                 return 0;
2311         default:
2312                 g_error ("unknown type 0x%02x in target_type_is_incompatible", simple_type->type);
2313         }
2314         return 1;
2315 }
2316
2317 /*
2318  * Prepare arguments for passing to a function call.
2319  * Return a non-zero value if the arguments can't be passed to the given
2320  * signature.
2321  * The type checks are not yet complete and some conversions may need
2322  * casts on 32 or 64 bit architectures.
2323  *
2324  * FIXME: implement this using target_type_is_incompatible ()
2325  */
2326 static int
2327 check_call_signature (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args)
2328 {
2329         MonoType *simple_type;
2330         int i;
2331
2332         if (sig->hasthis) {
2333                 if (args [0]->type != STACK_OBJ && args [0]->type != STACK_MP && args [0]->type != STACK_PTR)
2334                         return 1;
2335                 args++;
2336         }
2337         for (i = 0; i < sig->param_count; ++i) {
2338                 if (sig->params [i]->byref) {
2339                         if (args [i]->type != STACK_MP && args [i]->type != STACK_PTR)
2340                                 return 1;
2341                         continue;
2342                 }
2343                 simple_type = mini_get_underlying_type (sig->params [i]);
2344 handle_enum:
2345                 switch (simple_type->type) {
2346                 case MONO_TYPE_VOID:
2347                         return 1;
2348                         continue;
2349                 case MONO_TYPE_I1:
2350                 case MONO_TYPE_U1:
2351                 case MONO_TYPE_I2:
2352                 case MONO_TYPE_U2:
2353                 case MONO_TYPE_I4:
2354                 case MONO_TYPE_U4:
2355                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR)
2356                                 return 1;
2357                         continue;
2358                 case MONO_TYPE_I:
2359                 case MONO_TYPE_U:
2360                 case MONO_TYPE_PTR:
2361                 case MONO_TYPE_FNPTR:
2362                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR && args [i]->type != STACK_MP && args [i]->type != STACK_OBJ)
2363                                 return 1;
2364                         continue;
2365                 case MONO_TYPE_CLASS:
2366                 case MONO_TYPE_STRING:
2367                 case MONO_TYPE_OBJECT:
2368                 case MONO_TYPE_SZARRAY:
2369                 case MONO_TYPE_ARRAY:    
2370                         if (args [i]->type != STACK_OBJ)
2371                                 return 1;
2372                         continue;
2373                 case MONO_TYPE_I8:
2374                 case MONO_TYPE_U8:
2375                         if (args [i]->type != STACK_I8)
2376                                 return 1;
2377                         continue;
2378                 case MONO_TYPE_R4:
2379                         if (args [i]->type != cfg->r4_stack_type)
2380                                 return 1;
2381                         continue;
2382                 case MONO_TYPE_R8:
2383                         if (args [i]->type != STACK_R8)
2384                                 return 1;
2385                         continue;
2386                 case MONO_TYPE_VALUETYPE:
2387                         if (simple_type->data.klass->enumtype) {
2388                                 simple_type = mono_class_enum_basetype (simple_type->data.klass);
2389                                 goto handle_enum;
2390                         }
2391                         if (args [i]->type != STACK_VTYPE)
2392                                 return 1;
2393                         continue;
2394                 case MONO_TYPE_TYPEDBYREF:
2395                         if (args [i]->type != STACK_VTYPE)
2396                                 return 1;
2397                         continue;
2398                 case MONO_TYPE_GENERICINST:
2399                         simple_type = &simple_type->data.generic_class->container_class->byval_arg;
2400                         goto handle_enum;
2401                 case MONO_TYPE_VAR:
2402                 case MONO_TYPE_MVAR:
2403                         /* gsharedvt */
2404                         if (args [i]->type != STACK_VTYPE)
2405                                 return 1;
2406                         continue;
2407                 default:
2408                         g_error ("unknown type 0x%02x in check_call_signature",
2409                                  simple_type->type);
2410                 }
2411         }
2412         return 0;
2413 }
2414
2415 static int
2416 callvirt_to_call (int opcode)
2417 {
2418         switch (opcode) {
2419         case OP_CALL_MEMBASE:
2420                 return OP_CALL;
2421         case OP_VOIDCALL_MEMBASE:
2422                 return OP_VOIDCALL;
2423         case OP_FCALL_MEMBASE:
2424                 return OP_FCALL;
2425         case OP_RCALL_MEMBASE:
2426                 return OP_RCALL;
2427         case OP_VCALL_MEMBASE:
2428                 return OP_VCALL;
2429         case OP_LCALL_MEMBASE:
2430                 return OP_LCALL;
2431         default:
2432                 g_assert_not_reached ();
2433         }
2434
2435         return -1;
2436 }
2437
2438 static int
2439 callvirt_to_call_reg (int opcode)
2440 {
2441         switch (opcode) {
2442         case OP_CALL_MEMBASE:
2443                 return OP_CALL_REG;
2444         case OP_VOIDCALL_MEMBASE:
2445                 return OP_VOIDCALL_REG;
2446         case OP_FCALL_MEMBASE:
2447                 return OP_FCALL_REG;
2448         case OP_RCALL_MEMBASE:
2449                 return OP_RCALL_REG;
2450         case OP_VCALL_MEMBASE:
2451                 return OP_VCALL_REG;
2452         case OP_LCALL_MEMBASE:
2453                 return OP_LCALL_REG;
2454         default:
2455                 g_assert_not_reached ();
2456         }
2457
2458         return -1;
2459 }
2460
2461 /* Either METHOD or IMT_ARG needs to be set */
2462 static void
2463 emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoMethod *method, MonoInst *imt_arg)
2464 {
2465         int method_reg;
2466
2467         if (COMPILE_LLVM (cfg)) {
2468                 if (imt_arg) {
2469                         method_reg = alloc_preg (cfg);
2470                         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2471                 } else {
2472                         MonoInst *ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_METHODCONST, method);
2473                         method_reg = ins->dreg;
2474                 }
2475
2476 #ifdef ENABLE_LLVM
2477                 call->imt_arg_reg = method_reg;
2478 #endif
2479                 mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2480                 return;
2481         }
2482
2483         if (imt_arg) {
2484                 method_reg = alloc_preg (cfg);
2485                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2486         } else {
2487                 MonoInst *ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_METHODCONST, method);
2488                 method_reg = ins->dreg;
2489         }
2490
2491         mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2492 }
2493
2494 static MonoJumpInfo *
2495 mono_patch_info_new (MonoMemPool *mp, int ip, MonoJumpInfoType type, gconstpointer target)
2496 {
2497         MonoJumpInfo *ji = (MonoJumpInfo *)mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
2498
2499         ji->ip.i = ip;
2500         ji->type = type;
2501         ji->data.target = target;
2502
2503         return ji;
2504 }
2505
2506 static int
2507 mini_class_check_context_used (MonoCompile *cfg, MonoClass *klass)
2508 {
2509         if (cfg->gshared)
2510                 return mono_class_check_context_used (klass);
2511         else
2512                 return 0;
2513 }
2514
2515 static int
2516 mini_method_check_context_used (MonoCompile *cfg, MonoMethod *method)
2517 {
2518         if (cfg->gshared)
2519                 return mono_method_check_context_used (method);
2520         else
2521                 return 0;
2522 }
2523
2524 /*
2525  * check_method_sharing:
2526  *
2527  *   Check whenever the vtable or an mrgctx needs to be passed when calling CMETHOD.
2528  */
2529 static void
2530 check_method_sharing (MonoCompile *cfg, MonoMethod *cmethod, gboolean *out_pass_vtable, gboolean *out_pass_mrgctx)
2531 {
2532         gboolean pass_vtable = FALSE;
2533         gboolean pass_mrgctx = FALSE;
2534
2535         if (((cmethod->flags & METHOD_ATTRIBUTE_STATIC) || cmethod->klass->valuetype) &&
2536                 (cmethod->klass->generic_class || cmethod->klass->generic_container)) {
2537                 gboolean sharable = FALSE;
2538
2539                 if (mono_method_is_generic_sharable_full (cmethod, TRUE, TRUE, TRUE))
2540                         sharable = TRUE;
2541
2542                 /*
2543                  * Pass vtable iff target method might
2544                  * be shared, which means that sharing
2545                  * is enabled for its class and its
2546                  * context is sharable (and it's not a
2547                  * generic method).
2548                  */
2549                 if (sharable && !(mini_method_get_context (cmethod) && mini_method_get_context (cmethod)->method_inst))
2550                         pass_vtable = TRUE;
2551         }
2552
2553         if (mini_method_get_context (cmethod) &&
2554                 mini_method_get_context (cmethod)->method_inst) {
2555                 g_assert (!pass_vtable);
2556
2557                 if (mono_method_is_generic_sharable_full (cmethod, TRUE, TRUE, TRUE)) {
2558                         pass_mrgctx = TRUE;
2559                 } else {
2560                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (mono_method_signature (cmethod)))
2561                                 pass_mrgctx = TRUE;
2562                 }
2563         }
2564
2565         if (out_pass_vtable)
2566                 *out_pass_vtable = pass_vtable;
2567         if (out_pass_mrgctx)
2568                 *out_pass_mrgctx = pass_mrgctx;
2569 }
2570
2571 inline static MonoCallInst *
2572 mono_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig, 
2573                                          MonoInst **args, int calli, int virtual_, int tail, int rgctx, int unbox_trampoline)
2574 {
2575         MonoType *sig_ret;
2576         MonoCallInst *call;
2577 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2578         int i;
2579 #endif
2580
2581         if (cfg->llvm_only)
2582                 tail = FALSE;
2583
2584         if (tail) {
2585                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
2586
2587                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
2588         } else
2589                 MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (cfg, sig->ret, calli, virtual_));
2590
2591         call->args = args;
2592         call->signature = sig;
2593         call->rgctx_reg = rgctx;
2594         sig_ret = mini_get_underlying_type (sig->ret);
2595
2596         type_to_eval_stack_type ((cfg), sig_ret, &call->inst);
2597
2598         if (tail) {
2599                 if (mini_type_is_vtype (sig_ret)) {
2600                         call->vret_var = cfg->vret_addr;
2601                         //g_assert_not_reached ();
2602                 }
2603         } else if (mini_type_is_vtype (sig_ret)) {
2604                 MonoInst *temp = mono_compile_create_var (cfg, sig_ret, OP_LOCAL);
2605                 MonoInst *loada;
2606
2607                 temp->backend.is_pinvoke = sig->pinvoke;
2608
2609                 /*
2610                  * We use a new opcode OP_OUTARG_VTRETADDR instead of LDADDR for emitting the
2611                  * address of return value to increase optimization opportunities.
2612                  * Before vtype decomposition, the dreg of the call ins itself represents the
2613                  * fact the call modifies the return value. After decomposition, the call will
2614                  * be transformed into one of the OP_VOIDCALL opcodes, and the VTRETADDR opcode
2615                  * will be transformed into an LDADDR.
2616                  */
2617                 MONO_INST_NEW (cfg, loada, OP_OUTARG_VTRETADDR);
2618                 loada->dreg = alloc_preg (cfg);
2619                 loada->inst_p0 = temp;
2620                 /* We reference the call too since call->dreg could change during optimization */
2621                 loada->inst_p1 = call;
2622                 MONO_ADD_INS (cfg->cbb, loada);
2623
2624                 call->inst.dreg = temp->dreg;
2625
2626                 call->vret_var = loada;
2627         } else if (!MONO_TYPE_IS_VOID (sig_ret))
2628                 call->inst.dreg = alloc_dreg (cfg, (MonoStackType)call->inst.type);
2629
2630 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2631         if (COMPILE_SOFT_FLOAT (cfg)) {
2632                 /* 
2633                  * If the call has a float argument, we would need to do an r8->r4 conversion using 
2634                  * an icall, but that cannot be done during the call sequence since it would clobber
2635                  * the call registers + the stack. So we do it before emitting the call.
2636                  */
2637                 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2638                         MonoType *t;
2639                         MonoInst *in = call->args [i];
2640
2641                         if (i >= sig->hasthis)
2642                                 t = sig->params [i - sig->hasthis];
2643                         else
2644                                 t = &mono_defaults.int_class->byval_arg;
2645                         t = mono_type_get_underlying_type (t);
2646
2647                         if (!t->byref && t->type == MONO_TYPE_R4) {
2648                                 MonoInst *iargs [1];
2649                                 MonoInst *conv;
2650
2651                                 iargs [0] = in;
2652                                 conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
2653
2654                                 /* The result will be in an int vreg */
2655                                 call->args [i] = conv;
2656                         }
2657                 }
2658         }
2659 #endif
2660
2661         call->need_unbox_trampoline = unbox_trampoline;
2662
2663 #ifdef ENABLE_LLVM
2664         if (COMPILE_LLVM (cfg))
2665                 mono_llvm_emit_call (cfg, call);
2666         else
2667                 mono_arch_emit_call (cfg, call);
2668 #else
2669         mono_arch_emit_call (cfg, call);
2670 #endif
2671
2672         cfg->param_area = MAX (cfg->param_area, call->stack_usage);
2673         cfg->flags |= MONO_CFG_HAS_CALLS;
2674         
2675         return call;
2676 }
2677
2678 static void
2679 set_rgctx_arg (MonoCompile *cfg, MonoCallInst *call, int rgctx_reg, MonoInst *rgctx_arg)
2680 {
2681         mono_call_inst_add_outarg_reg (cfg, call, rgctx_reg, MONO_ARCH_RGCTX_REG, FALSE);
2682         cfg->uses_rgctx_reg = TRUE;
2683         call->rgctx_reg = TRUE;
2684 #ifdef ENABLE_LLVM
2685         call->rgctx_arg_reg = rgctx_reg;
2686 #endif
2687 }       
2688
2689 inline static MonoInst*
2690 mono_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr, MonoInst *imt_arg, MonoInst *rgctx_arg)
2691 {
2692         MonoCallInst *call;
2693         MonoInst *ins;
2694         int rgctx_reg = -1;
2695         gboolean check_sp = FALSE;
2696
2697         if (cfg->check_pinvoke_callconv && cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
2698                 WrapperInfo *info = mono_marshal_get_wrapper_info (cfg->method);
2699
2700                 if (info && info->subtype == WRAPPER_SUBTYPE_PINVOKE)
2701                         check_sp = TRUE;
2702         }
2703
2704         if (rgctx_arg) {
2705                 rgctx_reg = mono_alloc_preg (cfg);
2706                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2707         }
2708
2709         if (check_sp) {
2710                 if (!cfg->stack_inbalance_var)
2711                         cfg->stack_inbalance_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2712
2713                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2714                 ins->dreg = cfg->stack_inbalance_var->dreg;
2715                 MONO_ADD_INS (cfg->cbb, ins);
2716         }
2717
2718         call = mono_emit_call_args (cfg, sig, args, TRUE, FALSE, FALSE, rgctx_arg ? TRUE : FALSE, FALSE);
2719
2720         call->inst.sreg1 = addr->dreg;
2721
2722         if (imt_arg)
2723                 emit_imt_argument (cfg, call, NULL, imt_arg);
2724
2725         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2726
2727         if (check_sp) {
2728                 int sp_reg;
2729
2730                 sp_reg = mono_alloc_preg (cfg);
2731
2732                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2733                 ins->dreg = sp_reg;
2734                 MONO_ADD_INS (cfg->cbb, ins);
2735
2736                 /* Restore the stack so we don't crash when throwing the exception */
2737                 MONO_INST_NEW (cfg, ins, OP_SET_SP);
2738                 ins->sreg1 = cfg->stack_inbalance_var->dreg;
2739                 MONO_ADD_INS (cfg->cbb, ins);
2740
2741                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, cfg->stack_inbalance_var->dreg, sp_reg);
2742                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ExecutionEngineException");
2743         }
2744
2745         if (rgctx_arg)
2746                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2747
2748         return (MonoInst*)call;
2749 }
2750
2751 static MonoInst*
2752 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2753
2754 static MonoInst*
2755 emit_get_rgctx_method (MonoCompile *cfg, int context_used, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type);
2756 static MonoInst*
2757 emit_get_rgctx_klass (MonoCompile *cfg, int context_used, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2758
2759 static MonoInst*
2760 mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSignature *sig, gboolean tail,
2761                                                         MonoInst **args, MonoInst *this_ins, MonoInst *imt_arg, MonoInst *rgctx_arg)
2762 {
2763 #ifndef DISABLE_REMOTING
2764         gboolean might_be_remote = FALSE;
2765 #endif
2766         gboolean virtual_ = this_ins != NULL;
2767         gboolean enable_for_aot = TRUE;
2768         int context_used;
2769         MonoCallInst *call;
2770         MonoInst *call_target = NULL;
2771         int rgctx_reg = 0;
2772         gboolean need_unbox_trampoline;
2773
2774         if (!sig)
2775                 sig = mono_method_signature (method);
2776
2777         if (cfg->llvm_only && (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE))
2778                 g_assert_not_reached ();
2779
2780         if (rgctx_arg) {
2781                 rgctx_reg = mono_alloc_preg (cfg);
2782                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2783         }
2784
2785         if (method->string_ctor) {
2786                 /* Create the real signature */
2787                 /* FIXME: Cache these */
2788                 MonoMethodSignature *ctor_sig = mono_metadata_signature_dup_mempool (cfg->mempool, sig);
2789                 ctor_sig->ret = &mono_defaults.string_class->byval_arg;
2790
2791                 sig = ctor_sig;
2792         }
2793
2794         context_used = mini_method_check_context_used (cfg, method);
2795
2796 #ifndef DISABLE_REMOTING
2797         might_be_remote = this_ins && sig->hasthis &&
2798                 (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) &&
2799                 !(method->flags & METHOD_ATTRIBUTE_VIRTUAL) && (!MONO_CHECK_THIS (this_ins) || context_used);
2800
2801         if (might_be_remote && context_used) {
2802                 MonoInst *addr;
2803
2804                 g_assert (cfg->gshared);
2805
2806                 addr = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK);
2807
2808                 return mono_emit_calli (cfg, sig, args, addr, NULL, NULL);
2809         }
2810 #endif
2811
2812         if (cfg->llvm_only && !call_target && virtual_ && (method->flags & METHOD_ATTRIBUTE_VIRTUAL))
2813                 return emit_llvmonly_virtual_call (cfg, method, sig, 0, args);
2814
2815         need_unbox_trampoline = method->klass == mono_defaults.object_class || (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE);
2816
2817         call = mono_emit_call_args (cfg, sig, args, FALSE, virtual_, tail, rgctx_arg ? TRUE : FALSE, need_unbox_trampoline);
2818
2819 #ifndef DISABLE_REMOTING
2820         if (might_be_remote)
2821                 call->method = mono_marshal_get_remoting_invoke_with_check (method);
2822         else
2823 #endif
2824                 call->method = method;
2825         call->inst.flags |= MONO_INST_HAS_METHOD;
2826         call->inst.inst_left = this_ins;
2827         call->tail_call = tail;
2828
2829         if (virtual_) {
2830                 int vtable_reg, slot_reg, this_reg;
2831                 int offset;
2832
2833                 this_reg = this_ins->dreg;
2834
2835                 if (!cfg->llvm_only && (method->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (method->name, "Invoke")) {
2836                         MonoInst *dummy_use;
2837
2838                         MONO_EMIT_NULL_CHECK (cfg, this_reg);
2839
2840                         /* Make a call to delegate->invoke_impl */
2841                         call->inst.inst_basereg = this_reg;
2842                         call->inst.inst_offset = MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl);
2843                         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2844
2845                         /* We must emit a dummy use here because the delegate trampoline will
2846                         replace the 'this' argument with the delegate target making this activation
2847                         no longer a root for the delegate.
2848                         This is an issue for delegates that target collectible code such as dynamic
2849                         methods of GC'able assemblies.
2850
2851                         For a test case look into #667921.
2852
2853                         FIXME: a dummy use is not the best way to do it as the local register allocator
2854                         will put it on a caller save register and spil it around the call. 
2855                         Ideally, we would either put it on a callee save register or only do the store part.  
2856                          */
2857                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, args [0]);
2858
2859                         return (MonoInst*)call;
2860                 }
2861
2862                 if ((!cfg->compile_aot || enable_for_aot) && 
2863                         (!(method->flags & METHOD_ATTRIBUTE_VIRTUAL) || 
2864                          (MONO_METHOD_IS_FINAL (method) &&
2865                           method->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)) &&
2866                         !(mono_class_is_marshalbyref (method->klass) && context_used)) {
2867                         /* 
2868                          * the method is not virtual, we just need to ensure this is not null
2869                          * and then we can call the method directly.
2870                          */
2871 #ifndef DISABLE_REMOTING
2872                         if (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) {
2873                                 /* 
2874                                  * The check above ensures method is not gshared, this is needed since
2875                                  * gshared methods can't have wrappers.
2876                                  */
2877                                 method = call->method = mono_marshal_get_remoting_invoke_with_check (method);
2878                         }
2879 #endif
2880
2881                         if (!method->string_ctor)
2882                                 MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2883
2884                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2885                 } else if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && MONO_METHOD_IS_FINAL (method)) {
2886                         /*
2887                          * the method is virtual, but we can statically dispatch since either
2888                          * it's class or the method itself are sealed.
2889                          * But first we need to ensure it's not a null reference.
2890                          */
2891                         MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2892
2893                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2894                 } else if (call_target) {
2895                         vtable_reg = alloc_preg (cfg);
2896                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
2897
2898                         call->inst.opcode = callvirt_to_call_reg (call->inst.opcode);
2899                         call->inst.sreg1 = call_target->dreg;
2900                         call->inst.flags &= !MONO_INST_HAS_METHOD;
2901                 } else {
2902                         vtable_reg = alloc_preg (cfg);
2903                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
2904                         if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2905                                 guint32 imt_slot = mono_method_get_imt_slot (method);
2906                                 emit_imt_argument (cfg, call, call->method, imt_arg);
2907                                 slot_reg = vtable_reg;
2908                                 offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
2909                         } else {
2910                                 slot_reg = vtable_reg;
2911                                 offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) +
2912                                         ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
2913                                 if (imt_arg) {
2914                                         g_assert (mono_method_signature (method)->generic_param_count);
2915                                         emit_imt_argument (cfg, call, call->method, imt_arg);
2916                                 }
2917                         }
2918
2919                         call->inst.sreg1 = slot_reg;
2920                         call->inst.inst_offset = offset;
2921                         call->is_virtual = TRUE;
2922                 }
2923         }
2924
2925         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2926
2927         if (rgctx_arg)
2928                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2929
2930         return (MonoInst*)call;
2931 }
2932
2933 MonoInst*
2934 mono_emit_method_call (MonoCompile *cfg, MonoMethod *method, MonoInst **args, MonoInst *this_ins)
2935 {
2936         return mono_emit_method_call_full (cfg, method, mono_method_signature (method), FALSE, args, this_ins, NULL, NULL);
2937 }
2938
2939 MonoInst*
2940 mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig,
2941                                            MonoInst **args)
2942 {
2943         MonoCallInst *call;
2944
2945         g_assert (sig);
2946
2947         call = mono_emit_call_args (cfg, sig, args, FALSE, FALSE, FALSE, FALSE, FALSE);
2948         call->fptr = func;
2949
2950         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2951
2952         return (MonoInst*)call;
2953 }
2954
2955 MonoInst*
2956 mono_emit_jit_icall (MonoCompile *cfg, gconstpointer func, MonoInst **args)
2957 {
2958         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (func);
2959
2960         g_assert (info);
2961
2962         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
2963 }
2964
2965 /*
2966  * mono_emit_abs_call:
2967  *
2968  *   Emit a call to the runtime function described by PATCH_TYPE and DATA.
2969  */
2970 inline static MonoInst*
2971 mono_emit_abs_call (MonoCompile *cfg, MonoJumpInfoType patch_type, gconstpointer data, 
2972                                         MonoMethodSignature *sig, MonoInst **args)
2973 {
2974         MonoJumpInfo *ji = mono_patch_info_new (cfg->mempool, 0, patch_type, data);
2975         MonoInst *ins;
2976
2977         /* 
2978          * We pass ji as the call address, the PATCH_INFO_ABS resolving code will
2979          * handle it.
2980          */
2981         if (cfg->abs_patches == NULL)
2982                 cfg->abs_patches = g_hash_table_new (NULL, NULL);
2983         g_hash_table_insert (cfg->abs_patches, ji, ji);
2984         ins = mono_emit_native_call (cfg, ji, sig, args);
2985         ((MonoCallInst*)ins)->fptr_is_patch = TRUE;
2986         return ins;
2987 }
2988
2989 static MonoMethodSignature*
2990 sig_to_rgctx_sig (MonoMethodSignature *sig)
2991 {
2992         // FIXME: memory allocation
2993         MonoMethodSignature *res;
2994         int i;
2995
2996         res = (MonoMethodSignature *)g_malloc (MONO_SIZEOF_METHOD_SIGNATURE + (sig->param_count + 1) * sizeof (MonoType*));
2997         memcpy (res, sig, MONO_SIZEOF_METHOD_SIGNATURE);
2998         res->param_count = sig->param_count + 1;
2999         for (i = 0; i < sig->param_count; ++i)
3000                 res->params [i] = sig->params [i];
3001         res->params [sig->param_count] = &mono_defaults.int_class->this_arg;
3002         return res;
3003 }
3004
3005 /* Make an indirect call to FSIG passing an additional argument */
3006 static MonoInst*
3007 emit_extra_arg_calli (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **orig_args, int arg_reg, MonoInst *call_target)
3008 {
3009         MonoMethodSignature *csig;
3010         MonoInst *args_buf [16];
3011         MonoInst **args;
3012         int i, pindex, tmp_reg;
3013
3014         /* Make a call with an rgctx/extra arg */
3015         if (fsig->param_count + 2 < 16)
3016                 args = args_buf;
3017         else
3018                 args = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (fsig->param_count + 2));
3019         pindex = 0;
3020         if (fsig->hasthis)
3021                 args [pindex ++] = orig_args [0];
3022         for (i = 0; i < fsig->param_count; ++i)
3023                 args [pindex ++] = orig_args [fsig->hasthis + i];
3024         tmp_reg = alloc_preg (cfg);
3025         EMIT_NEW_UNALU (cfg, args [pindex], OP_MOVE, tmp_reg, arg_reg);
3026         csig = sig_to_rgctx_sig (fsig);
3027         return mono_emit_calli (cfg, csig, args, call_target, NULL, NULL);
3028 }
3029
3030 /* Emit an indirect call to the function descriptor ADDR */
3031 static MonoInst*
3032 emit_llvmonly_calli (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, MonoInst *addr)
3033 {
3034         int addr_reg, arg_reg;
3035         MonoInst *call_target;
3036
3037         g_assert (cfg->llvm_only);
3038
3039         /*
3040          * addr points to a <addr, arg> pair, load both of them, and
3041          * make a call to addr, passing arg as an extra arg.
3042          */
3043         addr_reg = alloc_preg (cfg);
3044         EMIT_NEW_LOAD_MEMBASE (cfg, call_target, OP_LOAD_MEMBASE, addr_reg, addr->dreg, 0);
3045         arg_reg = alloc_preg (cfg);
3046         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, arg_reg, addr->dreg, sizeof (gpointer));
3047
3048         return emit_extra_arg_calli (cfg, fsig, args, arg_reg, call_target);
3049 }
3050
3051 static gboolean
3052 direct_icalls_enabled (MonoCompile *cfg)
3053 {
3054         /* LLVM on amd64 can't handle calls to non-32 bit addresses */
3055 #ifdef TARGET_AMD64
3056         if (cfg->compile_llvm && !cfg->llvm_only)
3057                 return FALSE;
3058 #endif
3059         if (cfg->gen_sdb_seq_points || cfg->disable_direct_icalls)
3060                 return FALSE;
3061         return TRUE;
3062 }
3063
3064 MonoInst*
3065 mono_emit_jit_icall_by_info (MonoCompile *cfg, int il_offset, MonoJitICallInfo *info, MonoInst **args)
3066 {
3067         /*
3068          * Call the jit icall without a wrapper if possible.
3069          * The wrapper is needed for the following reasons:
3070          * - to handle exceptions thrown using mono_raise_exceptions () from the
3071          *   icall function. The EH code needs the lmf frame pushed by the
3072          *   wrapper to be able to unwind back to managed code.
3073          * - to be able to do stack walks for asynchronously suspended
3074          *   threads when debugging.
3075          */
3076         if (info->no_raise && direct_icalls_enabled (cfg)) {
3077                 char *name;
3078                 int costs;
3079
3080                 if (!info->wrapper_method) {
3081                         name = g_strdup_printf ("__icall_wrapper_%s", info->name);
3082                         info->wrapper_method = mono_marshal_get_icall_wrapper (info->sig, name, info->func, TRUE);
3083                         g_free (name);
3084                         mono_memory_barrier ();
3085                 }
3086
3087                 /*
3088                  * Inline the wrapper method, which is basically a call to the C icall, and
3089                  * an exception check.
3090                  */
3091                 costs = inline_method (cfg, info->wrapper_method, NULL,
3092                                                            args, NULL, il_offset, TRUE);
3093                 g_assert (costs > 0);
3094                 g_assert (!MONO_TYPE_IS_VOID (info->sig->ret));
3095
3096                 return args [0];
3097         } else {
3098                 return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
3099         }
3100 }
3101  
3102 static MonoInst*
3103 mono_emit_widen_call_res (MonoCompile *cfg, MonoInst *ins, MonoMethodSignature *fsig)
3104 {
3105         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
3106                 if ((fsig->pinvoke || LLVM_ENABLED) && !fsig->ret->byref) {
3107                         int widen_op = -1;
3108
3109                         /* 
3110                          * Native code might return non register sized integers 
3111                          * without initializing the upper bits.
3112                          */
3113                         switch (mono_type_to_load_membase (cfg, fsig->ret)) {
3114                         case OP_LOADI1_MEMBASE:
3115                                 widen_op = OP_ICONV_TO_I1;
3116                                 break;
3117                         case OP_LOADU1_MEMBASE:
3118                                 widen_op = OP_ICONV_TO_U1;
3119                                 break;
3120                         case OP_LOADI2_MEMBASE:
3121                                 widen_op = OP_ICONV_TO_I2;
3122                                 break;
3123                         case OP_LOADU2_MEMBASE:
3124                                 widen_op = OP_ICONV_TO_U2;
3125                                 break;
3126                         default:
3127                                 break;
3128                         }
3129
3130                         if (widen_op != -1) {
3131                                 int dreg = alloc_preg (cfg);
3132                                 MonoInst *widen;
3133
3134                                 EMIT_NEW_UNALU (cfg, widen, widen_op, dreg, ins->dreg);
3135                                 widen->type = ins->type;
3136                                 ins = widen;
3137                         }
3138                 }
3139         }
3140
3141         return ins;
3142 }
3143
3144
3145 static void
3146 emit_method_access_failure (MonoCompile *cfg, MonoMethod *method, MonoMethod *cil_method)
3147 {
3148         MonoInst *args [16];
3149
3150         args [0] = emit_get_rgctx_method (cfg, mono_method_check_context_used (method), method, MONO_RGCTX_INFO_METHOD);
3151         args [1] = emit_get_rgctx_method (cfg, mono_method_check_context_used (cil_method), cil_method, MONO_RGCTX_INFO_METHOD);
3152
3153         mono_emit_jit_icall (cfg, mono_throw_method_access, args);
3154 }
3155
3156 static MonoMethod*
3157 get_memcpy_method (void)
3158 {
3159         static MonoMethod *memcpy_method = NULL;
3160         if (!memcpy_method) {
3161                 memcpy_method = mono_class_get_method_from_name (mono_defaults.string_class, "memcpy", 3);
3162                 if (!memcpy_method)
3163                         g_error ("Old corlib found. Install a new one");
3164         }
3165         return memcpy_method;
3166 }
3167
3168 static void
3169 create_write_barrier_bitmap (MonoCompile *cfg, MonoClass *klass, unsigned *wb_bitmap, int offset)
3170 {
3171         MonoClassField *field;
3172         gpointer iter = NULL;
3173
3174         while ((field = mono_class_get_fields (klass, &iter))) {
3175                 int foffset;
3176
3177                 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
3178                         continue;
3179                 foffset = klass->valuetype ? field->offset - sizeof (MonoObject): field->offset;
3180                 if (mini_type_is_reference (mono_field_get_type (field))) {
3181                         g_assert ((foffset % SIZEOF_VOID_P) == 0);
3182                         *wb_bitmap |= 1 << ((offset + foffset) / SIZEOF_VOID_P);
3183                 } else {
3184                         MonoClass *field_class = mono_class_from_mono_type (field->type);
3185                         if (field_class->has_references)
3186                                 create_write_barrier_bitmap (cfg, field_class, wb_bitmap, offset + foffset);
3187                 }
3188         }
3189 }
3190
3191 static void
3192 emit_write_barrier (MonoCompile *cfg, MonoInst *ptr, MonoInst *value)
3193 {
3194         int card_table_shift_bits;
3195         gpointer card_table_mask;
3196         guint8 *card_table;
3197         MonoInst *dummy_use;
3198         int nursery_shift_bits;
3199         size_t nursery_size;
3200
3201         if (!cfg->gen_write_barriers)
3202                 return;
3203
3204         card_table = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
3205
3206         mono_gc_get_nursery (&nursery_shift_bits, &nursery_size);
3207
3208         if (cfg->backend->have_card_table_wb && !cfg->compile_aot && card_table && nursery_shift_bits > 0 && !COMPILE_LLVM (cfg)) {
3209                 MonoInst *wbarrier;
3210
3211                 MONO_INST_NEW (cfg, wbarrier, OP_CARD_TABLE_WBARRIER);
3212                 wbarrier->sreg1 = ptr->dreg;
3213                 wbarrier->sreg2 = value->dreg;
3214                 MONO_ADD_INS (cfg->cbb, wbarrier);
3215         } else if (card_table && !cfg->compile_aot && !mono_gc_card_table_nursery_check ()) {
3216                 int offset_reg = alloc_preg (cfg);
3217                 int card_reg;
3218                 MonoInst *ins;
3219
3220                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, offset_reg, ptr->dreg, card_table_shift_bits);
3221                 if (card_table_mask)
3222                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, offset_reg, offset_reg, card_table_mask);
3223
3224                 /*We can't use PADD_IMM since the cardtable might end up in high addresses and amd64 doesn't support
3225                  * IMM's larger than 32bits.
3226                  */
3227                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR, NULL);
3228                 card_reg = ins->dreg;
3229
3230                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, offset_reg, offset_reg, card_reg);
3231                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, offset_reg, 0, 1);
3232         } else {
3233                 MonoMethod *write_barrier = mono_gc_get_write_barrier ();
3234                 mono_emit_method_call (cfg, write_barrier, &ptr, NULL);
3235         }
3236
3237         EMIT_NEW_DUMMY_USE (cfg, dummy_use, value);
3238 }
3239
3240 static gboolean
3241 mono_emit_wb_aware_memcpy (MonoCompile *cfg, MonoClass *klass, MonoInst *iargs[4], int size, int align)
3242 {
3243         int dest_ptr_reg, tmp_reg, destreg, srcreg, offset;
3244         unsigned need_wb = 0;
3245
3246         if (align == 0)
3247                 align = 4;
3248
3249         /*types with references can't have alignment smaller than sizeof(void*) */
3250         if (align < SIZEOF_VOID_P)
3251                 return FALSE;
3252
3253         /*This value cannot be bigger than 32 due to the way we calculate the required wb bitmap.*/
3254         if (size > 32 * SIZEOF_VOID_P)
3255                 return FALSE;
3256
3257         create_write_barrier_bitmap (cfg, klass, &need_wb, 0);
3258
3259         /* We don't unroll more than 5 stores to avoid code bloat. */
3260         if (size > 5 * SIZEOF_VOID_P) {
3261                 /*This is harmless and simplify mono_gc_wbarrier_value_copy_bitmap */
3262                 size += (SIZEOF_VOID_P - 1);
3263                 size &= ~(SIZEOF_VOID_P - 1);
3264
3265                 EMIT_NEW_ICONST (cfg, iargs [2], size);
3266                 EMIT_NEW_ICONST (cfg, iargs [3], need_wb);
3267                 mono_emit_jit_icall (cfg, mono_gc_wbarrier_value_copy_bitmap, iargs);
3268                 return TRUE;
3269         }
3270
3271         destreg = iargs [0]->dreg;
3272         srcreg = iargs [1]->dreg;
3273         offset = 0;
3274
3275         dest_ptr_reg = alloc_preg (cfg);
3276         tmp_reg = alloc_preg (cfg);
3277
3278         /*tmp = dreg*/
3279         EMIT_NEW_UNALU (cfg, iargs [0], OP_MOVE, dest_ptr_reg, destreg);
3280
3281         while (size >= SIZEOF_VOID_P) {
3282                 MonoInst *load_inst;
3283                 MONO_INST_NEW (cfg, load_inst, OP_LOAD_MEMBASE);
3284                 load_inst->dreg = tmp_reg;
3285                 load_inst->inst_basereg = srcreg;
3286                 load_inst->inst_offset = offset;
3287                 MONO_ADD_INS (cfg->cbb, load_inst);
3288
3289                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, dest_ptr_reg, 0, tmp_reg);
3290
3291                 if (need_wb & 0x1)
3292                         emit_write_barrier (cfg, iargs [0], load_inst);
3293
3294                 offset += SIZEOF_VOID_P;
3295                 size -= SIZEOF_VOID_P;
3296                 need_wb >>= 1;
3297
3298                 /*tmp += sizeof (void*)*/
3299                 if (size >= SIZEOF_VOID_P) {
3300                         NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, dest_ptr_reg, dest_ptr_reg, SIZEOF_VOID_P);
3301                         MONO_ADD_INS (cfg->cbb, iargs [0]);
3302                 }
3303         }
3304
3305         /* Those cannot be references since size < sizeof (void*) */
3306         while (size >= 4) {
3307                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tmp_reg, srcreg, offset);
3308                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, tmp_reg);
3309                 offset += 4;
3310                 size -= 4;
3311         }
3312
3313         while (size >= 2) {
3314                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmp_reg, srcreg, offset);
3315                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, tmp_reg);
3316                 offset += 2;
3317                 size -= 2;
3318         }
3319
3320         while (size >= 1) {
3321                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmp_reg, srcreg, offset);
3322                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, tmp_reg);
3323                 offset += 1;
3324                 size -= 1;
3325         }
3326
3327         return TRUE;
3328 }
3329
3330 /*
3331  * Emit code to copy a valuetype of type @klass whose address is stored in
3332  * @src->dreg to memory whose address is stored at @dest->dreg.
3333  */
3334 void
3335 mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native)
3336 {
3337         MonoInst *iargs [4];
3338         int n;
3339         guint32 align = 0;
3340         MonoMethod *memcpy_method;
3341         MonoInst *size_ins = NULL;
3342         MonoInst *memcpy_ins = NULL;
3343
3344         g_assert (klass);
3345         if (cfg->gshared)
3346                 klass = mono_class_from_mono_type (mini_get_underlying_type (&klass->byval_arg));
3347
3348         /*
3349          * This check breaks with spilled vars... need to handle it during verification anyway.
3350          * g_assert (klass && klass == src->klass && klass == dest->klass);
3351          */
3352
3353         if (mini_is_gsharedvt_klass (klass)) {
3354                 g_assert (!native);
3355                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3356                 memcpy_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_MEMCPY);
3357         }
3358
3359         if (native)
3360                 n = mono_class_native_size (klass, &align);
3361         else
3362                 n = mono_class_value_size (klass, &align);
3363
3364         /* if native is true there should be no references in the struct */
3365         if (cfg->gen_write_barriers && (klass->has_references || size_ins) && !native) {
3366                 /* Avoid barriers when storing to the stack */
3367                 if (!((dest->opcode == OP_ADD_IMM && dest->sreg1 == cfg->frame_reg) ||
3368                           (dest->opcode == OP_LDADDR))) {
3369                         int context_used;
3370
3371                         iargs [0] = dest;
3372                         iargs [1] = src;
3373
3374                         context_used = mini_class_check_context_used (cfg, klass);
3375
3376                         /* It's ok to intrinsify under gsharing since shared code types are layout stable. */
3377                         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && mono_emit_wb_aware_memcpy (cfg, klass, iargs, n, align)) {
3378                                 return;
3379                         } else if (context_used) {
3380                                 iargs [2] = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3381                         }  else {
3382                                 iargs [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, klass);
3383                                 if (!cfg->compile_aot)
3384                                         mono_class_compute_gc_descriptor (klass);
3385                         }
3386
3387                         if (size_ins)
3388                                 mono_emit_jit_icall (cfg, mono_gsharedvt_value_copy, iargs);
3389                         else
3390                                 mono_emit_jit_icall (cfg, mono_value_copy, iargs);
3391                         return;
3392                 }
3393         }
3394
3395         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 8) {
3396                 /* FIXME: Optimize the case when src/dest is OP_LDADDR */
3397                 mini_emit_memcpy (cfg, dest->dreg, 0, src->dreg, 0, n, align);
3398         } else {
3399                 iargs [0] = dest;
3400                 iargs [1] = src;
3401                 if (size_ins)
3402                         iargs [2] = size_ins;
3403                 else
3404                         EMIT_NEW_ICONST (cfg, iargs [2], n);
3405                 
3406                 memcpy_method = get_memcpy_method ();
3407                 if (memcpy_ins)
3408                         mono_emit_calli (cfg, mono_method_signature (memcpy_method), iargs, memcpy_ins, NULL, NULL);
3409                 else
3410                         mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
3411         }
3412 }
3413
3414 static MonoMethod*
3415 get_memset_method (void)
3416 {
3417         static MonoMethod *memset_method = NULL;
3418         if (!memset_method) {
3419                 memset_method = mono_class_get_method_from_name (mono_defaults.string_class, "memset", 3);
3420                 if (!memset_method)
3421                         g_error ("Old corlib found. Install a new one");
3422         }
3423         return memset_method;
3424 }
3425
3426 void
3427 mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass)
3428 {
3429         MonoInst *iargs [3];
3430         int n;
3431         guint32 align;
3432         MonoMethod *memset_method;
3433         MonoInst *size_ins = NULL;
3434         MonoInst *bzero_ins = NULL;
3435         static MonoMethod *bzero_method;
3436
3437         /* FIXME: Optimize this for the case when dest is an LDADDR */
3438         mono_class_init (klass);
3439         if (mini_is_gsharedvt_klass (klass)) {
3440                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3441                 bzero_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_BZERO);
3442                 if (!bzero_method)
3443                         bzero_method = mono_class_get_method_from_name (mono_defaults.string_class, "bzero_aligned_1", 2);
3444                 g_assert (bzero_method);
3445                 iargs [0] = dest;
3446                 iargs [1] = size_ins;
3447                 mono_emit_calli (cfg, mono_method_signature (bzero_method), iargs, bzero_ins, NULL, NULL);
3448                 return;
3449         }
3450
3451         klass = mono_class_from_mono_type (mini_get_underlying_type (&klass->byval_arg));
3452
3453         n = mono_class_value_size (klass, &align);
3454
3455         if (n <= sizeof (gpointer) * 8) {
3456                 mini_emit_memset (cfg, dest->dreg, 0, n, 0, align);
3457         }
3458         else {
3459                 memset_method = get_memset_method ();
3460                 iargs [0] = dest;
3461                 EMIT_NEW_ICONST (cfg, iargs [1], 0);
3462                 EMIT_NEW_ICONST (cfg, iargs [2], n);
3463                 mono_emit_method_call (cfg, memset_method, iargs, NULL);
3464         }
3465 }
3466
3467 /*
3468  * emit_get_rgctx:
3469  *
3470  *   Emit IR to return either the this pointer for instance method,
3471  * or the mrgctx for static methods.
3472  */
3473 static MonoInst*
3474 emit_get_rgctx (MonoCompile *cfg, MonoMethod *method, int context_used)
3475 {
3476         MonoInst *this_ins = NULL;
3477
3478         g_assert (cfg->gshared);
3479
3480         if (!(method->flags & METHOD_ATTRIBUTE_STATIC) &&
3481                         !(context_used & MONO_GENERIC_CONTEXT_USED_METHOD) &&
3482                         !method->klass->valuetype)
3483                 EMIT_NEW_ARGLOAD (cfg, this_ins, 0);
3484
3485         if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD) {
3486                 MonoInst *mrgctx_loc, *mrgctx_var;
3487
3488                 g_assert (!this_ins);
3489                 g_assert (method->is_inflated && mono_method_get_context (method)->method_inst);
3490
3491                 mrgctx_loc = mono_get_vtable_var (cfg);
3492                 EMIT_NEW_TEMPLOAD (cfg, mrgctx_var, mrgctx_loc->inst_c0);
3493
3494                 return mrgctx_var;
3495         } else if (method->flags & METHOD_ATTRIBUTE_STATIC || method->klass->valuetype) {
3496                 MonoInst *vtable_loc, *vtable_var;
3497
3498                 g_assert (!this_ins);
3499
3500                 vtable_loc = mono_get_vtable_var (cfg);
3501                 EMIT_NEW_TEMPLOAD (cfg, vtable_var, vtable_loc->inst_c0);
3502
3503                 if (method->is_inflated && mono_method_get_context (method)->method_inst) {
3504                         MonoInst *mrgctx_var = vtable_var;
3505                         int vtable_reg;
3506
3507                         vtable_reg = alloc_preg (cfg);
3508                         EMIT_NEW_LOAD_MEMBASE (cfg, vtable_var, OP_LOAD_MEMBASE, vtable_reg, mrgctx_var->dreg, MONO_STRUCT_OFFSET (MonoMethodRuntimeGenericContext, class_vtable));
3509                         vtable_var->type = STACK_PTR;
3510                 }
3511
3512                 return vtable_var;
3513         } else {
3514                 MonoInst *ins;
3515                 int vtable_reg;
3516         
3517                 vtable_reg = alloc_preg (cfg);
3518                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, vtable_reg, this_ins->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3519                 return ins;
3520         }
3521 }
3522
3523 static MonoJumpInfoRgctxEntry *
3524 mono_patch_info_rgctx_entry_new (MonoMemPool *mp, MonoMethod *method, gboolean in_mrgctx, MonoJumpInfoType patch_type, gconstpointer patch_data, MonoRgctxInfoType info_type)
3525 {
3526         MonoJumpInfoRgctxEntry *res = (MonoJumpInfoRgctxEntry *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoRgctxEntry));
3527         res->method = method;
3528         res->in_mrgctx = in_mrgctx;
3529         res->data = (MonoJumpInfo *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo));
3530         res->data->type = patch_type;
3531         res->data->data.target = patch_data;
3532         res->info_type = info_type;
3533
3534         return res;
3535 }
3536
3537 static inline MonoInst*
3538 emit_rgctx_fetch_inline (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
3539 {
3540         MonoInst *args [16];
3541         MonoInst *call;
3542
3543         // FIXME: No fastpath since the slot is not a compile time constant
3544         args [0] = rgctx;
3545         EMIT_NEW_AOTCONST (cfg, args [1], MONO_PATCH_INFO_RGCTX_SLOT_INDEX, entry);
3546         if (entry->in_mrgctx)
3547                 call = mono_emit_jit_icall (cfg, mono_fill_method_rgctx, args);
3548         else
3549                 call = mono_emit_jit_icall (cfg, mono_fill_class_rgctx, args);
3550         return call;
3551 #if 0
3552         /*
3553          * FIXME: This can be called during decompose, which is a problem since it creates
3554          * new bblocks.
3555          * Also, the fastpath doesn't work since the slot number is dynamically allocated.
3556          */
3557         int i, slot, depth, index, rgctx_reg, val_reg, res_reg;
3558         gboolean mrgctx;
3559         MonoBasicBlock *is_null_bb, *end_bb;
3560         MonoInst *res, *ins, *call;
3561         MonoInst *args[16];
3562
3563         slot = mini_get_rgctx_entry_slot (entry);
3564
3565         mrgctx = MONO_RGCTX_SLOT_IS_MRGCTX (slot);
3566         index = MONO_RGCTX_SLOT_INDEX (slot);
3567         if (mrgctx)
3568                 index += MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
3569         for (depth = 0; ; ++depth) {
3570                 int size = mono_class_rgctx_get_array_size (depth, mrgctx);
3571
3572                 if (index < size - 1)
3573                         break;
3574                 index -= size - 1;
3575         }
3576
3577         NEW_BBLOCK (cfg, end_bb);
3578         NEW_BBLOCK (cfg, is_null_bb);
3579
3580         if (mrgctx) {
3581                 rgctx_reg = rgctx->dreg;
3582         } else {
3583                 rgctx_reg = alloc_preg (cfg);
3584
3585                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, rgctx_reg, rgctx->dreg, MONO_STRUCT_OFFSET (MonoVTable, runtime_generic_context));
3586                 // FIXME: Avoid this check by allocating the table when the vtable is created etc.
3587                 NEW_BBLOCK (cfg, is_null_bb);
3588
3589                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rgctx_reg, 0);
3590                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3591         }
3592
3593         for (i = 0; i < depth; ++i) {
3594                 int array_reg = alloc_preg (cfg);
3595
3596                 /* load ptr to next array */
3597                 if (mrgctx && i == 0)
3598                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, rgctx_reg, MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT);
3599                 else
3600                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, rgctx_reg, 0);
3601                 rgctx_reg = array_reg;
3602                 /* is the ptr null? */
3603                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rgctx_reg, 0);
3604                 /* if yes, jump to actual trampoline */
3605                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3606         }
3607
3608         /* fetch slot */
3609         val_reg = alloc_preg (cfg);
3610         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, val_reg, rgctx_reg, (index + 1) * sizeof (gpointer));
3611         /* is the slot null? */
3612         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, val_reg, 0);
3613         /* if yes, jump to actual trampoline */
3614         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3615
3616         /* Fastpath */
3617         res_reg = alloc_preg (cfg);
3618         MONO_INST_NEW (cfg, ins, OP_MOVE);
3619         ins->dreg = res_reg;
3620         ins->sreg1 = val_reg;
3621         MONO_ADD_INS (cfg->cbb, ins);
3622         res = ins;
3623         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3624
3625         /* Slowpath */
3626         MONO_START_BB (cfg, is_null_bb);
3627         args [0] = rgctx;
3628         EMIT_NEW_ICONST (cfg, args [1], index);
3629         if (mrgctx)
3630                 call = mono_emit_jit_icall (cfg, mono_fill_method_rgctx, args);
3631         else
3632                 call = mono_emit_jit_icall (cfg, mono_fill_class_rgctx, args);
3633         MONO_INST_NEW (cfg, ins, OP_MOVE);
3634         ins->dreg = res_reg;
3635         ins->sreg1 = call->dreg;
3636         MONO_ADD_INS (cfg->cbb, ins);
3637         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3638
3639         MONO_START_BB (cfg, end_bb);
3640
3641         return res;
3642 #endif
3643 }
3644
3645 /*
3646  * emit_rgctx_fetch:
3647  *
3648  *   Emit IR to load the value of the rgctx entry ENTRY from the rgctx
3649  * given by RGCTX.
3650  */
3651 static inline MonoInst*
3652 emit_rgctx_fetch (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
3653 {
3654         if (cfg->llvm_only)
3655                 return emit_rgctx_fetch_inline (cfg, rgctx, entry);
3656         else
3657                 return mono_emit_abs_call (cfg, MONO_PATCH_INFO_RGCTX_FETCH, entry, helper_sig_rgctx_lazy_fetch_trampoline, &rgctx);
3658 }
3659
3660 static MonoInst*
3661 emit_get_rgctx_klass (MonoCompile *cfg, int context_used,
3662                                           MonoClass *klass, MonoRgctxInfoType rgctx_type)
3663 {
3664         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);
3665         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3666
3667         return emit_rgctx_fetch (cfg, rgctx, entry);
3668 }
3669
3670 static MonoInst*
3671 emit_get_rgctx_sig (MonoCompile *cfg, int context_used,
3672                                         MonoMethodSignature *sig, MonoRgctxInfoType rgctx_type)
3673 {
3674         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);
3675         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3676
3677         return emit_rgctx_fetch (cfg, rgctx, entry);
3678 }
3679
3680 static MonoInst*
3681 emit_get_rgctx_gsharedvt_call (MonoCompile *cfg, int context_used,
3682                                                            MonoMethodSignature *sig, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3683 {
3684         MonoJumpInfoGSharedVtCall *call_info;
3685         MonoJumpInfoRgctxEntry *entry;
3686         MonoInst *rgctx;
3687
3688         call_info = (MonoJumpInfoGSharedVtCall *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoGSharedVtCall));
3689         call_info->sig = sig;
3690         call_info->method = cmethod;
3691
3692         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);
3693         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3694
3695         return emit_rgctx_fetch (cfg, rgctx, entry);
3696 }
3697
3698 /*
3699  * emit_get_rgctx_virt_method:
3700  *
3701  *   Return data for method VIRT_METHOD for a receiver of type KLASS.
3702  */
3703 static MonoInst*
3704 emit_get_rgctx_virt_method (MonoCompile *cfg, int context_used,
3705                                                         MonoClass *klass, MonoMethod *virt_method, MonoRgctxInfoType rgctx_type)
3706 {
3707         MonoJumpInfoVirtMethod *info;
3708         MonoJumpInfoRgctxEntry *entry;
3709         MonoInst *rgctx;
3710
3711         info = (MonoJumpInfoVirtMethod *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoVirtMethod));
3712         info->klass = klass;
3713         info->method = virt_method;
3714
3715         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);
3716         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3717
3718         return emit_rgctx_fetch (cfg, rgctx, entry);
3719 }
3720
3721 static MonoInst*
3722 emit_get_rgctx_gsharedvt_method (MonoCompile *cfg, int context_used,
3723                                                                  MonoMethod *cmethod, MonoGSharedVtMethodInfo *info)
3724 {
3725         MonoJumpInfoRgctxEntry *entry;
3726         MonoInst *rgctx;
3727
3728         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);
3729         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3730
3731         return emit_rgctx_fetch (cfg, rgctx, entry);
3732 }
3733
3734 /*
3735  * emit_get_rgctx_method:
3736  *
3737  *   Emit IR to load the property RGCTX_TYPE of CMETHOD. If context_used is 0, emit
3738  * normal constants, else emit a load from the rgctx.
3739  */
3740 static MonoInst*
3741 emit_get_rgctx_method (MonoCompile *cfg, int context_used,
3742                                            MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3743 {
3744         if (!context_used) {
3745                 MonoInst *ins;
3746
3747                 switch (rgctx_type) {
3748                 case MONO_RGCTX_INFO_METHOD:
3749                         EMIT_NEW_METHODCONST (cfg, ins, cmethod);
3750                         return ins;
3751                 case MONO_RGCTX_INFO_METHOD_RGCTX:
3752                         EMIT_NEW_METHOD_RGCTX_CONST (cfg, ins, cmethod);
3753                         return ins;
3754                 default:
3755                         g_assert_not_reached ();
3756                 }
3757         } else {
3758                 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);
3759                 MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3760
3761                 return emit_rgctx_fetch (cfg, rgctx, entry);
3762         }
3763 }
3764
3765 static MonoInst*
3766 emit_get_rgctx_field (MonoCompile *cfg, int context_used,
3767                                           MonoClassField *field, MonoRgctxInfoType rgctx_type)
3768 {
3769         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);
3770         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3771
3772         return emit_rgctx_fetch (cfg, rgctx, entry);
3773 }
3774
3775 static int
3776 get_gsharedvt_info_slot (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3777 {
3778         MonoGSharedVtMethodInfo *info = cfg->gsharedvt_info;
3779         MonoRuntimeGenericContextInfoTemplate *template_;
3780         int i, idx;
3781
3782         g_assert (info);
3783
3784         for (i = 0; i < info->num_entries; ++i) {
3785                 MonoRuntimeGenericContextInfoTemplate *otemplate = &info->entries [i];
3786
3787                 if (otemplate->info_type == rgctx_type && otemplate->data == data && rgctx_type != MONO_RGCTX_INFO_LOCAL_OFFSET)
3788                         return i;
3789         }
3790
3791         if (info->num_entries == info->count_entries) {
3792                 MonoRuntimeGenericContextInfoTemplate *new_entries;
3793                 int new_count_entries = info->count_entries ? info->count_entries * 2 : 16;
3794
3795                 new_entries = (MonoRuntimeGenericContextInfoTemplate *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * new_count_entries);
3796
3797                 memcpy (new_entries, info->entries, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
3798                 info->entries = new_entries;
3799                 info->count_entries = new_count_entries;
3800         }
3801
3802         idx = info->num_entries;
3803         template_ = &info->entries [idx];
3804         template_->info_type = rgctx_type;
3805         template_->data = data;
3806
3807         info->num_entries ++;
3808
3809         return idx;
3810 }
3811
3812 /*
3813  * emit_get_gsharedvt_info:
3814  *
3815  *   This is similar to emit_get_rgctx_.., but loads the data from the gsharedvt info var instead of calling an rgctx fetch trampoline.
3816  */
3817 static MonoInst*
3818 emit_get_gsharedvt_info (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3819 {
3820         MonoInst *ins;
3821         int idx, dreg;
3822
3823         idx = get_gsharedvt_info_slot (cfg, data, rgctx_type);
3824         /* Load info->entries [idx] */
3825         dreg = alloc_preg (cfg);
3826         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, cfg->gsharedvt_info_var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
3827
3828         return ins;
3829 }
3830
3831 static MonoInst*
3832 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type)
3833 {
3834         return emit_get_gsharedvt_info (cfg, &klass->byval_arg, rgctx_type);
3835 }
3836
3837 /*
3838  * On return the caller must check @klass for load errors.
3839  */
3840 static void
3841 emit_class_init (MonoCompile *cfg, MonoClass *klass)
3842 {
3843         MonoInst *vtable_arg;
3844         int context_used;
3845
3846         context_used = mini_class_check_context_used (cfg, klass);
3847
3848         if (context_used) {
3849                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
3850                                                                                    klass, MONO_RGCTX_INFO_VTABLE);
3851         } else {
3852                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
3853
3854                 if (!vtable)
3855                         return;
3856                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
3857         }
3858
3859         if (!COMPILE_LLVM (cfg) && cfg->backend->have_op_generic_class_init) {
3860                 MonoInst *ins;
3861
3862                 /*
3863                  * Using an opcode instead of emitting IR here allows the hiding of the call inside the opcode,
3864                  * so this doesn't have to clobber any regs and it doesn't break basic blocks.
3865                  */
3866                 MONO_INST_NEW (cfg, ins, OP_GENERIC_CLASS_INIT);
3867                 ins->sreg1 = vtable_arg->dreg;
3868                 MONO_ADD_INS (cfg->cbb, ins);
3869         } else {
3870                 static int byte_offset = -1;
3871                 static guint8 bitmask;
3872                 int bits_reg, inited_reg;
3873                 MonoBasicBlock *inited_bb;
3874                 MonoInst *args [16];
3875
3876                 if (byte_offset < 0)
3877                         mono_marshal_find_bitfield_offset (MonoVTable, initialized, &byte_offset, &bitmask);
3878
3879                 bits_reg = alloc_ireg (cfg);
3880                 inited_reg = alloc_ireg (cfg);
3881
3882                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, bits_reg, vtable_arg->dreg, byte_offset);
3883                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, inited_reg, bits_reg, bitmask);
3884
3885                 NEW_BBLOCK (cfg, inited_bb);
3886
3887                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, inited_reg, 0);
3888                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, inited_bb);
3889
3890                 args [0] = vtable_arg;
3891                 mono_emit_jit_icall (cfg, mono_generic_class_init, args);
3892
3893                 MONO_START_BB (cfg, inited_bb);
3894         }
3895 }
3896
3897 static void
3898 emit_seq_point (MonoCompile *cfg, MonoMethod *method, guint8* ip, gboolean intr_loc, gboolean nonempty_stack)
3899 {
3900         MonoInst *ins;
3901
3902         if (cfg->gen_seq_points && cfg->method == method) {
3903                 NEW_SEQ_POINT (cfg, ins, ip - cfg->header->code, intr_loc);
3904                 if (nonempty_stack)
3905                         ins->flags |= MONO_INST_NONEMPTY_STACK;
3906                 MONO_ADD_INS (cfg->cbb, ins);
3907         }
3908 }
3909
3910 static void
3911 save_cast_details (MonoCompile *cfg, MonoClass *klass, int obj_reg, gboolean null_check)
3912 {
3913         if (mini_get_debug_options ()->better_cast_details) {
3914                 int vtable_reg = alloc_preg (cfg);
3915                 int klass_reg = alloc_preg (cfg);
3916                 MonoBasicBlock *is_null_bb = NULL;
3917                 MonoInst *tls_get;
3918                 int to_klass_reg, context_used;
3919
3920                 if (null_check) {
3921                         NEW_BBLOCK (cfg, is_null_bb);
3922
3923                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
3924                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3925                 }
3926
3927                 tls_get = mono_get_jit_tls_intrinsic (cfg);
3928                 if (!tls_get) {
3929                         fprintf (stderr, "error: --debug=casts not supported on this platform.\n.");
3930                         exit (1);
3931                 }
3932
3933                 MONO_ADD_INS (cfg->cbb, tls_get);
3934                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3935                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3936
3937                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), klass_reg);
3938
3939                 context_used = mini_class_check_context_used (cfg, klass);
3940                 if (context_used) {
3941                         MonoInst *class_ins;
3942
3943                         class_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3944                         to_klass_reg = class_ins->dreg;
3945                 } else {
3946                         to_klass_reg = alloc_preg (cfg);
3947                         MONO_EMIT_NEW_CLASSCONST (cfg, to_klass_reg, klass);
3948                 }
3949                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_to), to_klass_reg);
3950
3951                 if (null_check)
3952                         MONO_START_BB (cfg, is_null_bb);
3953         }
3954 }
3955
3956 static void
3957 reset_cast_details (MonoCompile *cfg)
3958 {
3959         /* Reset the variables holding the cast details */
3960         if (mini_get_debug_options ()->better_cast_details) {
3961                 MonoInst *tls_get = mono_get_jit_tls_intrinsic (cfg);
3962
3963                 MONO_ADD_INS (cfg->cbb, tls_get);
3964                 /* It is enough to reset the from field */
3965                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), 0);
3966         }
3967 }
3968
3969 /*
3970  * On return the caller must check @array_class for load errors
3971  */
3972 static void
3973 mini_emit_check_array_type (MonoCompile *cfg, MonoInst *obj, MonoClass *array_class)
3974 {
3975         int vtable_reg = alloc_preg (cfg);
3976         int context_used;
3977
3978         context_used = mini_class_check_context_used (cfg, array_class);
3979
3980         save_cast_details (cfg, array_class, obj->dreg, FALSE);
3981
3982         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3983
3984         if (cfg->opt & MONO_OPT_SHARED) {
3985                 int class_reg = alloc_preg (cfg);
3986                 MonoInst *ins;
3987
3988                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, class_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3989                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, array_class);
3990                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, class_reg, ins->dreg);
3991         } else if (context_used) {
3992                 MonoInst *vtable_ins;
3993
3994                 vtable_ins = emit_get_rgctx_klass (cfg, context_used, array_class, MONO_RGCTX_INFO_VTABLE);
3995                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vtable_ins->dreg);
3996         } else {
3997                 if (cfg->compile_aot) {
3998                         int vt_reg;
3999                         MonoVTable *vtable;
4000
4001                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
4002                                 return;
4003                         vt_reg = alloc_preg (cfg);
4004                         MONO_EMIT_NEW_VTABLECONST (cfg, vt_reg, vtable);
4005                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vt_reg);
4006                 } else {
4007                         MonoVTable *vtable;
4008                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
4009                                 return;
4010                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vtable);
4011                 }
4012         }
4013         
4014         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ArrayTypeMismatchException");
4015
4016         reset_cast_details (cfg);
4017 }
4018
4019 /**
4020  * Handles unbox of a Nullable<T>. If context_used is non zero, then shared 
4021  * generic code is generated.
4022  */
4023 static MonoInst*
4024 handle_unbox_nullable (MonoCompile* cfg, MonoInst* val, MonoClass* klass, int context_used)
4025 {
4026         MonoMethod* method = mono_class_get_method_from_name (klass, "Unbox", 1);
4027
4028         if (context_used) {
4029                 MonoInst *rgctx, *addr;
4030
4031                 /* FIXME: What if the class is shared?  We might not
4032                    have to get the address of the method from the
4033                    RGCTX. */
4034                 addr = emit_get_rgctx_method (cfg, context_used, method,
4035                                                                           MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
4036                 if (cfg->llvm_only) {
4037                         cfg->signatures = g_slist_prepend_mempool (cfg->mempool, cfg->signatures, mono_method_signature (method));
4038                         return emit_llvmonly_calli (cfg, mono_method_signature (method), &val, addr);
4039                 } else {
4040                         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
4041
4042                         return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
4043                 }
4044         } else {
4045                 gboolean pass_vtable, pass_mrgctx;
4046                 MonoInst *rgctx_arg = NULL;
4047
4048                 check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
4049                 g_assert (!pass_mrgctx);
4050
4051                 if (pass_vtable) {
4052                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
4053
4054                         g_assert (vtable);
4055                         EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
4056                 }
4057
4058                 return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
4059         }
4060 }
4061
4062 static MonoInst*
4063 handle_unbox (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, int context_used)
4064 {
4065         MonoInst *add;
4066         int obj_reg;
4067         int vtable_reg = alloc_dreg (cfg ,STACK_PTR);
4068         int klass_reg = alloc_dreg (cfg ,STACK_PTR);
4069         int eclass_reg = alloc_dreg (cfg ,STACK_PTR);
4070         int rank_reg = alloc_dreg (cfg ,STACK_I4);
4071
4072         obj_reg = sp [0]->dreg;
4073         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4074         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
4075
4076         /* FIXME: generics */
4077         g_assert (klass->rank == 0);
4078                         
4079         // Check rank == 0
4080         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, 0);
4081         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4082
4083         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4084         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, element_class));
4085
4086         if (context_used) {
4087                 MonoInst *element_class;
4088
4089                 /* This assertion is from the unboxcast insn */
4090                 g_assert (klass->rank == 0);
4091
4092                 element_class = emit_get_rgctx_klass (cfg, context_used,
4093                                 klass, MONO_RGCTX_INFO_ELEMENT_KLASS);
4094
4095                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, eclass_reg, element_class->dreg);
4096                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4097         } else {
4098                 save_cast_details (cfg, klass->element_class, obj_reg, FALSE);
4099                 mini_emit_class_check (cfg, eclass_reg, klass->element_class);
4100                 reset_cast_details (cfg);
4101         }
4102
4103         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), obj_reg, sizeof (MonoObject));
4104         MONO_ADD_INS (cfg->cbb, add);
4105         add->type = STACK_MP;
4106         add->klass = klass;
4107
4108         return add;
4109 }
4110
4111 static MonoInst*
4112 handle_unbox_gsharedvt (MonoCompile *cfg, MonoClass *klass, MonoInst *obj)
4113 {
4114         MonoInst *addr, *klass_inst, *is_ref, *args[16];
4115         MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
4116         MonoInst *ins;
4117         int dreg, addr_reg;
4118
4119         klass_inst = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_KLASS);
4120
4121         /* obj */
4122         args [0] = obj;
4123
4124         /* klass */
4125         args [1] = klass_inst;
4126
4127         /* CASTCLASS */
4128         obj = mono_emit_jit_icall (cfg, mono_object_castclass_unbox, args);
4129
4130         NEW_BBLOCK (cfg, is_ref_bb);
4131         NEW_BBLOCK (cfg, is_nullable_bb);
4132         NEW_BBLOCK (cfg, end_bb);
4133         is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
4134         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
4135         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
4136
4137         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
4138         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
4139
4140         /* This will contain either the address of the unboxed vtype, or an address of the temporary where the ref is stored */
4141         addr_reg = alloc_dreg (cfg, STACK_MP);
4142
4143         /* Non-ref case */
4144         /* UNBOX */
4145         NEW_BIALU_IMM (cfg, addr, OP_ADD_IMM, addr_reg, obj->dreg, sizeof (MonoObject));
4146         MONO_ADD_INS (cfg->cbb, addr);
4147
4148         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4149
4150         /* Ref case */
4151         MONO_START_BB (cfg, is_ref_bb);
4152
4153         /* Save the ref to a temporary */
4154         dreg = alloc_ireg (cfg);
4155         EMIT_NEW_VARLOADA_VREG (cfg, addr, dreg, &klass->byval_arg);
4156         addr->dreg = addr_reg;
4157         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, obj->dreg);
4158         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4159
4160         /* Nullable case */
4161         MONO_START_BB (cfg, is_nullable_bb);
4162
4163         {
4164                 MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX);
4165                 MonoInst *unbox_call;
4166                 MonoMethodSignature *unbox_sig;
4167
4168                 unbox_sig = (MonoMethodSignature *)mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
4169                 unbox_sig->ret = &klass->byval_arg;
4170                 unbox_sig->param_count = 1;
4171                 unbox_sig->params [0] = &mono_defaults.object_class->byval_arg;
4172
4173                 if (cfg->llvm_only)
4174                         unbox_call = emit_llvmonly_calli (cfg, unbox_sig, &obj, addr);
4175                 else
4176                         unbox_call = mono_emit_calli (cfg, unbox_sig, &obj, addr, NULL, NULL);
4177
4178                 EMIT_NEW_VARLOADA_VREG (cfg, addr, unbox_call->dreg, &klass->byval_arg);
4179                 addr->dreg = addr_reg;
4180         }
4181
4182         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4183
4184         /* End */
4185         MONO_START_BB (cfg, end_bb);
4186
4187         /* LDOBJ */
4188         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr_reg, 0);
4189
4190         return ins;
4191 }
4192
4193 /*
4194  * Returns NULL and set the cfg exception on error.
4195  */
4196 static MonoInst*
4197 handle_alloc (MonoCompile *cfg, MonoClass *klass, gboolean for_box, int context_used)
4198 {
4199         MonoInst *iargs [2];
4200         void *alloc_ftn;
4201
4202         if (context_used) {
4203                 MonoInst *data;
4204                 MonoRgctxInfoType rgctx_info;
4205                 MonoInst *iargs [2];
4206                 gboolean known_instance_size = !mini_is_gsharedvt_klass (klass);
4207
4208                 MonoMethod *managed_alloc = mono_gc_get_managed_allocator (klass, for_box, known_instance_size);
4209
4210                 if (cfg->opt & MONO_OPT_SHARED)
4211                         rgctx_info = MONO_RGCTX_INFO_KLASS;
4212                 else
4213                         rgctx_info = MONO_RGCTX_INFO_VTABLE;
4214                 data = emit_get_rgctx_klass (cfg, context_used, klass, rgctx_info);
4215
4216                 if (cfg->opt & MONO_OPT_SHARED) {
4217                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
4218                         iargs [1] = data;
4219                         alloc_ftn = ves_icall_object_new;
4220                 } else {
4221                         iargs [0] = data;
4222                         alloc_ftn = ves_icall_object_new_specific;
4223                 }
4224
4225                 if (managed_alloc && !(cfg->opt & MONO_OPT_SHARED)) {
4226                         if (known_instance_size) {
4227                                 int size = mono_class_instance_size (klass);
4228                                 if (size < sizeof (MonoObject))
4229                                         g_error ("Invalid size %d for class %s", size, mono_type_get_full_name (klass));
4230
4231                                 EMIT_NEW_ICONST (cfg, iargs [1], size);
4232                         }
4233                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
4234                 }
4235
4236                 return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
4237         }
4238
4239         if (cfg->opt & MONO_OPT_SHARED) {
4240                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
4241                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
4242
4243                 alloc_ftn = ves_icall_object_new;
4244         } else if (cfg->compile_aot && cfg->cbb->out_of_line && klass->type_token && klass->image == mono_defaults.corlib && !klass->generic_class) {
4245                 /* This happens often in argument checking code, eg. throw new FooException... */
4246                 /* Avoid relocations and save some space by calling a helper function specialized to mscorlib */
4247                 EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (klass->type_token));
4248                 return mono_emit_jit_icall (cfg, mono_helper_newobj_mscorlib, iargs);
4249         } else {
4250                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
4251                 MonoMethod *managed_alloc = NULL;
4252                 gboolean pass_lw;
4253
4254                 if (!vtable) {
4255                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4256                         cfg->exception_ptr = klass;
4257                         return NULL;
4258                 }
4259
4260                 managed_alloc = mono_gc_get_managed_allocator (klass, for_box, TRUE);
4261
4262                 if (managed_alloc) {
4263                         int size = mono_class_instance_size (klass);
4264                         if (size < sizeof (MonoObject))
4265                                 g_error ("Invalid size %d for class %s", size, mono_type_get_full_name (klass));
4266
4267                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
4268                         EMIT_NEW_ICONST (cfg, iargs [1], size);
4269                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
4270                 }
4271                 alloc_ftn = mono_class_get_allocation_ftn (vtable, for_box, &pass_lw);
4272                 if (pass_lw) {
4273                         guint32 lw = vtable->klass->instance_size;
4274                         lw = ((lw + (sizeof (gpointer) - 1)) & ~(sizeof (gpointer) - 1)) / sizeof (gpointer);
4275                         EMIT_NEW_ICONST (cfg, iargs [0], lw);
4276                         EMIT_NEW_VTABLECONST (cfg, iargs [1], vtable);
4277                 }
4278                 else {
4279                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
4280                 }
4281         }
4282
4283         return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
4284 }
4285         
4286 /*
4287  * Returns NULL and set the cfg exception on error.
4288  */     
4289 static MonoInst*
4290 handle_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_used)
4291 {
4292         MonoInst *alloc, *ins;
4293
4294         if (mono_class_is_nullable (klass)) {
4295                 MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
4296
4297                 if (context_used) {
4298                         if (cfg->llvm_only && cfg->gsharedvt) {
4299                                 MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
4300                                                                                                                 MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
4301                                 return emit_llvmonly_calli (cfg, mono_method_signature (method), &val, addr);
4302                         } else {
4303                                 /* FIXME: What if the class is shared?  We might not
4304                                    have to get the method address from the RGCTX. */
4305                                 MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
4306                                                                                                                 MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
4307                                 MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
4308
4309                                 return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
4310                         }
4311                 } else {
4312                         gboolean pass_vtable, pass_mrgctx;
4313                         MonoInst *rgctx_arg = NULL;
4314
4315                         check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
4316                         g_assert (!pass_mrgctx);
4317
4318                         if (pass_vtable) {
4319                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
4320
4321                                 g_assert (vtable);
4322                                 EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
4323                         }
4324
4325                         return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
4326                 }
4327         }
4328
4329         if (mini_is_gsharedvt_klass (klass)) {
4330                 MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
4331                 MonoInst *res, *is_ref, *src_var, *addr;
4332                 int dreg;
4333
4334                 dreg = alloc_ireg (cfg);
4335
4336                 NEW_BBLOCK (cfg, is_ref_bb);
4337                 NEW_BBLOCK (cfg, is_nullable_bb);
4338                 NEW_BBLOCK (cfg, end_bb);
4339                 is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
4340                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
4341                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
4342
4343                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
4344                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
4345
4346                 /* Non-ref case */
4347                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4348                 if (!alloc)
4349                         return NULL;
4350                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4351                 ins->opcode = OP_STOREV_MEMBASE;
4352
4353                 EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, alloc->dreg);
4354                 res->type = STACK_OBJ;
4355                 res->klass = klass;
4356                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4357                 
4358                 /* Ref case */
4359                 MONO_START_BB (cfg, is_ref_bb);
4360
4361                 /* val is a vtype, so has to load the value manually */
4362                 src_var = get_vreg_to_inst (cfg, val->dreg);
4363                 if (!src_var)
4364                         src_var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, val->dreg);
4365                 EMIT_NEW_VARLOADA (cfg, addr, src_var, src_var->inst_vtype);
4366                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, addr->dreg, 0);
4367                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4368
4369                 /* Nullable case */
4370                 MONO_START_BB (cfg, is_nullable_bb);
4371
4372                 {
4373                         MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass,
4374                                                                                                         MONO_RGCTX_INFO_NULLABLE_CLASS_BOX);
4375                         MonoInst *box_call;
4376                         MonoMethodSignature *box_sig;
4377
4378                         /*
4379                          * klass is Nullable<T>, need to call Nullable<T>.Box () using a gsharedvt signature, but we cannot
4380                          * construct that method at JIT time, so have to do things by hand.
4381                          */
4382                         box_sig = (MonoMethodSignature *)mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
4383                         box_sig->ret = &mono_defaults.object_class->byval_arg;
4384                         box_sig->param_count = 1;
4385                         box_sig->params [0] = &klass->byval_arg;
4386
4387                         if (cfg->llvm_only)
4388                                 box_call = emit_llvmonly_calli (cfg, box_sig, &val, addr);
4389                         else
4390                                 box_call = mono_emit_calli (cfg, box_sig, &val, addr, NULL, NULL);
4391                         EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, box_call->dreg);
4392                         res->type = STACK_OBJ;
4393                         res->klass = klass;
4394                 }
4395
4396                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4397
4398                 MONO_START_BB (cfg, end_bb);
4399
4400                 return res;
4401         } else {
4402                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4403                 if (!alloc)
4404                         return NULL;
4405
4406                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4407                 return alloc;
4408         }
4409 }
4410
4411 static gboolean
4412 mini_class_has_reference_variant_generic_argument (MonoCompile *cfg, MonoClass *klass, int context_used)
4413 {
4414         int i;
4415         MonoGenericContainer *container;
4416         MonoGenericInst *ginst;
4417
4418         if (klass->generic_class) {
4419                 container = klass->generic_class->container_class->generic_container;
4420                 ginst = klass->generic_class->context.class_inst;
4421         } else if (klass->generic_container && context_used) {
4422                 container = klass->generic_container;
4423                 ginst = container->context.class_inst;
4424         } else {
4425                 return FALSE;
4426         }
4427
4428         for (i = 0; i < container->type_argc; ++i) {
4429                 MonoType *type;
4430                 if (!(mono_generic_container_get_param_info (container, i)->flags & (MONO_GEN_PARAM_VARIANT|MONO_GEN_PARAM_COVARIANT)))
4431                         continue;
4432                 type = ginst->type_argv [i];
4433                 if (mini_type_is_reference (type))
4434                         return TRUE;
4435         }
4436         return FALSE;
4437 }
4438
4439 static GHashTable* direct_icall_type_hash;
4440
4441 static gboolean
4442 icall_is_direct_callable (MonoCompile *cfg, MonoMethod *cmethod)
4443 {
4444         /* LLVM on amd64 can't handle calls to non-32 bit addresses */
4445         if (!direct_icalls_enabled (cfg))
4446                 return FALSE;
4447
4448         /*
4449          * An icall is directly callable if it doesn't directly or indirectly call mono_raise_exception ().
4450          * Whitelist a few icalls for now.
4451          */
4452         if (!direct_icall_type_hash) {
4453                 GHashTable *h = g_hash_table_new (g_str_hash, g_str_equal);
4454
4455                 g_hash_table_insert (h, (char*)"Decimal", GUINT_TO_POINTER (1));
4456                 g_hash_table_insert (h, (char*)"Number", GUINT_TO_POINTER (1));
4457                 g_hash_table_insert (h, (char*)"Buffer", GUINT_TO_POINTER (1));
4458                 g_hash_table_insert (h, (char*)"Monitor", GUINT_TO_POINTER (1));
4459                 mono_memory_barrier ();
4460                 direct_icall_type_hash = h;
4461         }
4462
4463         if (cmethod->klass == mono_defaults.math_class)
4464                 return TRUE;
4465         /* No locking needed */
4466         if (cmethod->klass->image == mono_defaults.corlib && g_hash_table_lookup (direct_icall_type_hash, cmethod->klass->name))
4467                 return TRUE;
4468         return FALSE;
4469 }
4470
4471 #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)
4472
4473 static MonoInst*
4474 emit_isinst_with_cache (MonoCompile *cfg, MonoClass *klass, MonoInst **args)
4475 {
4476         MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
4477         return mono_emit_method_call (cfg, mono_isinst, args, NULL);
4478 }
4479
4480 static MonoInst*
4481 emit_castclass_with_cache (MonoCompile *cfg, MonoClass *klass, MonoInst **args)
4482 {
4483         MonoMethod *mono_castclass = mono_marshal_get_castclass_with_cache ();
4484         MonoInst *res;
4485
4486         save_cast_details (cfg, klass, args [0]->dreg, TRUE);
4487         res = mono_emit_method_call (cfg, mono_castclass, args, NULL);
4488         reset_cast_details (cfg);
4489
4490         return res;
4491 }
4492
4493 static int
4494 get_castclass_cache_idx (MonoCompile *cfg)
4495 {
4496         /* Each CASTCLASS_CACHE patch needs a unique index which identifies the call site */
4497         cfg->castclass_cache_index ++;
4498         return (cfg->method_index << 16) | cfg->castclass_cache_index;
4499 }
4500
4501
4502 static MonoInst*
4503 emit_isinst_with_cache_nonshared (MonoCompile *cfg, MonoInst *obj, MonoClass *klass)
4504 {
4505         MonoInst *args [3];
4506         int idx;
4507
4508         args [0] = obj; /* obj */
4509         EMIT_NEW_CLASSCONST (cfg, args [1], klass); /* klass */
4510
4511         idx = get_castclass_cache_idx (cfg); /* inline cache*/
4512         args [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
4513
4514         return emit_isinst_with_cache (cfg, klass, args);
4515 }
4516
4517 static MonoInst*
4518 emit_castclass_with_cache_nonshared (MonoCompile *cfg, MonoInst *obj, MonoClass *klass)
4519 {
4520         MonoInst *args [3];
4521         int idx;
4522
4523         /* obj */
4524         args [0] = obj;
4525
4526         /* klass */
4527         EMIT_NEW_CLASSCONST (cfg, args [1], klass);
4528
4529         /* inline cache*/
4530         idx = get_castclass_cache_idx (cfg);
4531         args [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
4532
4533         /*The wrapper doesn't inline well so the bloat of inlining doesn't pay off.*/
4534         return emit_castclass_with_cache (cfg, klass, args);
4535 }
4536
4537 /*
4538  * Returns NULL and set the cfg exception on error.
4539  */
4540 static MonoInst*
4541 handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
4542 {
4543         MonoBasicBlock *is_null_bb;
4544         int obj_reg = src->dreg;
4545         int vtable_reg = alloc_preg (cfg);
4546         MonoInst *klass_inst = NULL;
4547
4548         if (src->opcode == OP_PCONST && src->inst_p0 == 0)
4549                 return src;
4550
4551         if (context_used) {
4552                 MonoInst *args [3];
4553
4554                 if (mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
4555                         MonoInst *cache_ins;
4556
4557                         cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
4558
4559                         /* obj */
4560                         args [0] = src;
4561
4562                         /* klass - it's the second element of the cache entry*/
4563                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
4564
4565                         /* cache */
4566                         args [2] = cache_ins;
4567
4568                         return emit_castclass_with_cache (cfg, klass, args);
4569                 }
4570
4571                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
4572         }
4573
4574         NEW_BBLOCK (cfg, is_null_bb);
4575
4576         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4577         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
4578
4579         save_cast_details (cfg, klass, obj_reg, FALSE);
4580
4581         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4582                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4583                 mini_emit_iface_cast (cfg, vtable_reg, klass, NULL, NULL);
4584         } else {
4585                 int klass_reg = alloc_preg (cfg);
4586
4587                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4588
4589                 if (!klass->rank && !cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
4590                         /* the remoting code is broken, access the class for now */
4591                         if (0) { /*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4592                                 MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4593                                 if (!vt) {
4594                                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4595                                         cfg->exception_ptr = klass;
4596                                         return NULL;
4597                                 }
4598                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4599                         } else {
4600                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4601                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4602                         }
4603                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4604                 } else {
4605                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4606                         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, klass_inst, is_null_bb);
4607                 }
4608         }
4609
4610         MONO_START_BB (cfg, is_null_bb);
4611
4612         reset_cast_details (cfg);
4613
4614         return src;
4615 }
4616
4617 /*
4618  * Returns NULL and set the cfg exception on error.
4619  */
4620 static MonoInst*
4621 handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
4622 {
4623         MonoInst *ins;
4624         MonoBasicBlock *is_null_bb, *false_bb, *end_bb;
4625         int obj_reg = src->dreg;
4626         int vtable_reg = alloc_preg (cfg);
4627         int res_reg = alloc_ireg_ref (cfg);
4628         MonoInst *klass_inst = NULL;
4629
4630         if (context_used) {
4631                 MonoInst *args [3];
4632
4633                 if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
4634                         MonoInst *cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
4635
4636                         args [0] = src; /* obj */
4637
4638                         /* klass - it's the second element of the cache entry*/
4639                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
4640
4641                         args [2] = cache_ins; /* cache */
4642                         return emit_isinst_with_cache (cfg, klass, args);
4643                 }
4644
4645                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
4646         }
4647
4648         NEW_BBLOCK (cfg, is_null_bb);
4649         NEW_BBLOCK (cfg, false_bb);
4650         NEW_BBLOCK (cfg, end_bb);
4651
4652         /* Do the assignment at the beginning, so the other assignment can be if converted */
4653         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, res_reg, obj_reg);
4654         ins->type = STACK_OBJ;
4655         ins->klass = klass;
4656
4657         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4658         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_null_bb);
4659
4660         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4661
4662         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4663                 g_assert (!context_used);
4664                 /* the is_null_bb target simply copies the input register to the output */
4665                 mini_emit_iface_cast (cfg, vtable_reg, klass, false_bb, is_null_bb);
4666         } else {
4667                 int klass_reg = alloc_preg (cfg);
4668
4669                 if (klass->rank) {
4670                         int rank_reg = alloc_preg (cfg);
4671                         int eclass_reg = alloc_preg (cfg);
4672
4673                         g_assert (!context_used);
4674                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
4675                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
4676                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4677                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4678                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
4679                         if (klass->cast_class == mono_defaults.object_class) {
4680                                 int parent_reg = alloc_preg (cfg);
4681                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
4682                                 mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, is_null_bb);
4683                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4684                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4685                         } else if (klass->cast_class == mono_defaults.enum_class->parent) {
4686                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, is_null_bb);
4687                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);                          
4688                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4689                         } else if (klass->cast_class == mono_defaults.enum_class) {
4690                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4691                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4692                         } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
4693                                 mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4694                         } else {
4695                                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY)) {
4696                                         /* Check that the object is a vector too */
4697                                         int bounds_reg = alloc_preg (cfg);
4698                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
4699                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
4700                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4701                                 }
4702
4703                                 /* the is_null_bb target simply copies the input register to the output */
4704                                 mini_emit_isninst_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4705                         }
4706                 } else if (mono_class_is_nullable (klass)) {
4707                         g_assert (!context_used);
4708                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4709                         /* the is_null_bb target simply copies the input register to the output */
4710                         mini_emit_isninst_cast (cfg, klass_reg, klass->cast_class, false_bb, is_null_bb);
4711                 } else {
4712                         if (!cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
4713                                 g_assert (!context_used);
4714                                 /* the remoting code is broken, access the class for now */
4715                                 if (0) {/*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4716                                         MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4717                                         if (!vt) {
4718                                                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4719                                                 cfg->exception_ptr = klass;
4720                                                 return NULL;
4721                                         }
4722                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4723                                 } else {
4724                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4725                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4726                                 }
4727                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4728                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, is_null_bb);
4729                         } else {
4730                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4731                                 /* the is_null_bb target simply copies the input register to the output */
4732                                 mini_emit_isninst_cast_inst (cfg, klass_reg, klass, klass_inst, false_bb, is_null_bb);
4733                         }
4734                 }
4735         }
4736
4737         MONO_START_BB (cfg, false_bb);
4738
4739         MONO_EMIT_NEW_PCONST (cfg, res_reg, 0);
4740         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4741
4742         MONO_START_BB (cfg, is_null_bb);
4743
4744         MONO_START_BB (cfg, end_bb);
4745
4746         return ins;
4747 }
4748
4749 static MonoInst*
4750 handle_cisinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4751 {
4752         /* This opcode takes as input an object reference and a class, and returns:
4753         0) if the object is an instance of the class,
4754         1) if the object is not instance of the class,
4755         2) if the object is a proxy whose type cannot be determined */
4756
4757         MonoInst *ins;
4758 #ifndef DISABLE_REMOTING
4759         MonoBasicBlock *true_bb, *false_bb, *false2_bb, *end_bb, *no_proxy_bb, *interface_fail_bb;
4760 #else
4761         MonoBasicBlock *true_bb, *false_bb, *end_bb;
4762 #endif
4763         int obj_reg = src->dreg;
4764         int dreg = alloc_ireg (cfg);
4765         int tmp_reg;
4766 #ifndef DISABLE_REMOTING
4767         int klass_reg = alloc_preg (cfg);
4768 #endif
4769
4770         NEW_BBLOCK (cfg, true_bb);
4771         NEW_BBLOCK (cfg, false_bb);
4772         NEW_BBLOCK (cfg, end_bb);
4773 #ifndef DISABLE_REMOTING
4774         NEW_BBLOCK (cfg, false2_bb);
4775         NEW_BBLOCK (cfg, no_proxy_bb);
4776 #endif
4777
4778         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4779         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, false_bb);
4780
4781         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4782 #ifndef DISABLE_REMOTING
4783                 NEW_BBLOCK (cfg, interface_fail_bb);
4784 #endif
4785
4786                 tmp_reg = alloc_preg (cfg);
4787                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4788 #ifndef DISABLE_REMOTING
4789                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, true_bb);
4790                 MONO_START_BB (cfg, interface_fail_bb);
4791                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4792                 
4793                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, false_bb);
4794
4795                 tmp_reg = alloc_preg (cfg);
4796                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4797                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4798                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false2_bb);                
4799 #else
4800                 mini_emit_iface_cast (cfg, tmp_reg, klass, false_bb, true_bb);
4801 #endif
4802         } else {
4803 #ifndef DISABLE_REMOTING
4804                 tmp_reg = alloc_preg (cfg);
4805                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4806                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4807
4808                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4809                 tmp_reg = alloc_preg (cfg);
4810                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4811                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4812
4813                 tmp_reg = alloc_preg (cfg);             
4814                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4815                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4816                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4817                 
4818                 mini_emit_isninst_cast (cfg, klass_reg, klass, false2_bb, true_bb);
4819                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false2_bb);
4820
4821                 MONO_START_BB (cfg, no_proxy_bb);
4822
4823                 mini_emit_isninst_cast (cfg, klass_reg, klass, false_bb, true_bb);
4824 #else
4825                 g_error ("transparent proxy support is disabled while trying to JIT code that uses it");
4826 #endif
4827         }
4828
4829         MONO_START_BB (cfg, false_bb);
4830
4831         MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4832         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4833
4834 #ifndef DISABLE_REMOTING
4835         MONO_START_BB (cfg, false2_bb);
4836
4837         MONO_EMIT_NEW_ICONST (cfg, dreg, 2);
4838         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4839 #endif
4840
4841         MONO_START_BB (cfg, true_bb);
4842
4843         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4844
4845         MONO_START_BB (cfg, end_bb);
4846
4847         /* FIXME: */
4848         MONO_INST_NEW (cfg, ins, OP_ICONST);
4849         ins->dreg = dreg;
4850         ins->type = STACK_I4;
4851
4852         return ins;
4853 }
4854
4855 static MonoInst*
4856 handle_ccastclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4857 {
4858         /* This opcode takes as input an object reference and a class, and returns:
4859         0) if the object is an instance of the class,
4860         1) if the object is a proxy whose type cannot be determined
4861         an InvalidCastException exception is thrown otherwhise*/
4862         
4863         MonoInst *ins;
4864 #ifndef DISABLE_REMOTING
4865         MonoBasicBlock *end_bb, *ok_result_bb, *no_proxy_bb, *interface_fail_bb, *fail_1_bb;
4866 #else
4867         MonoBasicBlock *ok_result_bb;
4868 #endif
4869         int obj_reg = src->dreg;
4870         int dreg = alloc_ireg (cfg);
4871         int tmp_reg = alloc_preg (cfg);
4872
4873 #ifndef DISABLE_REMOTING
4874         int klass_reg = alloc_preg (cfg);
4875         NEW_BBLOCK (cfg, end_bb);
4876 #endif
4877
4878         NEW_BBLOCK (cfg, ok_result_bb);
4879
4880         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4881         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, ok_result_bb);
4882
4883         save_cast_details (cfg, klass, obj_reg, FALSE);
4884
4885         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4886 #ifndef DISABLE_REMOTING
4887                 NEW_BBLOCK (cfg, interface_fail_bb);
4888         
4889                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4890                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, ok_result_bb);
4891                 MONO_START_BB (cfg, interface_fail_bb);
4892                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4893
4894                 mini_emit_class_check (cfg, klass_reg, mono_defaults.transparent_proxy_class);
4895
4896                 tmp_reg = alloc_preg (cfg);             
4897                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4898                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4899                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
4900                 
4901                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4902                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4903 #else
4904                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4905                 mini_emit_iface_cast (cfg, tmp_reg, klass, NULL, NULL);
4906                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, ok_result_bb);
4907 #endif
4908         } else {
4909 #ifndef DISABLE_REMOTING
4910                 NEW_BBLOCK (cfg, no_proxy_bb);
4911
4912                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4913                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4914                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4915
4916                 tmp_reg = alloc_preg (cfg);
4917                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4918                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4919
4920                 tmp_reg = alloc_preg (cfg);
4921                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4922                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4923                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4924
4925                 NEW_BBLOCK (cfg, fail_1_bb);
4926                 
4927                 mini_emit_isninst_cast (cfg, klass_reg, klass, fail_1_bb, ok_result_bb);
4928
4929                 MONO_START_BB (cfg, fail_1_bb);
4930
4931                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4932                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4933
4934                 MONO_START_BB (cfg, no_proxy_bb);
4935
4936                 mini_emit_castclass (cfg, obj_reg, klass_reg, klass, ok_result_bb);
4937 #else
4938                 g_error ("Transparent proxy support is disabled while trying to JIT code that uses it");
4939 #endif
4940         }
4941
4942         MONO_START_BB (cfg, ok_result_bb);
4943
4944         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4945
4946 #ifndef DISABLE_REMOTING
4947         MONO_START_BB (cfg, end_bb);
4948 #endif
4949
4950         /* FIXME: */
4951         MONO_INST_NEW (cfg, ins, OP_ICONST);
4952         ins->dreg = dreg;
4953         ins->type = STACK_I4;
4954
4955         return ins;
4956 }
4957
4958 static G_GNUC_UNUSED MonoInst*
4959 handle_enum_has_flag (MonoCompile *cfg, MonoClass *klass, MonoInst *enum_this, MonoInst *enum_flag)
4960 {
4961         MonoType *enum_type = mono_type_get_underlying_type (&klass->byval_arg);
4962         guint32 load_opc = mono_type_to_load_membase (cfg, enum_type);
4963         gboolean is_i4;
4964
4965         switch (enum_type->type) {
4966         case MONO_TYPE_I8:
4967         case MONO_TYPE_U8:
4968 #if SIZEOF_REGISTER == 8
4969         case MONO_TYPE_I:
4970         case MONO_TYPE_U:
4971 #endif
4972                 is_i4 = FALSE;
4973                 break;
4974         default:
4975                 is_i4 = TRUE;
4976                 break;
4977         }
4978
4979         {
4980                 MonoInst *load, *and_, *cmp, *ceq;
4981                 int enum_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
4982                 int and_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
4983                 int dest_reg = alloc_ireg (cfg);
4984
4985                 EMIT_NEW_LOAD_MEMBASE (cfg, load, load_opc, enum_reg, enum_this->dreg, 0);
4986                 EMIT_NEW_BIALU (cfg, and_, is_i4 ? OP_IAND : OP_LAND, and_reg, enum_reg, enum_flag->dreg);
4987                 EMIT_NEW_BIALU (cfg, cmp, is_i4 ? OP_ICOMPARE : OP_LCOMPARE, -1, and_reg, enum_flag->dreg);
4988                 EMIT_NEW_UNALU (cfg, ceq, is_i4 ? OP_ICEQ : OP_LCEQ, dest_reg, -1);
4989
4990                 ceq->type = STACK_I4;
4991
4992                 if (!is_i4) {
4993                         load = mono_decompose_opcode (cfg, load);
4994                         and_ = mono_decompose_opcode (cfg, and_);
4995                         cmp = mono_decompose_opcode (cfg, cmp);
4996                         ceq = mono_decompose_opcode (cfg, ceq);
4997                 }
4998
4999                 return ceq;
5000         }
5001 }
5002
5003 /*
5004  * Returns NULL and set the cfg exception on error.
5005  */
5006 static G_GNUC_UNUSED MonoInst*
5007 handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, MonoMethod *method, int context_used, gboolean virtual_)
5008 {
5009         MonoInst *ptr;
5010         int dreg;
5011         gpointer trampoline;
5012         MonoInst *obj, *method_ins, *tramp_ins;
5013         MonoDomain *domain;
5014         guint8 **code_slot;
5015
5016         if (virtual_ && !cfg->llvm_only) {
5017                 MonoMethod *invoke = mono_get_delegate_invoke (klass);
5018                 g_assert (invoke);
5019
5020                 if (!mono_get_delegate_virtual_invoke_impl (mono_method_signature (invoke), context_used ? NULL : method))
5021                         return NULL;
5022         }
5023
5024         obj = handle_alloc (cfg, klass, FALSE, mono_class_check_context_used (klass));
5025         if (!obj)
5026                 return NULL;
5027
5028         /* Inline the contents of mono_delegate_ctor */
5029
5030         /* Set target field */
5031         /* Optimize away setting of NULL target */
5032         if (!(target->opcode == OP_PCONST && target->inst_p0 == 0)) {
5033                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target), target->dreg);
5034                 if (cfg->gen_write_barriers) {
5035                         dreg = alloc_preg (cfg);
5036                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target));
5037                         emit_write_barrier (cfg, ptr, target);
5038                 }
5039         }
5040
5041         /* Set method field */
5042         method_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
5043         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method), method_ins->dreg);
5044
5045         /* 
5046          * To avoid looking up the compiled code belonging to the target method
5047          * in mono_delegate_trampoline (), we allocate a per-domain memory slot to
5048          * store it, and we fill it after the method has been compiled.
5049          */
5050         if (!method->dynamic && !(cfg->opt & MONO_OPT_SHARED)) {
5051                 MonoInst *code_slot_ins;
5052
5053                 if (context_used) {
5054                         code_slot_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD_DELEGATE_CODE);
5055                 } else {
5056                         domain = mono_domain_get ();
5057                         mono_domain_lock (domain);
5058                         if (!domain_jit_info (domain)->method_code_hash)
5059                                 domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
5060                         code_slot = (guint8 **)g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, method);
5061                         if (!code_slot) {
5062                                 code_slot = (guint8 **)mono_domain_alloc0 (domain, sizeof (gpointer));
5063                                 g_hash_table_insert (domain_jit_info (domain)->method_code_hash, method, code_slot);
5064                         }
5065                         mono_domain_unlock (domain);
5066
5067                         code_slot_ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_METHOD_CODE_SLOT, method);
5068                 }
5069                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_code), code_slot_ins->dreg);                
5070         }
5071
5072         if (cfg->llvm_only) {
5073                 MonoInst *args [16];
5074
5075                 if (virtual_) {
5076                         args [0] = obj;
5077                         args [1] = target;
5078                         args [2] = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
5079                         mono_emit_jit_icall (cfg, mono_llvmonly_init_delegate_virtual, args);
5080                 } else {
5081                         args [0] = obj;
5082                         mono_emit_jit_icall (cfg, mono_llvmonly_init_delegate, args);
5083                 }
5084
5085                 return obj;
5086         }
5087
5088         if (cfg->compile_aot) {
5089                 MonoDelegateClassMethodPair *del_tramp;
5090
5091                 del_tramp = (MonoDelegateClassMethodPair *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoDelegateClassMethodPair));
5092                 del_tramp->klass = klass;
5093                 del_tramp->method = context_used ? NULL : method;
5094                 del_tramp->is_virtual = virtual_;
5095                 EMIT_NEW_AOTCONST (cfg, tramp_ins, MONO_PATCH_INFO_DELEGATE_TRAMPOLINE, del_tramp);
5096         } else {
5097                 if (virtual_)
5098                         trampoline = mono_create_delegate_virtual_trampoline (cfg->domain, klass, context_used ? NULL : method);
5099                 else
5100                         trampoline = mono_create_delegate_trampoline_info (cfg->domain, klass, context_used ? NULL : method);
5101                 EMIT_NEW_PCONST (cfg, tramp_ins, trampoline);
5102         }
5103
5104         /* Set invoke_impl field */
5105         if (virtual_) {
5106                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), tramp_ins->dreg);
5107         } else {
5108                 dreg = alloc_preg (cfg);
5109                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, invoke_impl));
5110                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), dreg);
5111
5112                 dreg = alloc_preg (cfg);
5113                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, method_ptr));
5114                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr), dreg);
5115         }
5116
5117         dreg = alloc_preg (cfg);
5118         MONO_EMIT_NEW_ICONST (cfg, dreg, virtual_ ? 1 : 0);
5119         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_is_virtual), dreg);
5120
5121         /* All the checks which are in mono_delegate_ctor () are done by the delegate trampoline */
5122
5123         return obj;
5124 }
5125
5126 static MonoInst*
5127 handle_array_new (MonoCompile *cfg, int rank, MonoInst **sp, unsigned char *ip)
5128 {
5129         MonoJitICallInfo *info;
5130
5131         /* Need to register the icall so it gets an icall wrapper */
5132         info = mono_get_array_new_va_icall (rank);
5133
5134         cfg->flags |= MONO_CFG_HAS_VARARGS;
5135
5136         /* mono_array_new_va () needs a vararg calling convention */
5137         cfg->exception_message = g_strdup ("array-new");
5138         cfg->disable_llvm = TRUE;
5139
5140         /* FIXME: This uses info->sig, but it should use the signature of the wrapper */
5141         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, sp);
5142 }
5143
5144 /*
5145  * handle_constrained_gsharedvt_call:
5146  *
5147  *   Handle constrained calls where the receiver is a gsharedvt type.
5148  * Return the instruction representing the call. Set the cfg exception on failure.
5149  */
5150 static MonoInst*
5151 handle_constrained_gsharedvt_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp, MonoClass *constrained_class,
5152                                                                    gboolean *ref_emit_widen)
5153 {
5154         MonoInst *ins = NULL;
5155         gboolean emit_widen = *ref_emit_widen;
5156
5157         /*
5158          * Constrained calls need to behave differently at runtime dependending on whenever the receiver is instantiated as ref type or as a vtype.
5159          * 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
5160          * pack the arguments into an array, and do the rest of the work in in an icall.
5161          */
5162         if (((cmethod->klass == mono_defaults.object_class) || (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) || (!cmethod->klass->valuetype && cmethod->klass->image != mono_defaults.corlib)) &&
5163                 (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)) &&
5164                 (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]))))) {
5165                 MonoInst *args [16];
5166
5167                 /*
5168                  * This case handles calls to
5169                  * - object:ToString()/Equals()/GetHashCode(),
5170                  * - System.IComparable<T>:CompareTo()
5171                  * - System.IEquatable<T>:Equals ()
5172                  * plus some simple interface calls enough to support AsyncTaskMethodBuilder.
5173                  */
5174
5175                 args [0] = sp [0];
5176                 if (mono_method_check_context_used (cmethod))
5177                         args [1] = emit_get_rgctx_method (cfg, mono_method_check_context_used (cmethod), cmethod, MONO_RGCTX_INFO_METHOD);
5178                 else
5179                         EMIT_NEW_METHODCONST (cfg, args [1], cmethod);
5180                 args [2] = emit_get_rgctx_klass (cfg, mono_class_check_context_used (constrained_class), constrained_class, MONO_RGCTX_INFO_KLASS);
5181
5182                 /* !fsig->hasthis is for the wrapper for the Object.GetType () icall */
5183                 if (fsig->hasthis && fsig->param_count) {
5184                         /* Pass the arguments using a localloc-ed array using the format expected by runtime_invoke () */
5185                         MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
5186                         ins->dreg = alloc_preg (cfg);
5187                         ins->inst_imm = fsig->param_count * sizeof (mgreg_t);
5188                         MONO_ADD_INS (cfg->cbb, ins);
5189                         args [4] = ins;
5190
5191                         if (mini_is_gsharedvt_type (fsig->params [0])) {
5192                                 int addr_reg, deref_arg_reg;
5193
5194                                 ins = emit_get_gsharedvt_info_klass (cfg, mono_class_from_mono_type (fsig->params [0]), MONO_RGCTX_INFO_CLASS_BOX_TYPE);
5195                                 deref_arg_reg = alloc_preg (cfg);
5196                                 /* deref_arg = BOX_TYPE != MONO_GSHAREDVT_BOX_TYPE_VTYPE */
5197                                 EMIT_NEW_BIALU_IMM (cfg, args [3], OP_ISUB_IMM, deref_arg_reg, ins->dreg, 1);
5198
5199                                 EMIT_NEW_VARLOADA_VREG (cfg, ins, sp [1]->dreg, fsig->params [0]);
5200                                 addr_reg = ins->dreg;
5201                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, addr_reg);
5202                         } else {
5203                                 EMIT_NEW_ICONST (cfg, args [3], 0);
5204                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, sp [1]->dreg);
5205                         }
5206                 } else {
5207                         EMIT_NEW_ICONST (cfg, args [3], 0);
5208                         EMIT_NEW_ICONST (cfg, args [4], 0);
5209                 }
5210                 ins = mono_emit_jit_icall (cfg, mono_gsharedvt_constrained_call, args);
5211                 emit_widen = FALSE;
5212
5213                 if (mini_is_gsharedvt_type (fsig->ret)) {
5214                         ins = handle_unbox_gsharedvt (cfg, mono_class_from_mono_type (fsig->ret), ins);
5215                 } else if (MONO_TYPE_IS_PRIMITIVE (fsig->ret) || MONO_TYPE_ISSTRUCT (fsig->ret)) {
5216                         MonoInst *add;
5217
5218                         /* Unbox */
5219                         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), ins->dreg, sizeof (MonoObject));
5220                         MONO_ADD_INS (cfg->cbb, add);
5221                         /* Load value */
5222                         NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, add->dreg, 0);
5223                         MONO_ADD_INS (cfg->cbb, ins);
5224                         /* ins represents the call result */
5225                 }
5226         } else {
5227                 GSHAREDVT_FAILURE (CEE_CALLVIRT);
5228         }
5229
5230         *ref_emit_widen = emit_widen;
5231
5232         return ins;
5233
5234  exception_exit:
5235         return NULL;
5236 }
5237
5238 static void
5239 mono_emit_load_got_addr (MonoCompile *cfg)
5240 {
5241         MonoInst *getaddr, *dummy_use;
5242
5243         if (!cfg->got_var || cfg->got_var_allocated)
5244                 return;
5245
5246         MONO_INST_NEW (cfg, getaddr, OP_LOAD_GOTADDR);
5247         getaddr->cil_code = cfg->header->code;
5248         getaddr->dreg = cfg->got_var->dreg;
5249
5250         /* Add it to the start of the first bblock */
5251         if (cfg->bb_entry->code) {
5252                 getaddr->next = cfg->bb_entry->code;
5253                 cfg->bb_entry->code = getaddr;
5254         }
5255         else
5256                 MONO_ADD_INS (cfg->bb_entry, getaddr);
5257
5258         cfg->got_var_allocated = TRUE;
5259
5260         /* 
5261          * Add a dummy use to keep the got_var alive, since real uses might
5262          * only be generated by the back ends.
5263          * Add it to end_bblock, so the variable's lifetime covers the whole
5264          * method.
5265          * It would be better to make the usage of the got var explicit in all
5266          * cases when the backend needs it (i.e. calls, throw etc.), so this
5267          * wouldn't be needed.
5268          */
5269         NEW_DUMMY_USE (cfg, dummy_use, cfg->got_var);
5270         MONO_ADD_INS (cfg->bb_exit, dummy_use);
5271 }
5272
5273 static int inline_limit;
5274 static gboolean inline_limit_inited;
5275
5276 static gboolean
5277 mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
5278 {
5279         MonoMethodHeaderSummary header;
5280         MonoVTable *vtable;
5281 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
5282         MonoMethodSignature *sig = mono_method_signature (method);
5283         int i;
5284 #endif
5285
5286         if (cfg->disable_inline)
5287                 return FALSE;
5288         if (cfg->gshared)
5289                 return FALSE;
5290
5291         if (cfg->inline_depth > 10)
5292                 return FALSE;
5293
5294         if (!mono_method_get_header_summary (method, &header))
5295                 return FALSE;
5296
5297         /*runtime, icall and pinvoke are checked by summary call*/
5298         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
5299             (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
5300             (mono_class_is_marshalbyref (method->klass)) ||
5301             header.has_clauses)
5302                 return FALSE;
5303
5304         /* also consider num_locals? */
5305         /* Do the size check early to avoid creating vtables */
5306         if (!inline_limit_inited) {
5307                 if (g_getenv ("MONO_INLINELIMIT"))
5308                         inline_limit = atoi (g_getenv ("MONO_INLINELIMIT"));
5309                 else
5310                         inline_limit = INLINE_LENGTH_LIMIT;
5311                 inline_limit_inited = TRUE;
5312         }
5313         if (header.code_size >= inline_limit && !(method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))
5314                 return FALSE;
5315
5316         /*
5317          * if we can initialize the class of the method right away, we do,
5318          * otherwise we don't allow inlining if the class needs initialization,
5319          * since it would mean inserting a call to mono_runtime_class_init()
5320          * inside the inlined code
5321          */
5322         if (!(cfg->opt & MONO_OPT_SHARED)) {
5323                 /* The AggressiveInlining hint is a good excuse to force that cctor to run. */
5324                 if (method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING) {
5325                         vtable = mono_class_vtable (cfg->domain, method->klass);
5326                         if (!vtable)
5327                                 return FALSE;
5328                         if (!cfg->compile_aot) {
5329                                 MonoError error;
5330                                 if (!mono_runtime_class_init_full (vtable, &error)) {
5331                                         mono_error_cleanup (&error);
5332                                         return FALSE;
5333                                 }
5334                         }
5335                 } else if (method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
5336                         if (cfg->run_cctors && method->klass->has_cctor) {
5337                                 /*FIXME it would easier and lazier to just use mono_class_try_get_vtable */
5338                                 if (!method->klass->runtime_info)
5339                                         /* No vtable created yet */
5340                                         return FALSE;
5341                                 vtable = mono_class_vtable (cfg->domain, method->klass);
5342                                 if (!vtable)
5343                                         return FALSE;
5344                                 /* This makes so that inline cannot trigger */
5345                                 /* .cctors: too many apps depend on them */
5346                                 /* running with a specific order... */
5347                                 if (! vtable->initialized)
5348                                         return FALSE;
5349                                 MonoError error;
5350                                 if (!mono_runtime_class_init_full (vtable, &error)) {
5351                                         mono_error_cleanup (&error);
5352                                         return FALSE;
5353                                 }
5354                         }
5355                 } else if (mono_class_needs_cctor_run (method->klass, NULL)) {
5356                         if (!method->klass->runtime_info)
5357                                 /* No vtable created yet */
5358                                 return FALSE;
5359                         vtable = mono_class_vtable (cfg->domain, method->klass);
5360                         if (!vtable)
5361                                 return FALSE;
5362                         if (!vtable->initialized)
5363                                 return FALSE;
5364                 }
5365         } else {
5366                 /* 
5367                  * If we're compiling for shared code
5368                  * the cctor will need to be run at aot method load time, for example,
5369                  * or at the end of the compilation of the inlining method.
5370                  */
5371                 if (mono_class_needs_cctor_run (method->klass, NULL) && !((method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)))
5372                         return FALSE;
5373         }
5374
5375 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
5376         if (mono_arch_is_soft_float ()) {
5377                 /* FIXME: */
5378                 if (sig->ret && sig->ret->type == MONO_TYPE_R4)
5379                         return FALSE;
5380                 for (i = 0; i < sig->param_count; ++i)
5381                         if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_R4)
5382                                 return FALSE;
5383         }
5384 #endif
5385
5386         if (g_list_find (cfg->dont_inline, method))
5387                 return FALSE;
5388
5389         return TRUE;
5390 }
5391
5392 static gboolean
5393 mini_field_access_needs_cctor_run (MonoCompile *cfg, MonoMethod *method, MonoClass *klass, MonoVTable *vtable)
5394 {
5395         if (!cfg->compile_aot) {
5396                 g_assert (vtable);
5397                 if (vtable->initialized)
5398                         return FALSE;
5399         }
5400
5401         if (klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
5402                 if (cfg->method == method)
5403                         return FALSE;
5404         }
5405
5406         if (!mono_class_needs_cctor_run (klass, method))
5407                 return FALSE;
5408
5409         if (! (method->flags & METHOD_ATTRIBUTE_STATIC) && (klass == method->klass))
5410                 /* The initialization is already done before the method is called */
5411                 return FALSE;
5412
5413         return TRUE;
5414 }
5415
5416 static MonoInst*
5417 mini_emit_ldelema_1_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index, gboolean bcheck)
5418 {
5419         MonoInst *ins;
5420         guint32 size;
5421         int mult_reg, add_reg, array_reg, index_reg, index2_reg;
5422         int context_used;
5423
5424         if (mini_is_gsharedvt_variable_klass (klass)) {
5425                 size = -1;
5426         } else {
5427                 mono_class_init (klass);
5428                 size = mono_class_array_element_size (klass);
5429         }
5430
5431         mult_reg = alloc_preg (cfg);
5432         array_reg = arr->dreg;
5433         index_reg = index->dreg;
5434
5435 #if SIZEOF_REGISTER == 8
5436         /* The array reg is 64 bits but the index reg is only 32 */
5437         if (COMPILE_LLVM (cfg)) {
5438                 /* Not needed */
5439                 index2_reg = index_reg;
5440         } else {
5441                 index2_reg = alloc_preg (cfg);
5442                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index2_reg, index_reg);
5443         }
5444 #else
5445         if (index->type == STACK_I8) {
5446                 index2_reg = alloc_preg (cfg);
5447                 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I4, index2_reg, index_reg);
5448         } else {
5449                 index2_reg = index_reg;
5450         }
5451 #endif
5452
5453         if (bcheck)
5454                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index2_reg);
5455
5456 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5457         if (size == 1 || size == 2 || size == 4 || size == 8) {
5458                 static const int fast_log2 [] = { 1, 0, 1, -1, 2, -1, -1, -1, 3 };
5459
5460                 EMIT_NEW_X86_LEA (cfg, ins, array_reg, index2_reg, fast_log2 [size], MONO_STRUCT_OFFSET (MonoArray, vector));
5461                 ins->klass = mono_class_get_element_class (klass);
5462                 ins->type = STACK_MP;
5463
5464                 return ins;
5465         }
5466 #endif          
5467
5468         add_reg = alloc_ireg_mp (cfg);
5469
5470         if (size == -1) {
5471                 MonoInst *rgctx_ins;
5472
5473                 /* gsharedvt */
5474                 g_assert (cfg->gshared);
5475                 context_used = mini_class_check_context_used (cfg, klass);
5476                 g_assert (context_used);
5477                 rgctx_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE);
5478                 MONO_EMIT_NEW_BIALU (cfg, OP_IMUL, mult_reg, index2_reg, rgctx_ins->dreg);
5479         } else {
5480                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MUL_IMM, mult_reg, index2_reg, size);
5481         }
5482         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, array_reg, mult_reg);
5483         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
5484         ins->klass = mono_class_get_element_class (klass);
5485         ins->type = STACK_MP;
5486         MONO_ADD_INS (cfg->cbb, ins);
5487
5488         return ins;
5489 }
5490
5491 static MonoInst*
5492 mini_emit_ldelema_2_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index_ins1, MonoInst *index_ins2)
5493 {
5494         int bounds_reg = alloc_preg (cfg);
5495         int add_reg = alloc_ireg_mp (cfg);
5496         int mult_reg = alloc_preg (cfg);
5497         int mult2_reg = alloc_preg (cfg);
5498         int low1_reg = alloc_preg (cfg);
5499         int low2_reg = alloc_preg (cfg);
5500         int high1_reg = alloc_preg (cfg);
5501         int high2_reg = alloc_preg (cfg);
5502         int realidx1_reg = alloc_preg (cfg);
5503         int realidx2_reg = alloc_preg (cfg);
5504         int sum_reg = alloc_preg (cfg);
5505         int index1, index2, tmpreg;
5506         MonoInst *ins;
5507         guint32 size;
5508
5509         mono_class_init (klass);
5510         size = mono_class_array_element_size (klass);
5511
5512         index1 = index_ins1->dreg;
5513         index2 = index_ins2->dreg;
5514
5515 #if SIZEOF_REGISTER == 8
5516         /* The array reg is 64 bits but the index reg is only 32 */
5517         if (COMPILE_LLVM (cfg)) {
5518                 /* Not needed */
5519         } else {
5520                 tmpreg = alloc_preg (cfg);
5521                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index1);
5522                 index1 = tmpreg;
5523                 tmpreg = alloc_preg (cfg);
5524                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index2);
5525                 index2 = tmpreg;
5526         }
5527 #else
5528         // FIXME: Do we need to do something here for i8 indexes, like in ldelema_1_ins ?
5529         tmpreg = -1;
5530 #endif
5531
5532         /* range checking */
5533         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, 
5534                                        arr->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
5535
5536         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low1_reg, 
5537                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5538         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx1_reg, index1, low1_reg);
5539         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high1_reg, 
5540                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5541         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high1_reg, realidx1_reg);
5542         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
5543
5544         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low2_reg, 
5545                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5546         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx2_reg, index2, low2_reg);
5547         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high2_reg, 
5548                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5549         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high2_reg, realidx2_reg);
5550         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
5551
5552         MONO_EMIT_NEW_BIALU (cfg, OP_PMUL, mult_reg, high2_reg, realidx1_reg);
5553         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, mult_reg, realidx2_reg);
5554         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PMUL_IMM, mult2_reg, sum_reg, size);
5555         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult2_reg, arr->dreg);
5556         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
5557
5558         ins->type = STACK_MP;
5559         ins->klass = klass;
5560         MONO_ADD_INS (cfg->cbb, ins);
5561
5562         return ins;
5563 }
5564
5565 static MonoInst*
5566 mini_emit_ldelema_ins (MonoCompile *cfg, MonoMethod *cmethod, MonoInst **sp, unsigned char *ip, gboolean is_set)
5567 {
5568         int rank;
5569         MonoInst *addr;
5570         MonoMethod *addr_method;
5571         int element_size;
5572         MonoClass *eclass = cmethod->klass->element_class;
5573
5574         rank = mono_method_signature (cmethod)->param_count - (is_set? 1: 0);
5575
5576         if (rank == 1)
5577                 return mini_emit_ldelema_1_ins (cfg, eclass, sp [0], sp [1], TRUE);
5578
5579         /* emit_ldelema_2 depends on OP_LMUL */
5580         if (!cfg->backend->emulate_mul_div && rank == 2 && (cfg->opt & MONO_OPT_INTRINS) && !mini_is_gsharedvt_variable_klass (eclass)) {
5581                 return mini_emit_ldelema_2_ins (cfg, eclass, sp [0], sp [1], sp [2]);
5582         }
5583
5584         if (mini_is_gsharedvt_variable_klass (eclass))
5585                 element_size = 0;
5586         else
5587                 element_size = mono_class_array_element_size (eclass);
5588         addr_method = mono_marshal_get_array_address (rank, element_size);
5589         addr = mono_emit_method_call (cfg, addr_method, sp, NULL);
5590
5591         return addr;
5592 }
5593
5594 static MonoBreakPolicy
5595 always_insert_breakpoint (MonoMethod *method)
5596 {
5597         return MONO_BREAK_POLICY_ALWAYS;
5598 }
5599
5600 static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
5601
5602 /**
5603  * mono_set_break_policy:
5604  * policy_callback: the new callback function
5605  *
5606  * Allow embedders to decide wherther to actually obey breakpoint instructions
5607  * (both break IL instructions and Debugger.Break () method calls), for example
5608  * to not allow an app to be aborted by a perfectly valid IL opcode when executing
5609  * untrusted or semi-trusted code.
5610  *
5611  * @policy_callback will be called every time a break point instruction needs to
5612  * be inserted with the method argument being the method that calls Debugger.Break()
5613  * or has the IL break instruction. The callback should return #MONO_BREAK_POLICY_NEVER
5614  * if it wants the breakpoint to not be effective in the given method.
5615  * #MONO_BREAK_POLICY_ALWAYS is the default.
5616  */
5617 void
5618 mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
5619 {
5620         if (policy_callback)
5621                 break_policy_func = policy_callback;
5622         else
5623                 break_policy_func = always_insert_breakpoint;
5624 }
5625
5626 static gboolean
5627 should_insert_brekpoint (MonoMethod *method) {
5628         switch (break_policy_func (method)) {
5629         case MONO_BREAK_POLICY_ALWAYS:
5630                 return TRUE;
5631         case MONO_BREAK_POLICY_NEVER:
5632                 return FALSE;
5633         case MONO_BREAK_POLICY_ON_DBG:
5634                 g_warning ("mdb no longer supported");
5635                 return FALSE;
5636         default:
5637                 g_warning ("Incorrect value returned from break policy callback");
5638                 return FALSE;
5639         }
5640 }
5641
5642 /* optimize the simple GetGenericValueImpl/SetGenericValueImpl generic icalls */
5643 static MonoInst*
5644 emit_array_generic_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
5645 {
5646         MonoInst *addr, *store, *load;
5647         MonoClass *eklass = mono_class_from_mono_type (fsig->params [2]);
5648
5649         /* the bounds check is already done by the callers */
5650         addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
5651         if (is_set) {
5652                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, args [2]->dreg, 0);
5653                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, addr->dreg, 0, load->dreg);
5654                 if (mini_type_is_reference (fsig->params [2]))
5655                         emit_write_barrier (cfg, addr, load);
5656         } else {
5657                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, addr->dreg, 0);
5658                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, args [2]->dreg, 0, load->dreg);
5659         }
5660         return store;
5661 }
5662
5663
5664 static gboolean
5665 generic_class_is_reference_type (MonoCompile *cfg, MonoClass *klass)
5666 {
5667         return mini_type_is_reference (&klass->byval_arg);
5668 }
5669
5670 static MonoInst*
5671 emit_array_store (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, gboolean safety_checks)
5672 {
5673         if (safety_checks && generic_class_is_reference_type (cfg, klass) &&
5674                 !(sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL)) {
5675                 MonoClass *obj_array = mono_array_class_get_cached (mono_defaults.object_class, 1);
5676                 MonoMethod *helper = mono_marshal_get_virtual_stelemref (obj_array);
5677                 MonoInst *iargs [3];
5678
5679                 if (!helper->slot)
5680                         mono_class_setup_vtable (obj_array);
5681                 g_assert (helper->slot);
5682
5683                 if (sp [0]->type != STACK_OBJ)
5684                         return NULL;
5685                 if (sp [2]->type != STACK_OBJ)
5686                         return NULL;
5687
5688                 iargs [2] = sp [2];
5689                 iargs [1] = sp [1];
5690                 iargs [0] = sp [0];
5691
5692                 return mono_emit_method_call (cfg, helper, iargs, sp [0]);
5693         } else {
5694                 MonoInst *ins;
5695
5696                 if (mini_is_gsharedvt_variable_klass (klass)) {
5697                         MonoInst *addr;
5698
5699                         // FIXME-VT: OP_ICONST optimization
5700                         addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
5701                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5702                         ins->opcode = OP_STOREV_MEMBASE;
5703                 } else if (sp [1]->opcode == OP_ICONST) {
5704                         int array_reg = sp [0]->dreg;
5705                         int index_reg = sp [1]->dreg;
5706                         int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
5707
5708                         if (SIZEOF_REGISTER == 8 && COMPILE_LLVM (cfg))
5709                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, index_reg, index_reg);
5710
5711                         if (safety_checks)
5712                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
5713                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset, sp [2]->dreg);
5714                 } else {
5715                         MonoInst *addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], safety_checks);
5716                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5717                         if (generic_class_is_reference_type (cfg, klass))
5718                                 emit_write_barrier (cfg, addr, sp [2]);
5719                 }
5720                 return ins;
5721         }
5722 }
5723
5724 static MonoInst*
5725 emit_array_unsafe_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
5726 {
5727         MonoClass *eklass;
5728         
5729         if (is_set)
5730                 eklass = mono_class_from_mono_type (fsig->params [2]);
5731         else
5732                 eklass = mono_class_from_mono_type (fsig->ret);
5733
5734         if (is_set) {
5735                 return emit_array_store (cfg, eklass, args, FALSE);
5736         } else {
5737                 MonoInst *ins, *addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
5738                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &eklass->byval_arg, addr->dreg, 0);
5739                 return ins;
5740         }
5741 }
5742
5743 static gboolean
5744 is_unsafe_mov_compatible (MonoCompile *cfg, MonoClass *param_klass, MonoClass *return_klass)
5745 {
5746         uint32_t align;
5747         int param_size, return_size;
5748
5749         param_klass = mono_class_from_mono_type (mini_get_underlying_type (&param_klass->byval_arg));
5750         return_klass = mono_class_from_mono_type (mini_get_underlying_type (&return_klass->byval_arg));
5751
5752         if (cfg->verbose_level > 3)
5753                 printf ("[UNSAFE-MOV-INTRISIC] %s <- %s\n", return_klass->name, param_klass->name);
5754
5755         //Don't allow mixing reference types with value types
5756         if (param_klass->valuetype != return_klass->valuetype) {
5757                 if (cfg->verbose_level > 3)
5758                         printf ("[UNSAFE-MOV-INTRISIC]\tone of the args is a valuetype and the other is not\n");
5759                 return FALSE;
5760         }
5761
5762         if (!param_klass->valuetype) {
5763                 if (cfg->verbose_level > 3)
5764                         printf ("[UNSAFE-MOV-INTRISIC]\targs are reference types\n");
5765                 return TRUE;
5766         }
5767
5768         //That are blitable
5769         if (param_klass->has_references || return_klass->has_references)
5770                 return FALSE;
5771
5772         /* Avoid mixing structs and primitive types/enums, they need to be handled differently in the JIT */
5773         if ((MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && !MONO_TYPE_ISSTRUCT (&return_klass->byval_arg)) ||
5774                 (!MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && MONO_TYPE_ISSTRUCT (&return_klass->byval_arg))) {
5775                         if (cfg->verbose_level > 3)
5776                                 printf ("[UNSAFE-MOV-INTRISIC]\tmixing structs and scalars\n");
5777                 return FALSE;
5778         }
5779
5780         if (param_klass->byval_arg.type == MONO_TYPE_R4 || param_klass->byval_arg.type == MONO_TYPE_R8 ||
5781                 return_klass->byval_arg.type == MONO_TYPE_R4 || return_klass->byval_arg.type == MONO_TYPE_R8) {
5782                 if (cfg->verbose_level > 3)
5783                         printf ("[UNSAFE-MOV-INTRISIC]\tfloat or double are not supported\n");
5784                 return FALSE;
5785         }
5786
5787         param_size = mono_class_value_size (param_klass, &align);
5788         return_size = mono_class_value_size (return_klass, &align);
5789
5790         //We can do it if sizes match
5791         if (param_size == return_size) {
5792                 if (cfg->verbose_level > 3)
5793                         printf ("[UNSAFE-MOV-INTRISIC]\tsame size\n");
5794                 return TRUE;
5795         }
5796
5797         //No simple way to handle struct if sizes don't match
5798         if (MONO_TYPE_ISSTRUCT (&param_klass->byval_arg)) {
5799                 if (cfg->verbose_level > 3)
5800                         printf ("[UNSAFE-MOV-INTRISIC]\tsize mismatch and type is a struct\n");
5801                 return FALSE;
5802         }
5803
5804         /*
5805          * Same reg size category.
5806          * A quick note on why we don't require widening here.
5807          * The intrinsic is "R Array.UnsafeMov<S,R> (S s)".
5808          *
5809          * Since the source value comes from a function argument, the JIT will already have
5810          * the value in a VREG and performed any widening needed before (say, when loading from a field).
5811          */
5812         if (param_size <= 4 && return_size <= 4) {
5813                 if (cfg->verbose_level > 3)
5814                         printf ("[UNSAFE-MOV-INTRISIC]\tsize mismatch but both are of the same reg class\n");
5815                 return TRUE;
5816         }
5817
5818         return FALSE;
5819 }
5820
5821 static MonoInst*
5822 emit_array_unsafe_mov (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args)
5823 {
5824         MonoClass *param_klass = mono_class_from_mono_type (fsig->params [0]);
5825         MonoClass *return_klass = mono_class_from_mono_type (fsig->ret);
5826
5827         if (mini_is_gsharedvt_variable_type (fsig->ret))
5828                 return NULL;
5829
5830         //Valuetypes that are semantically equivalent or numbers than can be widened to
5831         if (is_unsafe_mov_compatible (cfg, param_klass, return_klass))
5832                 return args [0];
5833
5834         //Arrays of valuetypes that are semantically equivalent
5835         if (param_klass->rank == 1 && return_klass->rank == 1 && is_unsafe_mov_compatible (cfg, param_klass->element_class, return_klass->element_class))
5836                 return args [0];
5837
5838         return NULL;
5839 }
5840
5841 static MonoInst*
5842 mini_emit_inst_for_ctor (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5843 {
5844 #ifdef MONO_ARCH_SIMD_INTRINSICS
5845         MonoInst *ins = NULL;
5846
5847         if (cfg->opt & MONO_OPT_SIMD) {
5848                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
5849                 if (ins)
5850                         return ins;
5851         }
5852 #endif
5853
5854         return mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
5855 }
5856
5857 static MonoInst*
5858 emit_memory_barrier (MonoCompile *cfg, int kind)
5859 {
5860         MonoInst *ins = NULL;
5861         MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
5862         MONO_ADD_INS (cfg->cbb, ins);
5863         ins->backend.memory_barrier_kind = kind;
5864
5865         return ins;
5866 }
5867
5868 static MonoInst*
5869 llvm_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5870 {
5871         MonoInst *ins = NULL;
5872         int opcode = 0;
5873
5874         /* The LLVM backend supports these intrinsics */
5875         if (cmethod->klass == mono_defaults.math_class) {
5876                 if (strcmp (cmethod->name, "Sin") == 0) {
5877                         opcode = OP_SIN;
5878                 } else if (strcmp (cmethod->name, "Cos") == 0) {
5879                         opcode = OP_COS;
5880                 } else if (strcmp (cmethod->name, "Sqrt") == 0) {
5881                         opcode = OP_SQRT;
5882                 } else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8) {
5883                         opcode = OP_ABS;
5884                 }
5885
5886                 if (opcode && fsig->param_count == 1) {
5887                         MONO_INST_NEW (cfg, ins, opcode);
5888                         ins->type = STACK_R8;
5889                         ins->dreg = mono_alloc_dreg (cfg, ins->type);
5890                         ins->sreg1 = args [0]->dreg;
5891                         MONO_ADD_INS (cfg->cbb, ins);
5892                 }
5893
5894                 opcode = 0;
5895                 if (cfg->opt & MONO_OPT_CMOV) {
5896                         if (strcmp (cmethod->name, "Min") == 0) {
5897                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5898                                         opcode = OP_IMIN;
5899                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5900                                         opcode = OP_IMIN_UN;
5901                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5902                                         opcode = OP_LMIN;
5903                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5904                                         opcode = OP_LMIN_UN;
5905                         } else if (strcmp (cmethod->name, "Max") == 0) {
5906                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5907                                         opcode = OP_IMAX;
5908                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5909                                         opcode = OP_IMAX_UN;
5910                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5911                                         opcode = OP_LMAX;
5912                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5913                                         opcode = OP_LMAX_UN;
5914                         }
5915                 }
5916
5917                 if (opcode && fsig->param_count == 2) {
5918                         MONO_INST_NEW (cfg, ins, opcode);
5919                         ins->type = fsig->params [0]->type == MONO_TYPE_I4 ? STACK_I4 : STACK_I8;
5920                         ins->dreg = mono_alloc_dreg (cfg, ins->type);
5921                         ins->sreg1 = args [0]->dreg;
5922                         ins->sreg2 = args [1]->dreg;
5923                         MONO_ADD_INS (cfg->cbb, ins);
5924                 }
5925         }
5926
5927         return ins;
5928 }
5929
5930 static MonoInst*
5931 mini_emit_inst_for_sharable_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5932 {
5933         if (cmethod->klass == mono_defaults.array_class) {
5934                 if (strcmp (cmethod->name, "UnsafeStore") == 0)
5935                         return emit_array_unsafe_access (cfg, fsig, args, TRUE);
5936                 else if (strcmp (cmethod->name, "UnsafeLoad") == 0)
5937                         return emit_array_unsafe_access (cfg, fsig, args, FALSE);
5938                 else if (strcmp (cmethod->name, "UnsafeMov") == 0)
5939                         return emit_array_unsafe_mov (cfg, fsig, args);
5940         }
5941
5942         return NULL;
5943 }
5944
5945 static MonoInst*
5946 mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5947 {
5948         MonoInst *ins = NULL;
5949
5950          MonoClass *runtime_helpers_class = mono_class_get_runtime_helpers_class ();
5951
5952         if (cmethod->klass == mono_defaults.string_class) {
5953                 if (strcmp (cmethod->name, "get_Chars") == 0 && fsig->param_count + fsig->hasthis == 2) {
5954                         int dreg = alloc_ireg (cfg);
5955                         int index_reg = alloc_preg (cfg);
5956                         int add_reg = alloc_preg (cfg);
5957
5958 #if SIZEOF_REGISTER == 8
5959                         if (COMPILE_LLVM (cfg)) {
5960                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, index_reg, args [1]->dreg);
5961                         } else {
5962                                 /* The array reg is 64 bits but the index reg is only 32 */
5963                                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index_reg, args [1]->dreg);
5964                         }
5965 #else
5966                         index_reg = args [1]->dreg;
5967 #endif  
5968                         MONO_EMIT_BOUNDS_CHECK (cfg, args [0]->dreg, MonoString, length, index_reg);
5969
5970 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5971                         EMIT_NEW_X86_LEA (cfg, ins, args [0]->dreg, index_reg, 1, MONO_STRUCT_OFFSET (MonoString, chars));
5972                         add_reg = ins->dreg;
5973                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5974                                                                    add_reg, 0);
5975 #else
5976                         int mult_reg = alloc_preg (cfg);
5977                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, index_reg, 1);
5978                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
5979                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5980                                                                    add_reg, MONO_STRUCT_OFFSET (MonoString, chars));
5981 #endif
5982                         type_from_op (cfg, ins, NULL, NULL);
5983                         return ins;
5984                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count + fsig->hasthis == 1) {
5985                         int dreg = alloc_ireg (cfg);
5986                         /* Decompose later to allow more optimizations */
5987                         EMIT_NEW_UNALU (cfg, ins, OP_STRLEN, dreg, args [0]->dreg);
5988                         ins->type = STACK_I4;
5989                         ins->flags |= MONO_INST_FAULT;
5990                         cfg->cbb->has_array_access = TRUE;
5991                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
5992
5993                         return ins;
5994                 } else 
5995                         return NULL;
5996         } else if (cmethod->klass == mono_defaults.object_class) {
5997                 if (strcmp (cmethod->name, "GetType") == 0 && fsig->param_count + fsig->hasthis == 1) {
5998                         int dreg = alloc_ireg_ref (cfg);
5999                         int vt_reg = alloc_preg (cfg);
6000                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vt_reg, args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
6001                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, vt_reg, MONO_STRUCT_OFFSET (MonoVTable, type));
6002                         type_from_op (cfg, ins, NULL, NULL);
6003
6004                         return ins;
6005                 } else if (!cfg->backend->emulate_mul_div && strcmp (cmethod->name, "InternalGetHashCode") == 0 && fsig->param_count == 1 && !mono_gc_is_moving ()) {
6006                         int dreg = alloc_ireg (cfg);
6007                         int t1 = alloc_ireg (cfg);
6008         
6009                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, t1, args [0]->dreg, 3);
6010                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_MUL_IMM, dreg, t1, 2654435761u);
6011                         ins->type = STACK_I4;
6012
6013                         return ins;
6014                 } else if (strcmp (cmethod->name, ".ctor") == 0 && fsig->param_count == 0) {
6015                         MONO_INST_NEW (cfg, ins, OP_NOP);
6016                         MONO_ADD_INS (cfg->cbb, ins);
6017                         return ins;
6018                 } else
6019                         return NULL;
6020         } else if (cmethod->klass == mono_defaults.array_class) {
6021                 if (strcmp (cmethod->name, "GetGenericValueImpl") == 0 && fsig->param_count + fsig->hasthis == 3 && !cfg->gsharedvt)
6022                         return emit_array_generic_access (cfg, fsig, args, FALSE);
6023                 else if (strcmp (cmethod->name, "SetGenericValueImpl") == 0 && fsig->param_count + fsig->hasthis == 3 && !cfg->gsharedvt)
6024                         return emit_array_generic_access (cfg, fsig, args, TRUE);
6025
6026 #ifndef MONO_BIG_ARRAYS
6027                 /*
6028                  * This is an inline version of GetLength/GetLowerBound(0) used frequently in
6029                  * Array methods.
6030                  */
6031                 else if (((strcmp (cmethod->name, "GetLength") == 0 && fsig->param_count + fsig->hasthis == 2) ||
6032                          (strcmp (cmethod->name, "GetLowerBound") == 0 && fsig->param_count + fsig->hasthis == 2)) &&
6033                          args [1]->opcode == OP_ICONST && args [1]->inst_c0 == 0) {
6034                         int dreg = alloc_ireg (cfg);
6035                         int bounds_reg = alloc_ireg_mp (cfg);
6036                         MonoBasicBlock *end_bb, *szarray_bb;
6037                         gboolean get_length = strcmp (cmethod->name, "GetLength") == 0;
6038
6039                         NEW_BBLOCK (cfg, end_bb);
6040                         NEW_BBLOCK (cfg, szarray_bb);
6041
6042                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOAD_MEMBASE, bounds_reg,
6043                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
6044                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
6045                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, szarray_bb);
6046                         /* Non-szarray case */
6047                         if (get_length)
6048                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
6049                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
6050                         else
6051                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
6052                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
6053                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
6054                         MONO_START_BB (cfg, szarray_bb);
6055                         /* Szarray case */
6056                         if (get_length)
6057                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
6058                                                                            args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
6059                         else
6060                                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
6061                         MONO_START_BB (cfg, end_bb);
6062
6063                         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, dreg, dreg);
6064                         ins->type = STACK_I4;
6065                         
6066                         return ins;
6067                 }
6068 #endif
6069
6070                 if (cmethod->name [0] != 'g')
6071                         return NULL;
6072
6073                 if (strcmp (cmethod->name, "get_Rank") == 0 && fsig->param_count + fsig->hasthis == 1) {
6074                         int dreg = alloc_ireg (cfg);
6075                         int vtable_reg = alloc_preg (cfg);
6076                         MONO_EMIT_NEW_LOAD_MEMBASE_OP_FAULT (cfg, OP_LOAD_MEMBASE, vtable_reg, 
6077                                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
6078                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU1_MEMBASE, dreg,
6079                                                                    vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
6080                         type_from_op (cfg, ins, NULL, NULL);
6081
6082                         return ins;
6083                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count + fsig->hasthis == 1) {
6084                         int dreg = alloc_ireg (cfg);
6085
6086                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOADI4_MEMBASE, dreg, 
6087                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
6088                         type_from_op (cfg, ins, NULL, NULL);
6089
6090                         return ins;
6091                 } else
6092                         return NULL;
6093         } else if (cmethod->klass == runtime_helpers_class) {
6094                 if (strcmp (cmethod->name, "get_OffsetToStringData") == 0 && fsig->param_count == 0) {
6095                         EMIT_NEW_ICONST (cfg, ins, MONO_STRUCT_OFFSET (MonoString, chars));
6096                         return ins;
6097                 } else
6098                         return NULL;
6099         } else if (cmethod->klass == mono_defaults.monitor_class) {
6100                 gboolean is_enter = FALSE;
6101
6102                 if (!strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1)
6103                         is_enter = TRUE;
6104
6105                 if (is_enter) {
6106                         /*
6107                          * To make async stack traces work, icalls which can block should have a wrapper.
6108                          * For Monitor.Enter, emit two calls: a fastpath which doesn't have a wrapper, and a slowpath, which does.
6109                          */
6110                         MonoBasicBlock *end_bb;
6111
6112                         NEW_BBLOCK (cfg, end_bb);
6113
6114                         ins = mono_emit_jit_icall (cfg, (gpointer)mono_monitor_enter_fast, args);
6115                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, ins->dreg, 0);
6116                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, end_bb);
6117                         ins = mono_emit_jit_icall (cfg, (gpointer)mono_monitor_enter, args);
6118                         MONO_START_BB (cfg, end_bb);
6119                         return ins;
6120                 }
6121         } else if (cmethod->klass == mono_defaults.thread_class) {
6122                 if (strcmp (cmethod->name, "SpinWait_nop") == 0 && fsig->param_count == 0) {
6123                         MONO_INST_NEW (cfg, ins, OP_RELAXED_NOP);
6124                         MONO_ADD_INS (cfg->cbb, ins);
6125                         return ins;
6126                 } else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0) {
6127                         return emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6128                 } else if (!strcmp (cmethod->name, "VolatileRead") && fsig->param_count == 1) {
6129                         guint32 opcode = 0;
6130                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6131
6132                         if (fsig->params [0]->type == MONO_TYPE_I1)
6133                                 opcode = OP_LOADI1_MEMBASE;
6134                         else if (fsig->params [0]->type == MONO_TYPE_U1)
6135                                 opcode = OP_LOADU1_MEMBASE;
6136                         else if (fsig->params [0]->type == MONO_TYPE_I2)
6137                                 opcode = OP_LOADI2_MEMBASE;
6138                         else if (fsig->params [0]->type == MONO_TYPE_U2)
6139                                 opcode = OP_LOADU2_MEMBASE;
6140                         else if (fsig->params [0]->type == MONO_TYPE_I4)
6141                                 opcode = OP_LOADI4_MEMBASE;
6142                         else if (fsig->params [0]->type == MONO_TYPE_U4)
6143                                 opcode = OP_LOADU4_MEMBASE;
6144                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
6145                                 opcode = OP_LOADI8_MEMBASE;
6146                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6147                                 opcode = OP_LOADR4_MEMBASE;
6148                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6149                                 opcode = OP_LOADR8_MEMBASE;
6150                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
6151                                 opcode = OP_LOAD_MEMBASE;
6152
6153                         if (opcode) {
6154                                 MONO_INST_NEW (cfg, ins, opcode);
6155                                 ins->inst_basereg = args [0]->dreg;
6156                                 ins->inst_offset = 0;
6157                                 MONO_ADD_INS (cfg->cbb, ins);
6158
6159                                 switch (fsig->params [0]->type) {
6160                                 case MONO_TYPE_I1:
6161                                 case MONO_TYPE_U1:
6162                                 case MONO_TYPE_I2:
6163                                 case MONO_TYPE_U2:
6164                                 case MONO_TYPE_I4:
6165                                 case MONO_TYPE_U4:
6166                                         ins->dreg = mono_alloc_ireg (cfg);
6167                                         ins->type = STACK_I4;
6168                                         break;
6169                                 case MONO_TYPE_I8:
6170                                 case MONO_TYPE_U8:
6171                                         ins->dreg = mono_alloc_lreg (cfg);
6172                                         ins->type = STACK_I8;
6173                                         break;
6174                                 case MONO_TYPE_I:
6175                                 case MONO_TYPE_U:
6176                                         ins->dreg = mono_alloc_ireg (cfg);
6177 #if SIZEOF_REGISTER == 8
6178                                         ins->type = STACK_I8;
6179 #else
6180                                         ins->type = STACK_I4;
6181 #endif
6182                                         break;
6183                                 case MONO_TYPE_R4:
6184                                 case MONO_TYPE_R8:
6185                                         ins->dreg = mono_alloc_freg (cfg);
6186                                         ins->type = STACK_R8;
6187                                         break;
6188                                 default:
6189                                         g_assert (mini_type_is_reference (fsig->params [0]));
6190                                         ins->dreg = mono_alloc_ireg_ref (cfg);
6191                                         ins->type = STACK_OBJ;
6192                                         break;
6193                                 }
6194
6195                                 if (opcode == OP_LOADI8_MEMBASE)
6196                                         ins = mono_decompose_opcode (cfg, ins);
6197
6198                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6199
6200                                 return ins;
6201                         }
6202                 } else if (!strcmp (cmethod->name, "VolatileWrite") && fsig->param_count == 2) {
6203                         guint32 opcode = 0;
6204                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6205
6206                         if (fsig->params [0]->type == MONO_TYPE_I1 || fsig->params [0]->type == MONO_TYPE_U1)
6207                                 opcode = OP_STOREI1_MEMBASE_REG;
6208                         else if (fsig->params [0]->type == MONO_TYPE_I2 || fsig->params [0]->type == MONO_TYPE_U2)
6209                                 opcode = OP_STOREI2_MEMBASE_REG;
6210                         else if (fsig->params [0]->type == MONO_TYPE_I4 || fsig->params [0]->type == MONO_TYPE_U4)
6211                                 opcode = OP_STOREI4_MEMBASE_REG;
6212                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
6213                                 opcode = OP_STOREI8_MEMBASE_REG;
6214                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6215                                 opcode = OP_STORER4_MEMBASE_REG;
6216                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6217                                 opcode = OP_STORER8_MEMBASE_REG;
6218                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
6219                                 opcode = OP_STORE_MEMBASE_REG;
6220
6221                         if (opcode) {
6222                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6223
6224                                 MONO_INST_NEW (cfg, ins, opcode);
6225                                 ins->sreg1 = args [1]->dreg;
6226                                 ins->inst_destbasereg = args [0]->dreg;
6227                                 ins->inst_offset = 0;
6228                                 MONO_ADD_INS (cfg->cbb, ins);
6229
6230                                 if (opcode == OP_STOREI8_MEMBASE_REG)
6231                                         ins = mono_decompose_opcode (cfg, ins);
6232
6233                                 return ins;
6234                         }
6235                 }
6236         } else if (cmethod->klass->image == mono_defaults.corlib &&
6237                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
6238                            (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
6239                 ins = NULL;
6240
6241 #if SIZEOF_REGISTER == 8
6242                 if (!cfg->llvm_only && strcmp (cmethod->name, "Read") == 0 && fsig->param_count == 1 && (fsig->params [0]->type == MONO_TYPE_I8)) {
6243                         if (!cfg->llvm_only && mono_arch_opcode_supported (OP_ATOMIC_LOAD_I8)) {
6244                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_LOAD_I8);
6245                                 ins->dreg = mono_alloc_preg (cfg);
6246                                 ins->sreg1 = args [0]->dreg;
6247                                 ins->type = STACK_I8;
6248                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_SEQ;
6249                                 MONO_ADD_INS (cfg->cbb, ins);
6250                         } else {
6251                                 MonoInst *load_ins;
6252
6253                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6254
6255                                 /* 64 bit reads are already atomic */
6256                                 MONO_INST_NEW (cfg, load_ins, OP_LOADI8_MEMBASE);
6257                                 load_ins->dreg = mono_alloc_preg (cfg);
6258                                 load_ins->inst_basereg = args [0]->dreg;
6259                                 load_ins->inst_offset = 0;
6260                                 load_ins->type = STACK_I8;
6261                                 MONO_ADD_INS (cfg->cbb, load_ins);
6262
6263                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6264
6265                                 ins = load_ins;
6266                         }
6267                 }
6268 #endif
6269
6270                 if (strcmp (cmethod->name, "Increment") == 0 && fsig->param_count == 1) {
6271                         MonoInst *ins_iconst;
6272                         guint32 opcode = 0;
6273
6274                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6275                                 opcode = OP_ATOMIC_ADD_I4;
6276                                 cfg->has_atomic_add_i4 = TRUE;
6277                         }
6278 #if SIZEOF_REGISTER == 8
6279                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6280                                 opcode = OP_ATOMIC_ADD_I8;
6281 #endif
6282                         if (opcode) {
6283                                 if (!mono_arch_opcode_supported (opcode))
6284                                         return NULL;
6285                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
6286                                 ins_iconst->inst_c0 = 1;
6287                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
6288                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
6289
6290                                 MONO_INST_NEW (cfg, ins, opcode);
6291                                 ins->dreg = mono_alloc_ireg (cfg);
6292                                 ins->inst_basereg = args [0]->dreg;
6293                                 ins->inst_offset = 0;
6294                                 ins->sreg2 = ins_iconst->dreg;
6295                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6296                                 MONO_ADD_INS (cfg->cbb, ins);
6297                         }
6298                 } else if (strcmp (cmethod->name, "Decrement") == 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, "Add") == 0 && fsig->param_count == 2) {
6327                         guint32 opcode = 0;
6328
6329                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6330                                 opcode = OP_ATOMIC_ADD_I4;
6331                                 cfg->has_atomic_add_i4 = TRUE;
6332                         }
6333 #if SIZEOF_REGISTER == 8
6334                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6335                                 opcode = OP_ATOMIC_ADD_I8;
6336 #endif
6337                         if (opcode) {
6338                                 if (!mono_arch_opcode_supported (opcode))
6339                                         return NULL;
6340                                 MONO_INST_NEW (cfg, ins, opcode);
6341                                 ins->dreg = mono_alloc_ireg (cfg);
6342                                 ins->inst_basereg = args [0]->dreg;
6343                                 ins->inst_offset = 0;
6344                                 ins->sreg2 = args [1]->dreg;
6345                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6346                                 MONO_ADD_INS (cfg->cbb, ins);
6347                         }
6348                 }
6349                 else if (strcmp (cmethod->name, "Exchange") == 0 && fsig->param_count == 2) {
6350                         MonoInst *f2i = NULL, *i2f;
6351                         guint32 opcode, f2i_opcode, i2f_opcode;
6352                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6353                         gboolean is_float = fsig->params [0]->type == MONO_TYPE_R4 || fsig->params [0]->type == MONO_TYPE_R8;
6354
6355                         if (fsig->params [0]->type == MONO_TYPE_I4 ||
6356                             fsig->params [0]->type == MONO_TYPE_R4) {
6357                                 opcode = OP_ATOMIC_EXCHANGE_I4;
6358                                 f2i_opcode = OP_MOVE_F_TO_I4;
6359                                 i2f_opcode = OP_MOVE_I4_TO_F;
6360                                 cfg->has_atomic_exchange_i4 = TRUE;
6361                         }
6362 #if SIZEOF_REGISTER == 8
6363                         else if (is_ref ||
6364                                  fsig->params [0]->type == MONO_TYPE_I8 ||
6365                                  fsig->params [0]->type == MONO_TYPE_R8 ||
6366                                  fsig->params [0]->type == MONO_TYPE_I) {
6367                                 opcode = OP_ATOMIC_EXCHANGE_I8;
6368                                 f2i_opcode = OP_MOVE_F_TO_I8;
6369                                 i2f_opcode = OP_MOVE_I8_TO_F;
6370                         }
6371 #else
6372                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I) {
6373                                 opcode = OP_ATOMIC_EXCHANGE_I4;
6374                                 cfg->has_atomic_exchange_i4 = TRUE;
6375                         }
6376 #endif
6377                         else
6378                                 return NULL;
6379
6380                         if (!mono_arch_opcode_supported (opcode))
6381                                 return NULL;
6382
6383                         if (is_float) {
6384                                 /* TODO: Decompose these opcodes instead of bailing here. */
6385                                 if (COMPILE_SOFT_FLOAT (cfg))
6386                                         return NULL;
6387
6388                                 MONO_INST_NEW (cfg, f2i, f2i_opcode);
6389                                 f2i->dreg = mono_alloc_ireg (cfg);
6390                                 f2i->sreg1 = args [1]->dreg;
6391                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6392                                         f2i->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6393                                 MONO_ADD_INS (cfg->cbb, f2i);
6394                         }
6395
6396                         MONO_INST_NEW (cfg, ins, opcode);
6397                         ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : mono_alloc_ireg (cfg);
6398                         ins->inst_basereg = args [0]->dreg;
6399                         ins->inst_offset = 0;
6400                         ins->sreg2 = is_float ? f2i->dreg : args [1]->dreg;
6401                         MONO_ADD_INS (cfg->cbb, ins);
6402
6403                         switch (fsig->params [0]->type) {
6404                         case MONO_TYPE_I4:
6405                                 ins->type = STACK_I4;
6406                                 break;
6407                         case MONO_TYPE_I8:
6408                                 ins->type = STACK_I8;
6409                                 break;
6410                         case MONO_TYPE_I:
6411 #if SIZEOF_REGISTER == 8
6412                                 ins->type = STACK_I8;
6413 #else
6414                                 ins->type = STACK_I4;
6415 #endif
6416                                 break;
6417                         case MONO_TYPE_R4:
6418                         case MONO_TYPE_R8:
6419                                 ins->type = STACK_R8;
6420                                 break;
6421                         default:
6422                                 g_assert (mini_type_is_reference (fsig->params [0]));
6423                                 ins->type = STACK_OBJ;
6424                                 break;
6425                         }
6426
6427                         if (is_float) {
6428                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
6429                                 i2f->dreg = mono_alloc_freg (cfg);
6430                                 i2f->sreg1 = ins->dreg;
6431                                 i2f->type = STACK_R8;
6432                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
6433                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6434                                 MONO_ADD_INS (cfg->cbb, i2f);
6435
6436                                 ins = i2f;
6437                         }
6438
6439                         if (cfg->gen_write_barriers && is_ref)
6440                                 emit_write_barrier (cfg, args [0], args [1]);
6441                 }
6442                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 3) {
6443                         MonoInst *f2i_new = NULL, *f2i_cmp = NULL, *i2f;
6444                         guint32 opcode, f2i_opcode, i2f_opcode;
6445                         gboolean is_ref = mini_type_is_reference (fsig->params [1]);
6446                         gboolean is_float = fsig->params [1]->type == MONO_TYPE_R4 || fsig->params [1]->type == MONO_TYPE_R8;
6447
6448                         if (fsig->params [1]->type == MONO_TYPE_I4 ||
6449                             fsig->params [1]->type == MONO_TYPE_R4) {
6450                                 opcode = OP_ATOMIC_CAS_I4;
6451                                 f2i_opcode = OP_MOVE_F_TO_I4;
6452                                 i2f_opcode = OP_MOVE_I4_TO_F;
6453                                 cfg->has_atomic_cas_i4 = TRUE;
6454                         }
6455 #if SIZEOF_REGISTER == 8
6456                         else if (is_ref ||
6457                                  fsig->params [1]->type == MONO_TYPE_I8 ||
6458                                  fsig->params [1]->type == MONO_TYPE_R8 ||
6459                                  fsig->params [1]->type == MONO_TYPE_I) {
6460                                 opcode = OP_ATOMIC_CAS_I8;
6461                                 f2i_opcode = OP_MOVE_F_TO_I8;
6462                                 i2f_opcode = OP_MOVE_I8_TO_F;
6463                         }
6464 #else
6465                         else if (is_ref || fsig->params [1]->type == MONO_TYPE_I) {
6466                                 opcode = OP_ATOMIC_CAS_I4;
6467                                 cfg->has_atomic_cas_i4 = TRUE;
6468                         }
6469 #endif
6470                         else
6471                                 return NULL;
6472
6473                         if (!mono_arch_opcode_supported (opcode))
6474                                 return NULL;
6475
6476                         if (is_float) {
6477                                 /* TODO: Decompose these opcodes instead of bailing here. */
6478                                 if (COMPILE_SOFT_FLOAT (cfg))
6479                                         return NULL;
6480
6481                                 MONO_INST_NEW (cfg, f2i_new, f2i_opcode);
6482                                 f2i_new->dreg = mono_alloc_ireg (cfg);
6483                                 f2i_new->sreg1 = args [1]->dreg;
6484                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6485                                         f2i_new->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6486                                 MONO_ADD_INS (cfg->cbb, f2i_new);
6487
6488                                 MONO_INST_NEW (cfg, f2i_cmp, f2i_opcode);
6489                                 f2i_cmp->dreg = mono_alloc_ireg (cfg);
6490                                 f2i_cmp->sreg1 = args [2]->dreg;
6491                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6492                                         f2i_cmp->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6493                                 MONO_ADD_INS (cfg->cbb, f2i_cmp);
6494                         }
6495
6496                         MONO_INST_NEW (cfg, ins, opcode);
6497                         ins->dreg = is_ref ? alloc_ireg_ref (cfg) : alloc_ireg (cfg);
6498                         ins->sreg1 = args [0]->dreg;
6499                         ins->sreg2 = is_float ? f2i_new->dreg : args [1]->dreg;
6500                         ins->sreg3 = is_float ? f2i_cmp->dreg : args [2]->dreg;
6501                         MONO_ADD_INS (cfg->cbb, ins);
6502
6503                         switch (fsig->params [1]->type) {
6504                         case MONO_TYPE_I4:
6505                                 ins->type = STACK_I4;
6506                                 break;
6507                         case MONO_TYPE_I8:
6508                                 ins->type = STACK_I8;
6509                                 break;
6510                         case MONO_TYPE_I:
6511 #if SIZEOF_REGISTER == 8
6512                                 ins->type = STACK_I8;
6513 #else
6514                                 ins->type = STACK_I4;
6515 #endif
6516                                 break;
6517                         case MONO_TYPE_R4:
6518                                 ins->type = cfg->r4_stack_type;
6519                                 break;
6520                         case MONO_TYPE_R8:
6521                                 ins->type = STACK_R8;
6522                                 break;
6523                         default:
6524                                 g_assert (mini_type_is_reference (fsig->params [1]));
6525                                 ins->type = STACK_OBJ;
6526                                 break;
6527                         }
6528
6529                         if (is_float) {
6530                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
6531                                 i2f->dreg = mono_alloc_freg (cfg);
6532                                 i2f->sreg1 = ins->dreg;
6533                                 i2f->type = STACK_R8;
6534                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
6535                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6536                                 MONO_ADD_INS (cfg->cbb, i2f);
6537
6538                                 ins = i2f;
6539                         }
6540
6541                         if (cfg->gen_write_barriers && is_ref)
6542                                 emit_write_barrier (cfg, args [0], args [1]);
6543                 }
6544                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 4 &&
6545                          fsig->params [1]->type == MONO_TYPE_I4) {
6546                         MonoInst *cmp, *ceq;
6547
6548                         if (!mono_arch_opcode_supported (OP_ATOMIC_CAS_I4))
6549                                 return NULL;
6550
6551                         /* int32 r = CAS (location, value, comparand); */
6552                         MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I4);
6553                         ins->dreg = alloc_ireg (cfg);
6554                         ins->sreg1 = args [0]->dreg;
6555                         ins->sreg2 = args [1]->dreg;
6556                         ins->sreg3 = args [2]->dreg;
6557                         ins->type = STACK_I4;
6558                         MONO_ADD_INS (cfg->cbb, ins);
6559
6560                         /* bool result = r == comparand; */
6561                         MONO_INST_NEW (cfg, cmp, OP_ICOMPARE);
6562                         cmp->sreg1 = ins->dreg;
6563                         cmp->sreg2 = args [2]->dreg;
6564                         cmp->type = STACK_I4;
6565                         MONO_ADD_INS (cfg->cbb, cmp);
6566
6567                         MONO_INST_NEW (cfg, ceq, OP_ICEQ);
6568                         ceq->dreg = alloc_ireg (cfg);
6569                         ceq->type = STACK_I4;
6570                         MONO_ADD_INS (cfg->cbb, ceq);
6571
6572                         /* *success = result; */
6573                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, args [3]->dreg, 0, ceq->dreg);
6574
6575                         cfg->has_atomic_cas_i4 = TRUE;
6576                 }
6577                 else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0)
6578                         ins = emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6579
6580                 if (ins)
6581                         return ins;
6582         } else if (cmethod->klass->image == mono_defaults.corlib &&
6583                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
6584                            (strcmp (cmethod->klass->name, "Volatile") == 0)) {
6585                 ins = NULL;
6586
6587                 if (!cfg->llvm_only && !strcmp (cmethod->name, "Read") && fsig->param_count == 1) {
6588                         guint32 opcode = 0;
6589                         MonoType *t = fsig->params [0];
6590                         gboolean is_ref;
6591                         gboolean is_float = t->type == MONO_TYPE_R4 || t->type == MONO_TYPE_R8;
6592
6593                         g_assert (t->byref);
6594                         /* t is a byref type, so the reference check is more complicated */
6595                         is_ref = mini_type_is_reference (&mono_class_from_mono_type (t)->byval_arg);
6596                         if (t->type == MONO_TYPE_I1)
6597                                 opcode = OP_ATOMIC_LOAD_I1;
6598                         else if (t->type == MONO_TYPE_U1 || t->type == MONO_TYPE_BOOLEAN)
6599                                 opcode = OP_ATOMIC_LOAD_U1;
6600                         else if (t->type == MONO_TYPE_I2)
6601                                 opcode = OP_ATOMIC_LOAD_I2;
6602                         else if (t->type == MONO_TYPE_U2)
6603                                 opcode = OP_ATOMIC_LOAD_U2;
6604                         else if (t->type == MONO_TYPE_I4)
6605                                 opcode = OP_ATOMIC_LOAD_I4;
6606                         else if (t->type == MONO_TYPE_U4)
6607                                 opcode = OP_ATOMIC_LOAD_U4;
6608                         else if (t->type == MONO_TYPE_R4)
6609                                 opcode = OP_ATOMIC_LOAD_R4;
6610                         else if (t->type == MONO_TYPE_R8)
6611                                 opcode = OP_ATOMIC_LOAD_R8;
6612 #if SIZEOF_REGISTER == 8
6613                         else if (t->type == MONO_TYPE_I8 || t->type == MONO_TYPE_I)
6614                                 opcode = OP_ATOMIC_LOAD_I8;
6615                         else if (is_ref || t->type == MONO_TYPE_U8 || t->type == MONO_TYPE_U)
6616                                 opcode = OP_ATOMIC_LOAD_U8;
6617 #else
6618                         else if (t->type == MONO_TYPE_I)
6619                                 opcode = OP_ATOMIC_LOAD_I4;
6620                         else if (is_ref || t->type == MONO_TYPE_U)
6621                                 opcode = OP_ATOMIC_LOAD_U4;
6622 #endif
6623
6624                         if (opcode) {
6625                                 if (!mono_arch_opcode_supported (opcode))
6626                                         return NULL;
6627
6628                                 MONO_INST_NEW (cfg, ins, opcode);
6629                                 ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : (is_float ? mono_alloc_freg (cfg) : mono_alloc_ireg (cfg));
6630                                 ins->sreg1 = args [0]->dreg;
6631                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_ACQ;
6632                                 MONO_ADD_INS (cfg->cbb, ins);
6633
6634                                 switch (t->type) {
6635                                 case MONO_TYPE_BOOLEAN:
6636                                 case MONO_TYPE_I1:
6637                                 case MONO_TYPE_U1:
6638                                 case MONO_TYPE_I2:
6639                                 case MONO_TYPE_U2:
6640                                 case MONO_TYPE_I4:
6641                                 case MONO_TYPE_U4:
6642                                         ins->type = STACK_I4;
6643                                         break;
6644                                 case MONO_TYPE_I8:
6645                                 case MONO_TYPE_U8:
6646                                         ins->type = STACK_I8;
6647                                         break;
6648                                 case MONO_TYPE_I:
6649                                 case MONO_TYPE_U:
6650 #if SIZEOF_REGISTER == 8
6651                                         ins->type = STACK_I8;
6652 #else
6653                                         ins->type = STACK_I4;
6654 #endif
6655                                         break;
6656                                 case MONO_TYPE_R4:
6657                                         ins->type = cfg->r4_stack_type;
6658                                         break;
6659                                 case MONO_TYPE_R8:
6660                                         ins->type = STACK_R8;
6661                                         break;
6662                                 default:
6663                                         g_assert (is_ref);
6664                                         ins->type = STACK_OBJ;
6665                                         break;
6666                                 }
6667                         }
6668                 }
6669
6670                 if (!cfg->llvm_only && !strcmp (cmethod->name, "Write") && fsig->param_count == 2) {
6671                         guint32 opcode = 0;
6672                         MonoType *t = fsig->params [0];
6673                         gboolean is_ref;
6674
6675                         g_assert (t->byref);
6676                         is_ref = mini_type_is_reference (&mono_class_from_mono_type (t)->byval_arg);
6677                         if (t->type == MONO_TYPE_I1)
6678                                 opcode = OP_ATOMIC_STORE_I1;
6679                         else if (t->type == MONO_TYPE_U1 || t->type == MONO_TYPE_BOOLEAN)
6680                                 opcode = OP_ATOMIC_STORE_U1;
6681                         else if (t->type == MONO_TYPE_I2)
6682                                 opcode = OP_ATOMIC_STORE_I2;
6683                         else if (t->type == MONO_TYPE_U2)
6684                                 opcode = OP_ATOMIC_STORE_U2;
6685                         else if (t->type == MONO_TYPE_I4)
6686                                 opcode = OP_ATOMIC_STORE_I4;
6687                         else if (t->type == MONO_TYPE_U4)
6688                                 opcode = OP_ATOMIC_STORE_U4;
6689                         else if (t->type == MONO_TYPE_R4)
6690                                 opcode = OP_ATOMIC_STORE_R4;
6691                         else if (t->type == MONO_TYPE_R8)
6692                                 opcode = OP_ATOMIC_STORE_R8;
6693 #if SIZEOF_REGISTER == 8
6694                         else if (t->type == MONO_TYPE_I8 || t->type == MONO_TYPE_I)
6695                                 opcode = OP_ATOMIC_STORE_I8;
6696                         else if (is_ref || t->type == MONO_TYPE_U8 || t->type == MONO_TYPE_U)
6697                                 opcode = OP_ATOMIC_STORE_U8;
6698 #else
6699                         else if (t->type == MONO_TYPE_I)
6700                                 opcode = OP_ATOMIC_STORE_I4;
6701                         else if (is_ref || t->type == MONO_TYPE_U)
6702                                 opcode = OP_ATOMIC_STORE_U4;
6703 #endif
6704
6705                         if (opcode) {
6706                                 if (!mono_arch_opcode_supported (opcode))
6707                                         return NULL;
6708
6709                                 MONO_INST_NEW (cfg, ins, opcode);
6710                                 ins->dreg = args [0]->dreg;
6711                                 ins->sreg1 = args [1]->dreg;
6712                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_REL;
6713                                 MONO_ADD_INS (cfg->cbb, ins);
6714
6715                                 if (cfg->gen_write_barriers && is_ref)
6716                                         emit_write_barrier (cfg, args [0], args [1]);
6717                         }
6718                 }
6719
6720                 if (ins)
6721                         return ins;
6722         } else if (cmethod->klass->image == mono_defaults.corlib &&
6723                            (strcmp (cmethod->klass->name_space, "System.Diagnostics") == 0) &&
6724                            (strcmp (cmethod->klass->name, "Debugger") == 0)) {
6725                 if (!strcmp (cmethod->name, "Break") && fsig->param_count == 0) {
6726                         if (should_insert_brekpoint (cfg->method)) {
6727                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
6728                         } else {
6729                                 MONO_INST_NEW (cfg, ins, OP_NOP);
6730                                 MONO_ADD_INS (cfg->cbb, ins);
6731                         }
6732                         return ins;
6733                 }
6734         } else if (cmethod->klass->image == mono_defaults.corlib &&
6735                    (strcmp (cmethod->klass->name_space, "System") == 0) &&
6736                    (strcmp (cmethod->klass->name, "Environment") == 0)) {
6737                 if (!strcmp (cmethod->name, "get_IsRunningOnWindows") && fsig->param_count == 0) {
6738 #ifdef TARGET_WIN32
6739                         EMIT_NEW_ICONST (cfg, ins, 1);
6740 #else
6741                         EMIT_NEW_ICONST (cfg, ins, 0);
6742 #endif
6743                 }
6744         } else if (cmethod->klass->image == mono_defaults.corlib &&
6745                            (strcmp (cmethod->klass->name_space, "System.Reflection") == 0) &&
6746                            (strcmp (cmethod->klass->name, "Assembly") == 0)) {
6747                 if (cfg->llvm_only && !strcmp (cmethod->name, "GetExecutingAssembly")) {
6748                         /* No stack walks are currently available, so implement this as an intrinsic */
6749                         MonoInst *assembly_ins;
6750
6751                         EMIT_NEW_AOTCONST (cfg, assembly_ins, MONO_PATCH_INFO_IMAGE, cfg->method->klass->image);
6752                         ins = mono_emit_jit_icall (cfg, mono_get_assembly_object, &assembly_ins);
6753                         return ins;
6754                 }
6755         } else if (cmethod->klass->image == mono_defaults.corlib &&
6756                            (strcmp (cmethod->klass->name_space, "System.Reflection") == 0) &&
6757                            (strcmp (cmethod->klass->name, "MethodBase") == 0)) {
6758                 if (cfg->llvm_only && !strcmp (cmethod->name, "GetCurrentMethod")) {
6759                         /* No stack walks are currently available, so implement this as an intrinsic */
6760                         MonoInst *method_ins;
6761                         MonoMethod *declaring = cfg->method;
6762
6763                         /* This returns the declaring generic method */
6764                         if (declaring->is_inflated)
6765                                 declaring = ((MonoMethodInflated*)cfg->method)->declaring;
6766                         EMIT_NEW_AOTCONST (cfg, method_ins, MONO_PATCH_INFO_METHODCONST, declaring);
6767                         ins = mono_emit_jit_icall (cfg, mono_get_method_object, &method_ins);
6768                         cfg->no_inline = TRUE;
6769                         if (cfg->method != cfg->current_method)
6770                                 inline_failure (cfg, "MethodBase:GetCurrentMethod ()");
6771                         return ins;
6772                 }
6773         } else if (cmethod->klass == mono_defaults.math_class) {
6774                 /* 
6775                  * There is general branchless code for Min/Max, but it does not work for 
6776                  * all inputs:
6777                  * http://everything2.com/?node_id=1051618
6778                  */
6779         } else if (((!strcmp (cmethod->klass->image->assembly->aname.name, "MonoMac") ||
6780                     !strcmp (cmethod->klass->image->assembly->aname.name, "monotouch")) &&
6781                                 !strcmp (cmethod->klass->name_space, "XamCore.ObjCRuntime") &&
6782                                 !strcmp (cmethod->klass->name, "Selector")) ||
6783                            ((!strcmp (cmethod->klass->image->assembly->aname.name, "Xamarin.iOS") ||
6784                                  !strcmp (cmethod->klass->image->assembly->aname.name, "Xamarin.Mac")) &&
6785                                 !strcmp (cmethod->klass->name_space, "ObjCRuntime") &&
6786                                 !strcmp (cmethod->klass->name, "Selector"))
6787                            ) {
6788                 if ((cfg->backend->have_objc_get_selector || cfg->compile_llvm) &&
6789                         !strcmp (cmethod->name, "GetHandle") && fsig->param_count == 1 &&
6790                     (args [0]->opcode == OP_GOT_ENTRY || args [0]->opcode == OP_AOTCONST) &&
6791                     cfg->compile_aot) {
6792                         MonoInst *pi;
6793                         MonoJumpInfoToken *ji;
6794                         char *s;
6795
6796                         if (args [0]->opcode == OP_GOT_ENTRY) {
6797                                 pi = (MonoInst *)args [0]->inst_p1;
6798                                 g_assert (pi->opcode == OP_PATCH_INFO);
6799                                 g_assert (GPOINTER_TO_INT (pi->inst_p1) == MONO_PATCH_INFO_LDSTR);
6800                                 ji = (MonoJumpInfoToken *)pi->inst_p0;
6801                         } else {
6802                                 g_assert (GPOINTER_TO_INT (args [0]->inst_p1) == MONO_PATCH_INFO_LDSTR);
6803                                 ji = (MonoJumpInfoToken *)args [0]->inst_p0;
6804                         }
6805
6806                         NULLIFY_INS (args [0]);
6807
6808                         s = mono_ldstr_utf8 (ji->image, mono_metadata_token_index (ji->token), &cfg->error);
6809                         return_val_if_nok (&cfg->error, NULL);
6810
6811                         MONO_INST_NEW (cfg, ins, OP_OBJC_GET_SELECTOR);
6812                         ins->dreg = mono_alloc_ireg (cfg);
6813                         // FIXME: Leaks
6814                         ins->inst_p0 = s;
6815                         MONO_ADD_INS (cfg->cbb, ins);
6816                         return ins;
6817                 }
6818         }
6819
6820 #ifdef MONO_ARCH_SIMD_INTRINSICS
6821         if (cfg->opt & MONO_OPT_SIMD) {
6822                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
6823                 if (ins)
6824                         return ins;
6825         }
6826 #endif
6827
6828         ins = mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
6829         if (ins)
6830                 return ins;
6831
6832         if (COMPILE_LLVM (cfg)) {
6833                 ins = llvm_emit_inst_for_method (cfg, cmethod, fsig, args);
6834                 if (ins)
6835                         return ins;
6836         }
6837
6838         return mono_arch_emit_inst_for_method (cfg, cmethod, fsig, args);
6839 }
6840
6841 /*
6842  * This entry point could be used later for arbitrary method
6843  * redirection.
6844  */
6845 inline static MonoInst*
6846 mini_redirect_call (MonoCompile *cfg, MonoMethod *method,  
6847                                         MonoMethodSignature *signature, MonoInst **args, MonoInst *this_ins)
6848 {
6849         if (method->klass == mono_defaults.string_class) {
6850                 /* managed string allocation support */
6851                 if (strcmp (method->name, "InternalAllocateStr") == 0 && !(mono_profiler_events & MONO_PROFILE_ALLOCATIONS) && !(cfg->opt & MONO_OPT_SHARED)) {
6852                         MonoInst *iargs [2];
6853                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
6854                         MonoMethod *managed_alloc = NULL;
6855
6856                         g_assert (vtable); /*Should not fail since it System.String*/
6857 #ifndef MONO_CROSS_COMPILE
6858                         managed_alloc = mono_gc_get_managed_allocator (method->klass, FALSE, FALSE);
6859 #endif
6860                         if (!managed_alloc)
6861                                 return NULL;
6862                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
6863                         iargs [1] = args [0];
6864                         return mono_emit_method_call (cfg, managed_alloc, iargs, this_ins);
6865                 }
6866         }
6867         return NULL;
6868 }
6869
6870 static void
6871 mono_save_args (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **sp)
6872 {
6873         MonoInst *store, *temp;
6874         int i;
6875
6876         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
6877                 MonoType *argtype = (sig->hasthis && (i == 0)) ? type_from_stack_type (*sp) : sig->params [i - sig->hasthis];
6878
6879                 /*
6880                  * FIXME: We should use *args++ = sp [0], but that would mean the arg
6881                  * would be different than the MonoInst's used to represent arguments, and
6882                  * the ldelema implementation can't deal with that.
6883                  * Solution: When ldelema is used on an inline argument, create a var for 
6884                  * it, emit ldelema on that var, and emit the saving code below in
6885                  * inline_method () if needed.
6886                  */
6887                 temp = mono_compile_create_var (cfg, argtype, OP_LOCAL);
6888                 cfg->args [i] = temp;
6889                 /* This uses cfg->args [i] which is set by the preceeding line */
6890                 EMIT_NEW_ARGSTORE (cfg, store, i, *sp);
6891                 store->cil_code = sp [0]->cil_code;
6892                 sp++;
6893         }
6894 }
6895
6896 #define MONO_INLINE_CALLED_LIMITED_METHODS 1
6897 #define MONO_INLINE_CALLER_LIMITED_METHODS 1
6898
6899 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
6900 static gboolean
6901 check_inline_called_method_name_limit (MonoMethod *called_method)
6902 {
6903         int strncmp_result;
6904         static const char *limit = NULL;
6905         
6906         if (limit == NULL) {
6907                 const char *limit_string = g_getenv ("MONO_INLINE_CALLED_METHOD_NAME_LIMIT");
6908
6909                 if (limit_string != NULL)
6910                         limit = limit_string;
6911                 else
6912                         limit = "";
6913         }
6914
6915         if (limit [0] != '\0') {
6916                 char *called_method_name = mono_method_full_name (called_method, TRUE);
6917
6918                 strncmp_result = strncmp (called_method_name, limit, strlen (limit));
6919                 g_free (called_method_name);
6920         
6921                 //return (strncmp_result <= 0);
6922                 return (strncmp_result == 0);
6923         } else {
6924                 return TRUE;
6925         }
6926 }
6927 #endif
6928
6929 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
6930 static gboolean
6931 check_inline_caller_method_name_limit (MonoMethod *caller_method)
6932 {
6933         int strncmp_result;
6934         static const char *limit = NULL;
6935         
6936         if (limit == NULL) {
6937                 const char *limit_string = g_getenv ("MONO_INLINE_CALLER_METHOD_NAME_LIMIT");
6938                 if (limit_string != NULL) {
6939                         limit = limit_string;
6940                 } else {
6941                         limit = "";
6942                 }
6943         }
6944
6945         if (limit [0] != '\0') {
6946                 char *caller_method_name = mono_method_full_name (caller_method, TRUE);
6947
6948                 strncmp_result = strncmp (caller_method_name, limit, strlen (limit));
6949                 g_free (caller_method_name);
6950         
6951                 //return (strncmp_result <= 0);
6952                 return (strncmp_result == 0);
6953         } else {
6954                 return TRUE;
6955         }
6956 }
6957 #endif
6958
6959 static void
6960 emit_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
6961 {
6962         static double r8_0 = 0.0;
6963         static float r4_0 = 0.0;
6964         MonoInst *ins;
6965         int t;
6966
6967         rtype = mini_get_underlying_type (rtype);
6968         t = rtype->type;
6969
6970         if (rtype->byref) {
6971                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
6972         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
6973                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
6974         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
6975                 MONO_EMIT_NEW_I8CONST (cfg, dreg, 0);
6976         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
6977                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
6978                 ins->type = STACK_R4;
6979                 ins->inst_p0 = (void*)&r4_0;
6980                 ins->dreg = dreg;
6981                 MONO_ADD_INS (cfg->cbb, ins);
6982         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
6983                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
6984                 ins->type = STACK_R8;
6985                 ins->inst_p0 = (void*)&r8_0;
6986                 ins->dreg = dreg;
6987                 MONO_ADD_INS (cfg->cbb, ins);
6988         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
6989                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
6990                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
6991         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (rtype)) {
6992                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
6993         } else {
6994                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
6995         }
6996 }
6997
6998 static void
6999 emit_dummy_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
7000 {
7001         int t;
7002
7003         rtype = mini_get_underlying_type (rtype);
7004         t = rtype->type;
7005
7006         if (rtype->byref) {
7007                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_PCONST);
7008         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
7009                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_ICONST);
7010         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
7011                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_I8CONST);
7012         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
7013                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R4CONST);
7014         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
7015                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R8CONST);
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_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
7019         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (rtype)) {
7020                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
7021         } else {
7022                 emit_init_rvar (cfg, dreg, rtype);
7023         }
7024 }
7025
7026 /* If INIT is FALSE, emit dummy initialization statements to keep the IR valid */
7027 static void
7028 emit_init_local (MonoCompile *cfg, int local, MonoType *type, gboolean init)
7029 {
7030         MonoInst *var = cfg->locals [local];
7031         if (COMPILE_SOFT_FLOAT (cfg)) {
7032                 MonoInst *store;
7033                 int reg = alloc_dreg (cfg, (MonoStackType)var->type);
7034                 emit_init_rvar (cfg, reg, type);
7035                 EMIT_NEW_LOCSTORE (cfg, store, local, cfg->cbb->last_ins);
7036         } else {
7037                 if (init)
7038                         emit_init_rvar (cfg, var->dreg, type);
7039                 else
7040                         emit_dummy_init_rvar (cfg, var->dreg, type);
7041         }
7042 }
7043
7044 /*
7045  * inline_method:
7046  *
7047  *   Return the cost of inlining CMETHOD.
7048  */
7049 static int
7050 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
7051                            guchar *ip, guint real_offset, gboolean inline_always)
7052 {
7053         MonoError error;
7054         MonoInst *ins, *rvar = NULL;
7055         MonoMethodHeader *cheader;
7056         MonoBasicBlock *ebblock, *sbblock;
7057         int i, costs;
7058         MonoMethod *prev_inlined_method;
7059         MonoInst **prev_locals, **prev_args;
7060         MonoType **prev_arg_types;
7061         guint prev_real_offset;
7062         GHashTable *prev_cbb_hash;
7063         MonoBasicBlock **prev_cil_offset_to_bb;
7064         MonoBasicBlock *prev_cbb;
7065         unsigned char* prev_cil_start;
7066         guint32 prev_cil_offset_to_bb_len;
7067         MonoMethod *prev_current_method;
7068         MonoGenericContext *prev_generic_context;
7069         gboolean ret_var_set, prev_ret_var_set, prev_disable_inline, virtual_ = FALSE;
7070
7071         g_assert (cfg->exception_type == MONO_EXCEPTION_NONE);
7072
7073 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
7074         if ((! inline_always) && ! check_inline_called_method_name_limit (cmethod))
7075                 return 0;
7076 #endif
7077 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
7078         if ((! inline_always) && ! check_inline_caller_method_name_limit (cfg->method))
7079                 return 0;
7080 #endif
7081
7082         if (!fsig)
7083                 fsig = mono_method_signature (cmethod);
7084
7085         if (cfg->verbose_level > 2)
7086                 printf ("INLINE START %p %s -> %s\n", cmethod,  mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
7087
7088         if (!cmethod->inline_info) {
7089                 cfg->stat_inlineable_methods++;
7090                 cmethod->inline_info = 1;
7091         }
7092
7093         /* allocate local variables */
7094         cheader = mono_method_get_header_checked (cmethod, &error);
7095         if (!cheader) {
7096                 if (inline_always) {
7097                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
7098                         mono_error_move (&cfg->error, &error);
7099                 } else {
7100                         mono_error_cleanup (&error);
7101                 }
7102                 return 0;
7103         }
7104
7105         /*Must verify before creating locals as it can cause the JIT to assert.*/
7106         if (mono_compile_is_broken (cfg, cmethod, FALSE)) {
7107                 mono_metadata_free_mh (cheader);
7108                 return 0;
7109         }
7110
7111         /* allocate space to store the return value */
7112         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
7113                 rvar = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
7114         }
7115
7116         prev_locals = cfg->locals;
7117         cfg->locals = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, cheader->num_locals * sizeof (MonoInst*));
7118         for (i = 0; i < cheader->num_locals; ++i)
7119                 cfg->locals [i] = mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
7120
7121         /* allocate start and end blocks */
7122         /* This is needed so if the inline is aborted, we can clean up */
7123         NEW_BBLOCK (cfg, sbblock);
7124         sbblock->real_offset = real_offset;
7125
7126         NEW_BBLOCK (cfg, ebblock);
7127         ebblock->block_num = cfg->num_bblocks++;
7128         ebblock->real_offset = real_offset;
7129
7130         prev_args = cfg->args;
7131         prev_arg_types = cfg->arg_types;
7132         prev_inlined_method = cfg->inlined_method;
7133         cfg->inlined_method = cmethod;
7134         cfg->ret_var_set = FALSE;
7135         cfg->inline_depth ++;
7136         prev_real_offset = cfg->real_offset;
7137         prev_cbb_hash = cfg->cbb_hash;
7138         prev_cil_offset_to_bb = cfg->cil_offset_to_bb;
7139         prev_cil_offset_to_bb_len = cfg->cil_offset_to_bb_len;
7140         prev_cil_start = cfg->cil_start;
7141         prev_cbb = cfg->cbb;
7142         prev_current_method = cfg->current_method;
7143         prev_generic_context = cfg->generic_context;
7144         prev_ret_var_set = cfg->ret_var_set;
7145         prev_disable_inline = cfg->disable_inline;
7146
7147         if (ip && *ip == CEE_CALLVIRT && !(cmethod->flags & METHOD_ATTRIBUTE_STATIC))
7148                 virtual_ = TRUE;
7149
7150         costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, rvar, sp, real_offset, virtual_);
7151
7152         ret_var_set = cfg->ret_var_set;
7153
7154         cfg->inlined_method = prev_inlined_method;
7155         cfg->real_offset = prev_real_offset;
7156         cfg->cbb_hash = prev_cbb_hash;
7157         cfg->cil_offset_to_bb = prev_cil_offset_to_bb;
7158         cfg->cil_offset_to_bb_len = prev_cil_offset_to_bb_len;
7159         cfg->cil_start = prev_cil_start;
7160         cfg->locals = prev_locals;
7161         cfg->args = prev_args;
7162         cfg->arg_types = prev_arg_types;
7163         cfg->current_method = prev_current_method;
7164         cfg->generic_context = prev_generic_context;
7165         cfg->ret_var_set = prev_ret_var_set;
7166         cfg->disable_inline = prev_disable_inline;
7167         cfg->inline_depth --;
7168
7169         if ((costs >= 0 && costs < 60) || inline_always || (costs >= 0 && (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))) {
7170                 if (cfg->verbose_level > 2)
7171                         printf ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
7172                 
7173                 cfg->stat_inlined_methods++;
7174
7175                 /* always add some code to avoid block split failures */
7176                 MONO_INST_NEW (cfg, ins, OP_NOP);
7177                 MONO_ADD_INS (prev_cbb, ins);
7178
7179                 prev_cbb->next_bb = sbblock;
7180                 link_bblock (cfg, prev_cbb, sbblock);
7181
7182                 /* 
7183                  * Get rid of the begin and end bblocks if possible to aid local
7184                  * optimizations.
7185                  */
7186                 mono_merge_basic_blocks (cfg, prev_cbb, sbblock);
7187
7188                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] != ebblock))
7189                         mono_merge_basic_blocks (cfg, prev_cbb, prev_cbb->out_bb [0]);
7190
7191                 if ((ebblock->in_count == 1) && ebblock->in_bb [0]->out_count == 1) {
7192                         MonoBasicBlock *prev = ebblock->in_bb [0];
7193
7194                         if (prev->next_bb == ebblock) {
7195                                 mono_merge_basic_blocks (cfg, prev, ebblock);
7196                                 cfg->cbb = prev;
7197                                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] == prev)) {
7198                                         mono_merge_basic_blocks (cfg, prev_cbb, prev);
7199                                         cfg->cbb = prev_cbb;
7200                                 }
7201                         } else {
7202                                 /* There could be a bblock after 'prev', and making 'prev' the current bb could cause problems */
7203                                 cfg->cbb = ebblock;
7204                         }
7205                 } else {
7206                         /* 
7207                          * Its possible that the rvar is set in some prev bblock, but not in others.
7208                          * (#1835).
7209                          */
7210                         if (rvar) {
7211                                 MonoBasicBlock *bb;
7212
7213                                 for (i = 0; i < ebblock->in_count; ++i) {
7214                                         bb = ebblock->in_bb [i];
7215
7216                                         if (bb->last_ins && bb->last_ins->opcode == OP_NOT_REACHED) {
7217                                                 cfg->cbb = bb;
7218
7219                                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
7220                                         }
7221                                 }
7222                         }
7223
7224                         cfg->cbb = ebblock;
7225                 }
7226
7227                 if (rvar) {
7228                         /*
7229                          * If the inlined method contains only a throw, then the ret var is not 
7230                          * set, so set it to a dummy value.
7231                          */
7232                         if (!ret_var_set)
7233                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
7234
7235                         EMIT_NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
7236                         *sp++ = ins;
7237                 }
7238                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
7239                 return costs + 1;
7240         } else {
7241                 if (cfg->verbose_level > 2)
7242                         printf ("INLINE ABORTED %s (cost %d)\n", mono_method_full_name (cmethod, TRUE), costs);
7243                 cfg->exception_type = MONO_EXCEPTION_NONE;
7244
7245                 /* This gets rid of the newly added bblocks */
7246                 cfg->cbb = prev_cbb;
7247         }
7248         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
7249         return 0;
7250 }
7251
7252 /*
7253  * Some of these comments may well be out-of-date.
7254  * Design decisions: we do a single pass over the IL code (and we do bblock 
7255  * splitting/merging in the few cases when it's required: a back jump to an IL
7256  * address that was not already seen as bblock starting point).
7257  * Code is validated as we go (full verification is still better left to metadata/verify.c).
7258  * Complex operations are decomposed in simpler ones right away. We need to let the 
7259  * arch-specific code peek and poke inside this process somehow (except when the 
7260  * optimizations can take advantage of the full semantic info of coarse opcodes).
7261  * All the opcodes of the form opcode.s are 'normalized' to opcode.
7262  * MonoInst->opcode initially is the IL opcode or some simplification of that 
7263  * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific 
7264  * opcode with value bigger than OP_LAST.
7265  * At this point the IR can be handed over to an interpreter, a dumb code generator
7266  * or to the optimizing code generator that will translate it to SSA form.
7267  *
7268  * Profiling directed optimizations.
7269  * We may compile by default with few or no optimizations and instrument the code
7270  * or the user may indicate what methods to optimize the most either in a config file
7271  * or through repeated runs where the compiler applies offline the optimizations to 
7272  * each method and then decides if it was worth it.
7273  */
7274
7275 #define CHECK_TYPE(ins) if (!(ins)->type) UNVERIFIED
7276 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) UNVERIFIED
7277 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) UNVERIFIED
7278 #define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) UNVERIFIED
7279 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
7280 #define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
7281 #define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
7282 #define CHECK_TYPELOAD(klass) if (!(klass) || mono_class_has_failure (klass)) TYPE_LOAD_ERROR ((klass))
7283
7284 /* offset from br.s -> br like opcodes */
7285 #define BIG_BRANCH_OFFSET 13
7286
7287 static gboolean
7288 ip_in_bb (MonoCompile *cfg, MonoBasicBlock *bb, const guint8* ip)
7289 {
7290         MonoBasicBlock *b = cfg->cil_offset_to_bb [ip - cfg->cil_start];
7291
7292         return b == NULL || b == bb;
7293 }
7294
7295 static int
7296 get_basic_blocks (MonoCompile *cfg, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
7297 {
7298         unsigned char *ip = start;
7299         unsigned char *target;
7300         int i;
7301         guint cli_addr;
7302         MonoBasicBlock *bblock;
7303         const MonoOpcode *opcode;
7304
7305         while (ip < end) {
7306                 cli_addr = ip - start;
7307                 i = mono_opcode_value ((const guint8 **)&ip, end);
7308                 if (i < 0)
7309                         UNVERIFIED;
7310                 opcode = &mono_opcodes [i];
7311                 switch (opcode->argument) {
7312                 case MonoInlineNone:
7313                         ip++; 
7314                         break;
7315                 case MonoInlineString:
7316                 case MonoInlineType:
7317                 case MonoInlineField:
7318                 case MonoInlineMethod:
7319                 case MonoInlineTok:
7320                 case MonoInlineSig:
7321                 case MonoShortInlineR:
7322                 case MonoInlineI:
7323                         ip += 5;
7324                         break;
7325                 case MonoInlineVar:
7326                         ip += 3;
7327                         break;
7328                 case MonoShortInlineVar:
7329                 case MonoShortInlineI:
7330                         ip += 2;
7331                         break;
7332                 case MonoShortInlineBrTarget:
7333                         target = start + cli_addr + 2 + (signed char)ip [1];
7334                         GET_BBLOCK (cfg, bblock, target);
7335                         ip += 2;
7336                         if (ip < end)
7337                                 GET_BBLOCK (cfg, bblock, ip);
7338                         break;
7339                 case MonoInlineBrTarget:
7340                         target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
7341                         GET_BBLOCK (cfg, bblock, target);
7342                         ip += 5;
7343                         if (ip < end)
7344                                 GET_BBLOCK (cfg, bblock, ip);
7345                         break;
7346                 case MonoInlineSwitch: {
7347                         guint32 n = read32 (ip + 1);
7348                         guint32 j;
7349                         ip += 5;
7350                         cli_addr += 5 + 4 * n;
7351                         target = start + cli_addr;
7352                         GET_BBLOCK (cfg, bblock, target);
7353                         
7354                         for (j = 0; j < n; ++j) {
7355                                 target = start + cli_addr + (gint32)read32 (ip);
7356                                 GET_BBLOCK (cfg, bblock, target);
7357                                 ip += 4;
7358                         }
7359                         break;
7360                 }
7361                 case MonoInlineR:
7362                 case MonoInlineI8:
7363                         ip += 9;
7364                         break;
7365                 default:
7366                         g_assert_not_reached ();
7367                 }
7368
7369                 if (i == CEE_THROW) {
7370                         unsigned char *bb_start = ip - 1;
7371                         
7372                         /* Find the start of the bblock containing the throw */
7373                         bblock = NULL;
7374                         while ((bb_start >= start) && !bblock) {
7375                                 bblock = cfg->cil_offset_to_bb [(bb_start) - start];
7376                                 bb_start --;
7377                         }
7378                         if (bblock)
7379                                 bblock->out_of_line = 1;
7380                 }
7381         }
7382         return 0;
7383 unverified:
7384 exception_exit:
7385         *pos = ip;
7386         return 1;
7387 }
7388
7389 static inline MonoMethod *
7390 mini_get_method_allow_open (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context, MonoError *error)
7391 {
7392         MonoMethod *method;
7393
7394         mono_error_init (error);
7395
7396         if (m->wrapper_type != MONO_WRAPPER_NONE) {
7397                 method = (MonoMethod *)mono_method_get_wrapper_data (m, token);
7398                 if (context) {
7399                         method = mono_class_inflate_generic_method_checked (method, context, error);
7400                 }
7401         } else {
7402                 method = mono_get_method_checked (m->klass->image, token, klass, context, error);
7403         }
7404
7405         return method;
7406 }
7407
7408 static inline MonoMethod *
7409 mini_get_method (MonoCompile *cfg, MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
7410 {
7411         MonoError error;
7412         MonoMethod *method = mini_get_method_allow_open (m, token, klass, context, cfg ? &cfg->error : &error);
7413
7414         if (method && cfg && !cfg->gshared && mono_class_is_open_constructed_type (&method->klass->byval_arg)) {
7415                 mono_error_set_bad_image (&cfg->error, cfg->method->klass->image, "Method with open type while not compiling gshared");
7416                 method = NULL;
7417         }
7418
7419         if (!method && !cfg)
7420                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
7421
7422         return method;
7423 }
7424
7425 static inline MonoClass*
7426 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
7427 {
7428         MonoError error;
7429         MonoClass *klass;
7430
7431         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7432                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
7433                 if (context) {
7434                         klass = mono_class_inflate_generic_class_checked (klass, context, &error);
7435                         mono_error_cleanup (&error); /* FIXME don't swallow the error */
7436                 }
7437         } else {
7438                 klass = mono_class_get_and_inflate_typespec_checked (method->klass->image, token, context, &error);
7439                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
7440         }
7441         if (klass)
7442                 mono_class_init (klass);
7443         return klass;
7444 }
7445
7446 static inline MonoMethodSignature*
7447 mini_get_signature (MonoMethod *method, guint32 token, MonoGenericContext *context, MonoError *error)
7448 {
7449         MonoMethodSignature *fsig;
7450
7451         mono_error_init (error);
7452         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7453                 fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
7454         } else {
7455                 fsig = mono_metadata_parse_signature_checked (method->klass->image, token, error);
7456                 return_val_if_nok (error, NULL);
7457         }
7458         if (context) {
7459                 fsig = mono_inflate_generic_signature(fsig, context, error);
7460         }
7461         return fsig;
7462 }
7463
7464 static MonoMethod*
7465 throw_exception (void)
7466 {
7467         static MonoMethod *method = NULL;
7468
7469         if (!method) {
7470                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
7471                 method = mono_class_get_method_from_name (secman->securitymanager, "ThrowException", 1);
7472         }
7473         g_assert (method);
7474         return method;
7475 }
7476
7477 static void
7478 emit_throw_exception (MonoCompile *cfg, MonoException *ex)
7479 {
7480         MonoMethod *thrower = throw_exception ();
7481         MonoInst *args [1];
7482
7483         EMIT_NEW_PCONST (cfg, args [0], ex);
7484         mono_emit_method_call (cfg, thrower, args, NULL);
7485 }
7486
7487 /*
7488  * Return the original method is a wrapper is specified. We can only access 
7489  * the custom attributes from the original method.
7490  */
7491 static MonoMethod*
7492 get_original_method (MonoMethod *method)
7493 {
7494         if (method->wrapper_type == MONO_WRAPPER_NONE)
7495                 return method;
7496
7497         /* native code (which is like Critical) can call any managed method XXX FIXME XXX to validate all usages */
7498         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)
7499                 return NULL;
7500
7501         /* in other cases we need to find the original method */
7502         return mono_marshal_method_from_wrapper (method);
7503 }
7504
7505 static void
7506 ensure_method_is_allowed_to_access_field (MonoCompile *cfg, MonoMethod *caller, MonoClassField *field)
7507 {
7508         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
7509         MonoException *ex = mono_security_core_clr_is_field_access_allowed (get_original_method (caller), field);
7510         if (ex)
7511                 emit_throw_exception (cfg, ex);
7512 }
7513
7514 static void
7515 ensure_method_is_allowed_to_call_method (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee)
7516 {
7517         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
7518         MonoException *ex = mono_security_core_clr_is_call_allowed (get_original_method (caller), callee);
7519         if (ex)
7520                 emit_throw_exception (cfg, ex);
7521 }
7522
7523 /*
7524  * Check that the IL instructions at ip are the array initialization
7525  * sequence and return the pointer to the data and the size.
7526  */
7527 static const char*
7528 initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, MonoClass *klass, guint32 len, int *out_size, guint32 *out_field_token)
7529 {
7530         /*
7531          * newarr[System.Int32]
7532          * dup
7533          * ldtoken field valuetype ...
7534          * call void class [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle)
7535          */
7536         if (ip [0] == CEE_DUP && ip [1] == CEE_LDTOKEN && ip [5] == 0x4 && ip [6] == CEE_CALL) {
7537                 MonoError error;
7538                 guint32 token = read32 (ip + 7);
7539                 guint32 field_token = read32 (ip + 2);
7540                 guint32 field_index = field_token & 0xffffff;
7541                 guint32 rva;
7542                 const char *data_ptr;
7543                 int size = 0;
7544                 MonoMethod *cmethod;
7545                 MonoClass *dummy_class;
7546                 MonoClassField *field = mono_field_from_token_checked (method->klass->image, field_token, &dummy_class, NULL, &error);
7547                 int dummy_align;
7548
7549                 if (!field) {
7550                         mono_error_cleanup (&error); /* FIXME don't swallow the error */
7551                         return NULL;
7552                 }
7553
7554                 *out_field_token = field_token;
7555
7556                 cmethod = mini_get_method (NULL, method, token, NULL, NULL);
7557                 if (!cmethod)
7558                         return NULL;
7559                 if (strcmp (cmethod->name, "InitializeArray") || strcmp (cmethod->klass->name, "RuntimeHelpers") || cmethod->klass->image != mono_defaults.corlib)
7560                         return NULL;
7561                 switch (mono_type_get_underlying_type (&klass->byval_arg)->type) {
7562                 case MONO_TYPE_BOOLEAN:
7563                 case MONO_TYPE_I1:
7564                 case MONO_TYPE_U1:
7565                         size = 1; break;
7566                 /* we need to swap on big endian, so punt. Should we handle R4 and R8 as well? */
7567 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
7568                 case MONO_TYPE_CHAR:
7569                 case MONO_TYPE_I2:
7570                 case MONO_TYPE_U2:
7571                         size = 2; break;
7572                 case MONO_TYPE_I4:
7573                 case MONO_TYPE_U4:
7574                 case MONO_TYPE_R4:
7575                         size = 4; break;
7576                 case MONO_TYPE_R8:
7577                 case MONO_TYPE_I8:
7578                 case MONO_TYPE_U8:
7579                         size = 8; break;
7580 #endif
7581                 default:
7582                         return NULL;
7583                 }
7584                 size *= len;
7585                 if (size > mono_type_size (field->type, &dummy_align))
7586                     return NULL;
7587                 *out_size = size;
7588                 /*g_print ("optimized in %s: size: %d, numelems: %d\n", method->name, size, newarr->inst_newa_len->inst_c0);*/
7589                 if (!image_is_dynamic (method->klass->image)) {
7590                         field_index = read32 (ip + 2) & 0xffffff;
7591                         mono_metadata_field_info (method->klass->image, field_index - 1, NULL, &rva, NULL);
7592                         data_ptr = mono_image_rva_map (method->klass->image, rva);
7593                         /*g_print ("field: 0x%08x, rva: %d, rva_ptr: %p\n", read32 (ip + 2), rva, data_ptr);*/
7594                         /* for aot code we do the lookup on load */
7595                         if (aot && data_ptr)
7596                                 return (const char *)GUINT_TO_POINTER (rva);
7597                 } else {
7598                         /*FIXME is it possible to AOT a SRE assembly not meant to be saved? */ 
7599                         g_assert (!aot);
7600                         data_ptr = mono_field_get_data (field);
7601                 }
7602                 return data_ptr;
7603         }
7604         return NULL;
7605 }
7606
7607 static void
7608 set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsigned char *ip)
7609 {
7610         MonoError error;
7611         char *method_fname = mono_method_full_name (method, TRUE);
7612         char *method_code;
7613         MonoMethodHeader *header = mono_method_get_header_checked (method, &error);
7614
7615         if (!header) {
7616                 method_code = g_strdup_printf ("could not parse method body due to %s", mono_error_get_message (&error));
7617                 mono_error_cleanup (&error);
7618         } else if (header->code_size == 0)
7619                 method_code = g_strdup ("method body is empty.");
7620         else
7621                 method_code = mono_disasm_code_one (NULL, method, ip, NULL);
7622         mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("Invalid IL code in %s: %s\n", method_fname, method_code));
7623         g_free (method_fname);
7624         g_free (method_code);
7625         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
7626 }
7627
7628 static void
7629 emit_stloc_ir (MonoCompile *cfg, MonoInst **sp, MonoMethodHeader *header, int n)
7630 {
7631         MonoInst *ins;
7632         guint32 opcode = mono_type_to_regmove (cfg, header->locals [n]);
7633         if ((opcode == OP_MOVE) && cfg->cbb->last_ins == sp [0]  &&
7634                         ((sp [0]->opcode == OP_ICONST) || (sp [0]->opcode == OP_I8CONST))) {
7635                 /* Optimize reg-reg moves away */
7636                 /* 
7637                  * Can't optimize other opcodes, since sp[0] might point to
7638                  * the last ins of a decomposed opcode.
7639                  */
7640                 sp [0]->dreg = (cfg)->locals [n]->dreg;
7641         } else {
7642                 EMIT_NEW_LOCSTORE (cfg, ins, n, *sp);
7643         }
7644 }
7645
7646 /*
7647  * ldloca inhibits many optimizations so try to get rid of it in common
7648  * cases.
7649  */
7650 static inline unsigned char *
7651 emit_optimized_ldloca_ir (MonoCompile *cfg, unsigned char *ip, unsigned char *end, int size)
7652 {
7653         int local, token;
7654         MonoClass *klass;
7655         MonoType *type;
7656
7657         if (size == 1) {
7658                 local = ip [1];
7659                 ip += 2;
7660         } else {
7661                 local = read16 (ip + 2);
7662                 ip += 4;
7663         }
7664         
7665         if (ip + 6 < end && (ip [0] == CEE_PREFIX1) && (ip [1] == CEE_INITOBJ) && ip_in_bb (cfg, cfg->cbb, ip + 1)) {
7666                 /* From the INITOBJ case */
7667                 token = read32 (ip + 2);
7668                 klass = mini_get_class (cfg->current_method, token, cfg->generic_context);
7669                 CHECK_TYPELOAD (klass);
7670                 type = mini_get_underlying_type (&klass->byval_arg);
7671                 emit_init_local (cfg, local, type, TRUE);
7672                 return ip + 6;
7673         }
7674  exception_exit:
7675         return NULL;
7676 }
7677
7678 static MonoInst*
7679 emit_llvmonly_virtual_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used, MonoInst **sp)
7680 {
7681         MonoInst *icall_args [16];
7682         MonoInst *call_target, *ins, *vtable_ins;
7683         int arg_reg, this_reg, vtable_reg;
7684         gboolean is_iface = cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE;
7685         gboolean is_gsharedvt = cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig);
7686         gboolean variant_iface = FALSE;
7687         guint32 slot;
7688         int offset;
7689
7690         /*
7691          * In llvm-only mode, vtables contain function descriptors instead of
7692          * method addresses/trampolines.
7693          */
7694         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
7695
7696         if (is_iface)
7697                 slot = mono_method_get_imt_slot (cmethod);
7698         else
7699                 slot = mono_method_get_vtable_index (cmethod);
7700
7701         this_reg = sp [0]->dreg;
7702
7703         if (is_iface && mono_class_has_variant_generic_params (cmethod->klass))
7704                 variant_iface = TRUE;
7705
7706         if (!fsig->generic_param_count && !is_iface && !is_gsharedvt) {
7707                 /*
7708                  * The simplest case, a normal virtual call.
7709                  */
7710                 int slot_reg = alloc_preg (cfg);
7711                 int addr_reg = alloc_preg (cfg);
7712                 int arg_reg = alloc_preg (cfg);
7713                 MonoBasicBlock *non_null_bb;
7714
7715                 vtable_reg = alloc_preg (cfg);
7716                 EMIT_NEW_LOAD_MEMBASE (cfg, vtable_ins, OP_LOAD_MEMBASE, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
7717                 offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) + (slot * SIZEOF_VOID_P);
7718
7719                 /* Load the vtable slot, which contains a function descriptor. */
7720                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, slot_reg, vtable_reg, offset);
7721
7722                 NEW_BBLOCK (cfg, non_null_bb);
7723
7724                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, slot_reg, 0);
7725                 cfg->cbb->last_ins->flags |= MONO_INST_LIKELY;
7726                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, non_null_bb);
7727
7728                 /* Slow path */
7729                 // FIXME: Make the wrapper use the preserveall cconv
7730                 // FIXME: Use one icall per slot for small slot numbers ?
7731                 icall_args [0] = vtable_ins;
7732                 EMIT_NEW_ICONST (cfg, icall_args [1], slot);
7733                 /* Make the icall return the vtable slot value to save some code space */
7734                 ins = mono_emit_jit_icall (cfg, mono_init_vtable_slot, icall_args);
7735                 ins->dreg = slot_reg;
7736                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, non_null_bb);
7737
7738                 /* Fastpath */
7739                 MONO_START_BB (cfg, non_null_bb);
7740                 /* Load the address + arg from the vtable slot */
7741                 EMIT_NEW_LOAD_MEMBASE (cfg, call_target, OP_LOAD_MEMBASE, addr_reg, slot_reg, 0);
7742                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, arg_reg, slot_reg, SIZEOF_VOID_P);
7743
7744                 return emit_extra_arg_calli (cfg, fsig, sp, arg_reg, call_target);
7745         }
7746
7747         if (!fsig->generic_param_count && is_iface && !variant_iface && !is_gsharedvt) {
7748                 /*
7749                  * A simple interface call
7750                  *
7751                  * We make a call through an imt slot to obtain the function descriptor we need to call.
7752                  * The imt slot contains a function descriptor for a runtime function + arg.
7753                  */
7754                 int slot_reg = alloc_preg (cfg);
7755                 int addr_reg = alloc_preg (cfg);
7756                 int arg_reg = alloc_preg (cfg);
7757                 MonoInst *thunk_addr_ins, *thunk_arg_ins, *ftndesc_ins;
7758
7759                 vtable_reg = alloc_preg (cfg);
7760                 EMIT_NEW_LOAD_MEMBASE (cfg, vtable_ins, OP_LOAD_MEMBASE, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
7761                 offset = ((gint32)slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
7762
7763                 /*
7764                  * The slot is already initialized when the vtable is created so there is no need
7765                  * to check it here.
7766                  */
7767
7768                 /* Load the imt slot, which contains a function descriptor. */
7769                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, slot_reg, vtable_reg, offset);
7770
7771                 /* Load the address + arg of the imt thunk from the imt slot */
7772                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_addr_ins, OP_LOAD_MEMBASE, addr_reg, slot_reg, 0);
7773                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_arg_ins, OP_LOAD_MEMBASE, arg_reg, slot_reg, SIZEOF_VOID_P);
7774                 /*
7775                  * IMT thunks in llvm-only mode are C functions which take an info argument
7776                  * plus the imt method and return the ftndesc to call.
7777                  */
7778                 icall_args [0] = thunk_arg_ins;
7779                 icall_args [1] = emit_get_rgctx_method (cfg, context_used,
7780                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD);
7781                 ftndesc_ins = mono_emit_calli (cfg, helper_sig_llvmonly_imt_thunk, icall_args, thunk_addr_ins, NULL, NULL);
7782
7783                 return emit_llvmonly_calli (cfg, fsig, sp, ftndesc_ins);
7784         }
7785
7786         if ((fsig->generic_param_count || variant_iface) && !is_gsharedvt) {
7787                 /*
7788                  * This is similar to the interface case, the vtable slot points to an imt thunk which is
7789                  * dynamically extended as more instantiations are discovered.
7790                  * This handles generic virtual methods both on classes and interfaces.
7791                  */
7792                 int slot_reg = alloc_preg (cfg);
7793                 int addr_reg = alloc_preg (cfg);
7794                 int arg_reg = alloc_preg (cfg);
7795                 int ftndesc_reg = alloc_preg (cfg);
7796                 MonoInst *thunk_addr_ins, *thunk_arg_ins, *ftndesc_ins;
7797                 MonoBasicBlock *slowpath_bb, *end_bb;
7798
7799                 NEW_BBLOCK (cfg, slowpath_bb);
7800                 NEW_BBLOCK (cfg, end_bb);
7801
7802                 vtable_reg = alloc_preg (cfg);
7803                 EMIT_NEW_LOAD_MEMBASE (cfg, vtable_ins, OP_LOAD_MEMBASE, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
7804                 if (is_iface)
7805                         offset = ((gint32)slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
7806                 else
7807                         offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) + (slot * SIZEOF_VOID_P);
7808
7809                 /* Load the slot, which contains a function descriptor. */
7810                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, slot_reg, vtable_reg, offset);
7811
7812                 /* These slots are not initialized, so fall back to the slow path until they are initialized */
7813                 /* That happens when mono_method_add_generic_virtual_invocation () creates an IMT thunk */
7814                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, slot_reg, 0);
7815                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, slowpath_bb);
7816
7817                 /* Fastpath */
7818                 /* Same as with iface calls */
7819                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_addr_ins, OP_LOAD_MEMBASE, addr_reg, slot_reg, 0);
7820                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_arg_ins, OP_LOAD_MEMBASE, arg_reg, slot_reg, SIZEOF_VOID_P);
7821                 icall_args [0] = thunk_arg_ins;
7822                 icall_args [1] = emit_get_rgctx_method (cfg, context_used,
7823                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD);
7824                 ftndesc_ins = mono_emit_calli (cfg, helper_sig_llvmonly_imt_thunk, icall_args, thunk_addr_ins, NULL, NULL);
7825                 ftndesc_ins->dreg = ftndesc_reg;
7826                 /*
7827                  * Unlike normal iface calls, these imt thunks can return NULL, i.e. when they are passed an instantiation
7828                  * they don't know about yet. Fall back to the slowpath in that case.
7829                  */
7830                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, ftndesc_reg, 0);
7831                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, slowpath_bb);
7832
7833                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
7834
7835                 /* Slowpath */
7836                 MONO_START_BB (cfg, slowpath_bb);
7837                 icall_args [0] = vtable_ins;
7838                 EMIT_NEW_ICONST (cfg, icall_args [1], slot);
7839                 icall_args [2] = emit_get_rgctx_method (cfg, context_used,
7840                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD);
7841                 if (is_iface)
7842                         ftndesc_ins = mono_emit_jit_icall (cfg, mono_resolve_generic_virtual_iface_call, icall_args);
7843                 else
7844                         ftndesc_ins = mono_emit_jit_icall (cfg, mono_resolve_generic_virtual_call, icall_args);
7845                 ftndesc_ins->dreg = ftndesc_reg;
7846                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
7847
7848                 /* Common case */
7849                 MONO_START_BB (cfg, end_bb);
7850                 return emit_llvmonly_calli (cfg, fsig, sp, ftndesc_ins);
7851         }
7852
7853         /*
7854          * Non-optimized cases
7855          */
7856         icall_args [0] = sp [0];
7857         EMIT_NEW_ICONST (cfg, icall_args [1], slot);
7858
7859         icall_args [2] = emit_get_rgctx_method (cfg, context_used,
7860                                                                                         cmethod, MONO_RGCTX_INFO_METHOD);
7861
7862         arg_reg = alloc_preg (cfg);
7863         MONO_EMIT_NEW_PCONST (cfg, arg_reg, NULL);
7864         EMIT_NEW_VARLOADA_VREG (cfg, icall_args [3], arg_reg, &mono_defaults.int_class->byval_arg);
7865
7866         g_assert (is_gsharedvt);
7867         if (is_iface)
7868                 call_target = mono_emit_jit_icall (cfg, mono_resolve_iface_call_gsharedvt, icall_args);
7869         else
7870                 call_target = mono_emit_jit_icall (cfg, mono_resolve_vcall_gsharedvt, icall_args);
7871
7872         /*
7873          * Pass the extra argument even if the callee doesn't receive it, most
7874          * calling conventions allow this.
7875          */
7876         return emit_extra_arg_calli (cfg, fsig, sp, arg_reg, call_target);
7877 }
7878
7879 static gboolean
7880 is_exception_class (MonoClass *klass)
7881 {
7882         while (klass) {
7883                 if (klass == mono_defaults.exception_class)
7884                         return TRUE;
7885                 klass = klass->parent;
7886         }
7887         return FALSE;
7888 }
7889
7890 /*
7891  * is_jit_optimizer_disabled:
7892  *
7893  *   Determine whenever M's assembly has a DebuggableAttribute with the
7894  * IsJITOptimizerDisabled flag set.
7895  */
7896 static gboolean
7897 is_jit_optimizer_disabled (MonoMethod *m)
7898 {
7899         MonoError error;
7900         MonoAssembly *ass = m->klass->image->assembly;
7901         MonoCustomAttrInfo* attrs;
7902         MonoClass *klass;
7903         int i;
7904         gboolean val = FALSE;
7905
7906         g_assert (ass);
7907         if (ass->jit_optimizer_disabled_inited)
7908                 return ass->jit_optimizer_disabled;
7909
7910         klass = mono_class_try_get_debuggable_attribute_class ();
7911
7912         if (!klass) {
7913                 /* Linked away */
7914                 ass->jit_optimizer_disabled = FALSE;
7915                 mono_memory_barrier ();
7916                 ass->jit_optimizer_disabled_inited = TRUE;
7917                 return FALSE;
7918         }
7919
7920         attrs = mono_custom_attrs_from_assembly_checked (ass, &error);
7921         mono_error_cleanup (&error); /* FIXME don't swallow the error */
7922         if (attrs) {
7923                 for (i = 0; i < attrs->num_attrs; ++i) {
7924                         MonoCustomAttrEntry *attr = &attrs->attrs [i];
7925                         const gchar *p;
7926                         MonoMethodSignature *sig;
7927
7928                         if (!attr->ctor || attr->ctor->klass != klass)
7929                                 continue;
7930                         /* Decode the attribute. See reflection.c */
7931                         p = (const char*)attr->data;
7932                         g_assert (read16 (p) == 0x0001);
7933                         p += 2;
7934
7935                         // FIXME: Support named parameters
7936                         sig = mono_method_signature (attr->ctor);
7937                         if (sig->param_count != 2 || sig->params [0]->type != MONO_TYPE_BOOLEAN || sig->params [1]->type != MONO_TYPE_BOOLEAN)
7938                                 continue;
7939                         /* Two boolean arguments */
7940                         p ++;
7941                         val = *p;
7942                 }
7943                 mono_custom_attrs_free (attrs);
7944         }
7945
7946         ass->jit_optimizer_disabled = val;
7947         mono_memory_barrier ();
7948         ass->jit_optimizer_disabled_inited = TRUE;
7949
7950         return val;
7951 }
7952
7953 static gboolean
7954 is_supported_tail_call (MonoCompile *cfg, MonoMethod *method, MonoMethod *cmethod, MonoMethodSignature *fsig, int call_opcode)
7955 {
7956         gboolean supported_tail_call;
7957         int i;
7958
7959         supported_tail_call = mono_arch_tail_call_supported (cfg, mono_method_signature (method), mono_method_signature (cmethod));
7960
7961         for (i = 0; i < fsig->param_count; ++i) {
7962                 if (fsig->params [i]->byref || fsig->params [i]->type == MONO_TYPE_PTR || fsig->params [i]->type == MONO_TYPE_FNPTR)
7963                         /* These can point to the current method's stack */
7964                         supported_tail_call = FALSE;
7965         }
7966         if (fsig->hasthis && cmethod->klass->valuetype)
7967                 /* this might point to the current method's stack */
7968                 supported_tail_call = FALSE;
7969         if (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
7970                 supported_tail_call = FALSE;
7971         if (cfg->method->save_lmf)
7972                 supported_tail_call = FALSE;
7973         if (cmethod->wrapper_type && cmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD)
7974                 supported_tail_call = FALSE;
7975         if (call_opcode != CEE_CALL)
7976                 supported_tail_call = FALSE;
7977
7978         /* Debugging support */
7979 #if 0
7980         if (supported_tail_call) {
7981                 if (!mono_debug_count ())
7982                         supported_tail_call = FALSE;
7983         }
7984 #endif
7985
7986         return supported_tail_call;
7987 }
7988
7989 /*
7990  * handle_ctor_call:
7991  *
7992  *   Handle calls made to ctors from NEWOBJ opcodes.
7993  */
7994 static void
7995 handle_ctor_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used,
7996                                   MonoInst **sp, guint8 *ip, int *inline_costs)
7997 {
7998         MonoInst *vtable_arg = NULL, *callvirt_this_arg = NULL, *ins;
7999
8000         if (cmethod->klass->valuetype && mono_class_generic_sharing_enabled (cmethod->klass) &&
8001                                         mono_method_is_generic_sharable (cmethod, TRUE)) {
8002                 if (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst) {
8003                         mono_class_vtable (cfg->domain, cmethod->klass);
8004                         CHECK_TYPELOAD (cmethod->klass);
8005
8006                         vtable_arg = emit_get_rgctx_method (cfg, context_used,
8007                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
8008                 } else {
8009                         if (context_used) {
8010                                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
8011                                                                                                    cmethod->klass, MONO_RGCTX_INFO_VTABLE);
8012                         } else {
8013                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
8014
8015                                 CHECK_TYPELOAD (cmethod->klass);
8016                                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
8017                         }
8018                 }
8019         }
8020
8021         /* Avoid virtual calls to ctors if possible */
8022         if (mono_class_is_marshalbyref (cmethod->klass))
8023                 callvirt_this_arg = sp [0];
8024
8025         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_ctor (cfg, cmethod, fsig, sp))) {
8026                 g_assert (MONO_TYPE_IS_VOID (fsig->ret));
8027                 CHECK_CFG_EXCEPTION;
8028         } else if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used && !vtable_arg &&
8029                            mono_method_check_inlining (cfg, cmethod) &&
8030                            !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE)) {
8031                 int costs;
8032
8033                 if ((costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, FALSE))) {
8034                         cfg->real_offset += 5;
8035
8036                         *inline_costs += costs - 5;
8037                 } else {
8038                         INLINE_FAILURE ("inline failure");
8039                         // FIXME-VT: Clean this up
8040                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))
8041                                 GSHAREDVT_FAILURE(*ip);
8042                         mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, callvirt_this_arg, NULL, NULL);
8043                 }
8044         } else if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
8045                 MonoInst *addr;
8046
8047                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE);
8048
8049                 if (cfg->llvm_only) {
8050                         // FIXME: Avoid initializing vtable_arg
8051                         emit_llvmonly_calli (cfg, fsig, sp, addr);
8052                 } else {
8053                         mono_emit_calli (cfg, fsig, sp, addr, NULL, vtable_arg);
8054                 }
8055         } else if (context_used &&
8056                            ((!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
8057                                  !mono_class_generic_sharing_enabled (cmethod->klass)) || cfg->gsharedvt)) {
8058                 MonoInst *cmethod_addr;
8059
8060                 /* Generic calls made out of gsharedvt methods cannot be patched, so use an indirect call */
8061
8062                 if (cfg->llvm_only) {
8063                         MonoInst *addr = emit_get_rgctx_method (cfg, context_used, cmethod,
8064                                                                                                         MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
8065                         emit_llvmonly_calli (cfg, fsig, sp, addr);
8066                 } else {
8067                         cmethod_addr = emit_get_rgctx_method (cfg, context_used,
8068                                                                                                   cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
8069
8070                         mono_emit_calli (cfg, fsig, sp, cmethod_addr, NULL, vtable_arg);
8071                 }
8072         } else {
8073                 INLINE_FAILURE ("ctor call");
8074                 ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp,
8075                                                                                   callvirt_this_arg, NULL, vtable_arg);
8076         }
8077  exception_exit:
8078         return;
8079 }
8080
8081 static void
8082 emit_setret (MonoCompile *cfg, MonoInst *val)
8083 {
8084         MonoType *ret_type = mini_get_underlying_type (mono_method_signature (cfg->method)->ret);
8085         MonoInst *ins;
8086
8087         if (mini_type_to_stind (cfg, ret_type) == CEE_STOBJ) {
8088                 MonoInst *ret_addr;
8089
8090                 if (!cfg->vret_addr) {
8091                         EMIT_NEW_VARSTORE (cfg, ins, cfg->ret, ret_type, val);
8092                 } else {
8093                         EMIT_NEW_RETLOADA (cfg, ret_addr);
8094
8095                         EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STOREV_MEMBASE, ret_addr->dreg, 0, val->dreg);
8096                         ins->klass = mono_class_from_mono_type (ret_type);
8097                 }
8098         } else {
8099 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
8100                 if (COMPILE_SOFT_FLOAT (cfg) && !ret_type->byref && ret_type->type == MONO_TYPE_R4) {
8101                         MonoInst *iargs [1];
8102                         MonoInst *conv;
8103
8104                         iargs [0] = val;
8105                         conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
8106                         mono_arch_emit_setret (cfg, cfg->method, conv);
8107                 } else {
8108                         mono_arch_emit_setret (cfg, cfg->method, val);
8109                 }
8110 #else
8111                 mono_arch_emit_setret (cfg, cfg->method, val);
8112 #endif
8113         }
8114 }
8115
8116 /*
8117  * mono_method_to_ir:
8118  *
8119  *   Translate the .net IL into linear IR.
8120  */
8121 int
8122 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
8123                    MonoInst *return_var, MonoInst **inline_args, 
8124                    guint inline_offset, gboolean is_virtual_call)
8125 {
8126         MonoError error;
8127         MonoInst *ins, **sp, **stack_start;
8128         MonoBasicBlock *tblock = NULL, *init_localsbb = NULL;
8129         MonoSimpleBasicBlock *bb = NULL, *original_bb = NULL;
8130         MonoMethod *cmethod, *method_definition;
8131         MonoInst **arg_array;
8132         MonoMethodHeader *header;
8133         MonoImage *image;
8134         guint32 token, ins_flag;
8135         MonoClass *klass;
8136         MonoClass *constrained_class = NULL;
8137         unsigned char *ip, *end, *target, *err_pos;
8138         MonoMethodSignature *sig;
8139         MonoGenericContext *generic_context = NULL;
8140         MonoGenericContainer *generic_container = NULL;
8141         MonoType **param_types;
8142         int i, n, start_new_bblock, dreg;
8143         int num_calls = 0, inline_costs = 0;
8144         int breakpoint_id = 0;
8145         guint num_args;
8146         GSList *class_inits = NULL;
8147         gboolean dont_verify, dont_verify_stloc, readonly = FALSE;
8148         int context_used;
8149         gboolean init_locals, seq_points, skip_dead_blocks;
8150         gboolean sym_seq_points = FALSE;
8151         MonoDebugMethodInfo *minfo;
8152         MonoBitSet *seq_point_locs = NULL;
8153         MonoBitSet *seq_point_set_locs = NULL;
8154
8155         cfg->disable_inline = is_jit_optimizer_disabled (method);
8156
8157         /* serialization and xdomain stuff may need access to private fields and methods */
8158         dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
8159         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE;
8160         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH;
8161         dont_verify |= method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; /* bug #77896 */
8162         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP;
8163         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP_INVOKE;
8164
8165         /* still some type unsafety issues in marshal wrappers... (unknown is PtrToStructure) */
8166         dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE;
8167         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_UNKNOWN;
8168         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED;
8169         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_STELEMREF;
8170
8171         image = method->klass->image;
8172         header = mono_method_get_header_checked (method, &cfg->error);
8173         if (!header) {
8174                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
8175                 goto exception_exit;
8176         }
8177         generic_container = mono_method_get_generic_container (method);
8178         sig = mono_method_signature (method);
8179         num_args = sig->hasthis + sig->param_count;
8180         ip = (unsigned char*)header->code;
8181         cfg->cil_start = ip;
8182         end = ip + header->code_size;
8183         cfg->stat_cil_code_size += header->code_size;
8184
8185         seq_points = cfg->gen_seq_points && cfg->method == method;
8186
8187         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
8188                 /* We could hit a seq point before attaching to the JIT (#8338) */
8189                 seq_points = FALSE;
8190         }
8191
8192         if (cfg->gen_sdb_seq_points && cfg->method == method) {
8193                 minfo = mono_debug_lookup_method (method);
8194                 if (minfo) {
8195                         MonoSymSeqPoint *sps;
8196                         int i, n_il_offsets;
8197
8198                         mono_debug_get_seq_points (minfo, NULL, NULL, NULL, &sps, &n_il_offsets);
8199                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
8200                         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);
8201                         sym_seq_points = TRUE;
8202                         for (i = 0; i < n_il_offsets; ++i) {
8203                                 if (sps [i].il_offset < header->code_size)
8204                                         mono_bitset_set_fast (seq_point_locs, sps [i].il_offset);
8205                         }
8206                         g_free (sps);
8207                 } else if (!method->wrapper_type && !method->dynamic && mono_debug_image_has_debug_info (method->klass->image)) {
8208                         /* Methods without line number info like auto-generated property accessors */
8209                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
8210                         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);
8211                         sym_seq_points = TRUE;
8212                 }
8213         }
8214
8215         /* 
8216          * Methods without init_locals set could cause asserts in various passes
8217          * (#497220). To work around this, we emit dummy initialization opcodes
8218          * (OP_DUMMY_ICONST etc.) which generate no code. These are only supported
8219          * on some platforms.
8220          */
8221         if ((cfg->opt & MONO_OPT_UNSAFE) && cfg->backend->have_dummy_init)
8222                 init_locals = header->init_locals;
8223         else
8224                 init_locals = TRUE;
8225
8226         method_definition = method;
8227         while (method_definition->is_inflated) {
8228                 MonoMethodInflated *imethod = (MonoMethodInflated *) method_definition;
8229                 method_definition = imethod->declaring;
8230         }
8231
8232         /* SkipVerification is not allowed if core-clr is enabled */
8233         if (!dont_verify && mini_assembly_can_skip_verification (cfg->domain, method)) {
8234                 dont_verify = TRUE;
8235                 dont_verify_stloc = TRUE;
8236         }
8237
8238         if (sig->is_inflated)
8239                 generic_context = mono_method_get_context (method);
8240         else if (generic_container)
8241                 generic_context = &generic_container->context;
8242         cfg->generic_context = generic_context;
8243
8244         if (!cfg->gshared)
8245                 g_assert (!sig->has_type_parameters);
8246
8247         if (sig->generic_param_count && method->wrapper_type == MONO_WRAPPER_NONE) {
8248                 g_assert (method->is_inflated);
8249                 g_assert (mono_method_get_context (method)->method_inst);
8250         }
8251         if (method->is_inflated && mono_method_get_context (method)->method_inst)
8252                 g_assert (sig->generic_param_count);
8253
8254         if (cfg->method == method) {
8255                 cfg->real_offset = 0;
8256         } else {
8257                 cfg->real_offset = inline_offset;
8258         }
8259
8260         cfg->cil_offset_to_bb = (MonoBasicBlock **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoBasicBlock*) * header->code_size);
8261         cfg->cil_offset_to_bb_len = header->code_size;
8262
8263         cfg->current_method = method;
8264
8265         if (cfg->verbose_level > 2)
8266                 printf ("method to IR %s\n", mono_method_full_name (method, TRUE));
8267
8268         param_types = (MonoType **)mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * num_args);
8269         if (sig->hasthis)
8270                 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
8271         for (n = 0; n < sig->param_count; ++n)
8272                 param_types [n + sig->hasthis] = sig->params [n];
8273         cfg->arg_types = param_types;
8274
8275         cfg->dont_inline = g_list_prepend (cfg->dont_inline, method);
8276         if (cfg->method == method) {
8277
8278                 if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
8279                         cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
8280
8281                 /* ENTRY BLOCK */
8282                 NEW_BBLOCK (cfg, start_bblock);
8283                 cfg->bb_entry = start_bblock;
8284                 start_bblock->cil_code = NULL;
8285                 start_bblock->cil_length = 0;
8286
8287                 /* EXIT BLOCK */
8288                 NEW_BBLOCK (cfg, end_bblock);
8289                 cfg->bb_exit = end_bblock;
8290                 end_bblock->cil_code = NULL;
8291                 end_bblock->cil_length = 0;
8292                 end_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
8293                 g_assert (cfg->num_bblocks == 2);
8294
8295                 arg_array = cfg->args;
8296
8297                 if (header->num_clauses) {
8298                         cfg->spvars = g_hash_table_new (NULL, NULL);
8299                         cfg->exvars = g_hash_table_new (NULL, NULL);
8300                 }
8301                 /* handle exception clauses */
8302                 for (i = 0; i < header->num_clauses; ++i) {
8303                         MonoBasicBlock *try_bb;
8304                         MonoExceptionClause *clause = &header->clauses [i];
8305                         GET_BBLOCK (cfg, try_bb, ip + clause->try_offset);
8306
8307                         try_bb->real_offset = clause->try_offset;
8308                         try_bb->try_start = TRUE;
8309                         try_bb->region = ((i + 1) << 8) | clause->flags;
8310                         GET_BBLOCK (cfg, tblock, ip + clause->handler_offset);
8311                         tblock->real_offset = clause->handler_offset;
8312                         tblock->flags |= BB_EXCEPTION_HANDLER;
8313
8314                         /*
8315                          * Linking the try block with the EH block hinders inlining as we won't be able to 
8316                          * merge the bblocks from inlining and produce an artificial hole for no good reason.
8317                          */
8318                         if (COMPILE_LLVM (cfg))
8319                                 link_bblock (cfg, try_bb, tblock);
8320
8321                         if (*(ip + clause->handler_offset) == CEE_POP)
8322                                 tblock->flags |= BB_EXCEPTION_DEAD_OBJ;
8323
8324                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
8325                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER ||
8326                             clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
8327                                 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
8328                                 MONO_ADD_INS (tblock, ins);
8329
8330                                 if (seq_points && clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY && clause->flags != MONO_EXCEPTION_CLAUSE_FILTER) {
8331                                         /* finally clauses already have a seq point */
8332                                         /* seq points for filter clauses are emitted below */
8333                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
8334                                         MONO_ADD_INS (tblock, ins);
8335                                 }
8336
8337                                 /* todo: is a fault block unsafe to optimize? */
8338                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
8339                                         tblock->flags |= BB_EXCEPTION_UNSAFE;
8340                         }
8341
8342                         /*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);
8343                           while (p < end) {
8344                           printf ("%s", mono_disasm_code_one (NULL, method, p, &p));
8345                           }*/
8346                         /* catch and filter blocks get the exception object on the stack */
8347                         if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
8348                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
8349
8350                                 /* mostly like handle_stack_args (), but just sets the input args */
8351                                 /* printf ("handling clause at IL_%04x\n", clause->handler_offset); */
8352                                 tblock->in_scount = 1;
8353                                 tblock->in_stack = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
8354                                 tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
8355
8356                                 cfg->cbb = tblock;
8357
8358 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
8359                                 /* The EH code passes in the exception in a register to both JITted and LLVM compiled code */
8360                                 if (!cfg->compile_llvm) {
8361                                         MONO_INST_NEW (cfg, ins, OP_GET_EX_OBJ);
8362                                         ins->dreg = tblock->in_stack [0]->dreg;
8363                                         MONO_ADD_INS (tblock, ins);
8364                                 }
8365 #else
8366                                 MonoInst *dummy_use;
8367
8368                                 /* 
8369                                  * Add a dummy use for the exvar so its liveness info will be
8370                                  * correct.
8371                                  */
8372                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, tblock->in_stack [0]);
8373 #endif
8374
8375                                 if (seq_points && clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
8376                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
8377                                         MONO_ADD_INS (tblock, ins);
8378                                 }
8379                                 
8380                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
8381                                         GET_BBLOCK (cfg, tblock, ip + clause->data.filter_offset);
8382                                         tblock->flags |= BB_EXCEPTION_HANDLER;
8383                                         tblock->real_offset = clause->data.filter_offset;
8384                                         tblock->in_scount = 1;
8385                                         tblock->in_stack = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
8386                                         /* The filter block shares the exvar with the handler block */
8387                                         tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
8388                                         MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
8389                                         MONO_ADD_INS (tblock, ins);
8390                                 }
8391                         }
8392
8393                         if (clause->flags != MONO_EXCEPTION_CLAUSE_FILTER &&
8394                                         clause->data.catch_class &&
8395                                         cfg->gshared &&
8396                                         mono_class_check_context_used (clause->data.catch_class)) {
8397                                 /*
8398                                  * In shared generic code with catch
8399                                  * clauses containing type variables
8400                                  * the exception handling code has to
8401                                  * be able to get to the rgctx.
8402                                  * Therefore we have to make sure that
8403                                  * the vtable/mrgctx argument (for
8404                                  * static or generic methods) or the
8405                                  * "this" argument (for non-static
8406                                  * methods) are live.
8407                                  */
8408                                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
8409                                                 mini_method_get_context (method)->method_inst ||
8410                                                 method->klass->valuetype) {
8411                                         mono_get_vtable_var (cfg);
8412                                 } else {
8413                                         MonoInst *dummy_use;
8414
8415                                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, arg_array [0]);
8416                                 }
8417                         }
8418                 }
8419         } else {
8420                 arg_array = (MonoInst **) alloca (sizeof (MonoInst *) * num_args);
8421                 cfg->cbb = start_bblock;
8422                 cfg->args = arg_array;
8423                 mono_save_args (cfg, sig, inline_args);
8424         }
8425
8426         /* FIRST CODE BLOCK */
8427         NEW_BBLOCK (cfg, tblock);
8428         tblock->cil_code = ip;
8429         cfg->cbb = tblock;
8430         cfg->ip = ip;
8431
8432         ADD_BBLOCK (cfg, tblock);
8433
8434         if (cfg->method == method) {
8435                 breakpoint_id = mono_debugger_method_has_breakpoint (method);
8436                 if (breakpoint_id) {
8437                         MONO_INST_NEW (cfg, ins, OP_BREAK);
8438                         MONO_ADD_INS (cfg->cbb, ins);
8439                 }
8440         }
8441
8442         /* we use a separate basic block for the initialization code */
8443         NEW_BBLOCK (cfg, init_localsbb);
8444         cfg->bb_init = init_localsbb;
8445         init_localsbb->real_offset = cfg->real_offset;
8446         start_bblock->next_bb = init_localsbb;
8447         init_localsbb->next_bb = cfg->cbb;
8448         link_bblock (cfg, start_bblock, init_localsbb);
8449         link_bblock (cfg, init_localsbb, cfg->cbb);
8450                 
8451         cfg->cbb = init_localsbb;
8452
8453         if (cfg->gsharedvt && cfg->method == method) {
8454                 MonoGSharedVtMethodInfo *info;
8455                 MonoInst *var, *locals_var;
8456                 int dreg;
8457
8458                 info = (MonoGSharedVtMethodInfo *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoGSharedVtMethodInfo));
8459                 info->method = cfg->method;
8460                 info->count_entries = 16;
8461                 info->entries = (MonoRuntimeGenericContextInfoTemplate *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
8462                 cfg->gsharedvt_info = info;
8463
8464                 var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8465                 /* prevent it from being register allocated */
8466                 //var->flags |= MONO_INST_VOLATILE;
8467                 cfg->gsharedvt_info_var = var;
8468
8469                 ins = emit_get_rgctx_gsharedvt_method (cfg, mini_method_check_context_used (cfg, method), method, info);
8470                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, var->dreg, ins->dreg);
8471
8472                 /* Allocate locals */
8473                 locals_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8474                 /* prevent it from being register allocated */
8475                 //locals_var->flags |= MONO_INST_VOLATILE;
8476                 cfg->gsharedvt_locals_var = locals_var;
8477
8478                 dreg = alloc_ireg (cfg);
8479                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, dreg, var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, locals_size));
8480
8481                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
8482                 ins->dreg = locals_var->dreg;
8483                 ins->sreg1 = dreg;
8484                 MONO_ADD_INS (cfg->cbb, ins);
8485                 cfg->gsharedvt_locals_var_ins = ins;
8486                 
8487                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
8488                 /*
8489                 if (init_locals)
8490                         ins->flags |= MONO_INST_INIT;
8491                 */
8492         }
8493
8494         if (mono_security_core_clr_enabled ()) {
8495                 /* check if this is native code, e.g. an icall or a p/invoke */
8496                 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
8497                         MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
8498                         if (wrapped) {
8499                                 gboolean pinvk = (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL);
8500                                 gboolean icall = (wrapped->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL);
8501
8502                                 /* if this ia a native call then it can only be JITted from platform code */
8503                                 if ((icall || pinvk) && method->klass && method->klass->image) {
8504                                         if (!mono_security_core_clr_is_platform_image (method->klass->image)) {
8505                                                 MonoException *ex = icall ? mono_get_exception_security () : 
8506                                                         mono_get_exception_method_access ();
8507                                                 emit_throw_exception (cfg, ex);
8508                                         }
8509                                 }
8510                         }
8511                 }
8512         }
8513
8514         CHECK_CFG_EXCEPTION;
8515
8516         if (header->code_size == 0)
8517                 UNVERIFIED;
8518
8519         if (get_basic_blocks (cfg, header, cfg->real_offset, ip, end, &err_pos)) {
8520                 ip = err_pos;
8521                 UNVERIFIED;
8522         }
8523
8524         if (cfg->method == method)
8525                 mono_debug_init_method (cfg, cfg->cbb, breakpoint_id);
8526
8527         for (n = 0; n < header->num_locals; ++n) {
8528                 if (header->locals [n]->type == MONO_TYPE_VOID && !header->locals [n]->byref)
8529                         UNVERIFIED;
8530         }
8531         class_inits = NULL;
8532
8533         /* We force the vtable variable here for all shared methods
8534            for the possibility that they might show up in a stack
8535            trace where their exact instantiation is needed. */
8536         if (cfg->gshared && method == cfg->method) {
8537                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
8538                                 mini_method_get_context (method)->method_inst ||
8539                                 method->klass->valuetype) {
8540                         mono_get_vtable_var (cfg);
8541                 } else {
8542                         /* FIXME: Is there a better way to do this?
8543                            We need the variable live for the duration
8544                            of the whole method. */
8545                         cfg->args [0]->flags |= MONO_INST_VOLATILE;
8546                 }
8547         }
8548
8549         /* add a check for this != NULL to inlined methods */
8550         if (is_virtual_call) {
8551                 MonoInst *arg_ins;
8552
8553                 NEW_ARGLOAD (cfg, arg_ins, 0);
8554                 MONO_ADD_INS (cfg->cbb, arg_ins);
8555                 MONO_EMIT_NEW_CHECK_THIS (cfg, arg_ins->dreg);
8556         }
8557
8558         skip_dead_blocks = !dont_verify;
8559         if (skip_dead_blocks) {
8560                 original_bb = bb = mono_basic_block_split (method, &cfg->error, header);
8561                 CHECK_CFG_ERROR;
8562                 g_assert (bb);
8563         }
8564
8565         /* we use a spare stack slot in SWITCH and NEWOBJ and others */
8566         stack_start = sp = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
8567
8568         ins_flag = 0;
8569         start_new_bblock = 0;
8570         while (ip < end) {
8571                 if (cfg->method == method)
8572                         cfg->real_offset = ip - header->code;
8573                 else
8574                         cfg->real_offset = inline_offset;
8575                 cfg->ip = ip;
8576
8577                 context_used = 0;
8578
8579                 if (start_new_bblock) {
8580                         cfg->cbb->cil_length = ip - cfg->cbb->cil_code;
8581                         if (start_new_bblock == 2) {
8582                                 g_assert (ip == tblock->cil_code);
8583                         } else {
8584                                 GET_BBLOCK (cfg, tblock, ip);
8585                         }
8586                         cfg->cbb->next_bb = tblock;
8587                         cfg->cbb = tblock;
8588                         start_new_bblock = 0;
8589                         for (i = 0; i < cfg->cbb->in_scount; ++i) {
8590                                 if (cfg->verbose_level > 3)
8591                                         printf ("loading %d from temp %d\n", i, (int)cfg->cbb->in_stack [i]->inst_c0);
8592                                 EMIT_NEW_TEMPLOAD (cfg, ins, cfg->cbb->in_stack [i]->inst_c0);
8593                                 *sp++ = ins;
8594                         }
8595                         if (class_inits)
8596                                 g_slist_free (class_inits);
8597                         class_inits = NULL;
8598                 } else {
8599                         if ((tblock = cfg->cil_offset_to_bb [ip - cfg->cil_start]) && (tblock != cfg->cbb)) {
8600                                 link_bblock (cfg, cfg->cbb, tblock);
8601                                 if (sp != stack_start) {
8602                                         handle_stack_args (cfg, stack_start, sp - stack_start);
8603                                         sp = stack_start;
8604                                         CHECK_UNVERIFIABLE (cfg);
8605                                 }
8606                                 cfg->cbb->next_bb = tblock;
8607                                 cfg->cbb = tblock;
8608                                 for (i = 0; i < cfg->cbb->in_scount; ++i) {
8609                                         if (cfg->verbose_level > 3)
8610                                                 printf ("loading %d from temp %d\n", i, (int)cfg->cbb->in_stack [i]->inst_c0);
8611                                         EMIT_NEW_TEMPLOAD (cfg, ins, cfg->cbb->in_stack [i]->inst_c0);
8612                                         *sp++ = ins;
8613                                 }
8614                                 g_slist_free (class_inits);
8615                                 class_inits = NULL;
8616                         }
8617                 }
8618
8619                 if (skip_dead_blocks) {
8620                         int ip_offset = ip - header->code;
8621
8622                         if (ip_offset == bb->end)
8623                                 bb = bb->next;
8624
8625                         if (bb->dead) {
8626                                 int op_size = mono_opcode_size (ip, end);
8627                                 g_assert (op_size > 0); /*The BB formation pass must catch all bad ops*/
8628
8629                                 if (cfg->verbose_level > 3) printf ("SKIPPING DEAD OP at %x\n", ip_offset);
8630
8631                                 if (ip_offset + op_size == bb->end) {
8632                                         MONO_INST_NEW (cfg, ins, OP_NOP);
8633                                         MONO_ADD_INS (cfg->cbb, ins);
8634                                         start_new_bblock = 1;
8635                                 }
8636
8637                                 ip += op_size;
8638                                 continue;
8639                         }
8640                 }
8641                 /*
8642                  * Sequence points are points where the debugger can place a breakpoint.
8643                  * Currently, we generate these automatically at points where the IL
8644                  * stack is empty.
8645                  */
8646                 if (seq_points && ((!sym_seq_points && (sp == stack_start)) || (sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code)))) {
8647                         /*
8648                          * Make methods interruptable at the beginning, and at the targets of
8649                          * backward branches.
8650                          * Also, do this at the start of every bblock in methods with clauses too,
8651                          * to be able to handle instructions with inprecise control flow like
8652                          * throw/endfinally.
8653                          * Backward branches are handled at the end of method-to-ir ().
8654                          */
8655                         gboolean intr_loc = ip == header->code || (!cfg->cbb->last_ins && cfg->header->num_clauses);
8656                         gboolean sym_seq_point = sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code);
8657
8658                         /* Avoid sequence points on empty IL like .volatile */
8659                         // FIXME: Enable this
8660                         //if (!(cfg->cbb->last_ins && cfg->cbb->last_ins->opcode == OP_SEQ_POINT)) {
8661                         NEW_SEQ_POINT (cfg, ins, ip - header->code, intr_loc);
8662                         if ((sp != stack_start) && !sym_seq_point)
8663                                 ins->flags |= MONO_INST_NONEMPTY_STACK;
8664                         MONO_ADD_INS (cfg->cbb, ins);
8665
8666                         if (sym_seq_points)
8667                                 mono_bitset_set_fast (seq_point_set_locs, ip - header->code);
8668                 }
8669
8670                 cfg->cbb->real_offset = cfg->real_offset;
8671
8672                 if ((cfg->method == method) && cfg->coverage_info) {
8673                         guint32 cil_offset = ip - header->code;
8674                         cfg->coverage_info->data [cil_offset].cil_code = ip;
8675
8676                         /* TODO: Use an increment here */
8677 #if defined(TARGET_X86)
8678                         MONO_INST_NEW (cfg, ins, OP_STORE_MEM_IMM);
8679                         ins->inst_p0 = &(cfg->coverage_info->data [cil_offset].count);
8680                         ins->inst_imm = 1;
8681                         MONO_ADD_INS (cfg->cbb, ins);
8682 #else
8683                         EMIT_NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
8684                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, ins->dreg, 0, 1);
8685 #endif
8686                 }
8687
8688                 if (cfg->verbose_level > 3)
8689                         printf ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
8690
8691                 switch (*ip) {
8692                 case CEE_NOP:
8693                         if (seq_points && !sym_seq_points && sp != stack_start) {
8694                                 /*
8695                                  * The C# compiler uses these nops to notify the JIT that it should
8696                                  * insert seq points.
8697                                  */
8698                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, FALSE);
8699                                 MONO_ADD_INS (cfg->cbb, ins);
8700                         }
8701                         if (cfg->keep_cil_nops)
8702                                 MONO_INST_NEW (cfg, ins, OP_HARD_NOP);
8703                         else
8704                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8705                         ip++;
8706                         MONO_ADD_INS (cfg->cbb, ins);
8707                         break;
8708                 case CEE_BREAK:
8709                         if (should_insert_brekpoint (cfg->method)) {
8710                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
8711                         } else {
8712                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8713                         }
8714                         ip++;
8715                         MONO_ADD_INS (cfg->cbb, ins);
8716                         break;
8717                 case CEE_LDARG_0:
8718                 case CEE_LDARG_1:
8719                 case CEE_LDARG_2:
8720                 case CEE_LDARG_3:
8721                         CHECK_STACK_OVF (1);
8722                         n = (*ip)-CEE_LDARG_0;
8723                         CHECK_ARG (n);
8724                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8725                         ip++;
8726                         *sp++ = ins;
8727                         break;
8728                 case CEE_LDLOC_0:
8729                 case CEE_LDLOC_1:
8730                 case CEE_LDLOC_2:
8731                 case CEE_LDLOC_3:
8732                         CHECK_STACK_OVF (1);
8733                         n = (*ip)-CEE_LDLOC_0;
8734                         CHECK_LOCAL (n);
8735                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8736                         ip++;
8737                         *sp++ = ins;
8738                         break;
8739                 case CEE_STLOC_0:
8740                 case CEE_STLOC_1:
8741                 case CEE_STLOC_2:
8742                 case CEE_STLOC_3: {
8743                         CHECK_STACK (1);
8744                         n = (*ip)-CEE_STLOC_0;
8745                         CHECK_LOCAL (n);
8746                         --sp;
8747                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
8748                                 UNVERIFIED;
8749                         emit_stloc_ir (cfg, sp, header, n);
8750                         ++ip;
8751                         inline_costs += 1;
8752                         break;
8753                         }
8754                 case CEE_LDARG_S:
8755                         CHECK_OPSIZE (2);
8756                         CHECK_STACK_OVF (1);
8757                         n = ip [1];
8758                         CHECK_ARG (n);
8759                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8760                         *sp++ = ins;
8761                         ip += 2;
8762                         break;
8763                 case CEE_LDARGA_S:
8764                         CHECK_OPSIZE (2);
8765                         CHECK_STACK_OVF (1);
8766                         n = ip [1];
8767                         CHECK_ARG (n);
8768                         NEW_ARGLOADA (cfg, ins, n);
8769                         MONO_ADD_INS (cfg->cbb, ins);
8770                         *sp++ = ins;
8771                         ip += 2;
8772                         break;
8773                 case CEE_STARG_S:
8774                         CHECK_OPSIZE (2);
8775                         CHECK_STACK (1);
8776                         --sp;
8777                         n = ip [1];
8778                         CHECK_ARG (n);
8779                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [ip [1]], *sp))
8780                                 UNVERIFIED;
8781                         EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
8782                         ip += 2;
8783                         break;
8784                 case CEE_LDLOC_S:
8785                         CHECK_OPSIZE (2);
8786                         CHECK_STACK_OVF (1);
8787                         n = ip [1];
8788                         CHECK_LOCAL (n);
8789                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8790                         *sp++ = ins;
8791                         ip += 2;
8792                         break;
8793                 case CEE_LDLOCA_S: {
8794                         unsigned char *tmp_ip;
8795                         CHECK_OPSIZE (2);
8796                         CHECK_STACK_OVF (1);
8797                         CHECK_LOCAL (ip [1]);
8798
8799                         if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 1))) {
8800                                 ip = tmp_ip;
8801                                 inline_costs += 1;
8802                                 break;
8803                         }
8804
8805                         EMIT_NEW_LOCLOADA (cfg, ins, ip [1]);
8806                         *sp++ = ins;
8807                         ip += 2;
8808                         break;
8809                 }
8810                 case CEE_STLOC_S:
8811                         CHECK_OPSIZE (2);
8812                         CHECK_STACK (1);
8813                         --sp;
8814                         CHECK_LOCAL (ip [1]);
8815                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [ip [1]], *sp))
8816                                 UNVERIFIED;
8817                         emit_stloc_ir (cfg, sp, header, ip [1]);
8818                         ip += 2;
8819                         inline_costs += 1;
8820                         break;
8821                 case CEE_LDNULL:
8822                         CHECK_STACK_OVF (1);
8823                         EMIT_NEW_PCONST (cfg, ins, NULL);
8824                         ins->type = STACK_OBJ;
8825                         ++ip;
8826                         *sp++ = ins;
8827                         break;
8828                 case CEE_LDC_I4_M1:
8829                         CHECK_STACK_OVF (1);
8830                         EMIT_NEW_ICONST (cfg, ins, -1);
8831                         ++ip;
8832                         *sp++ = ins;
8833                         break;
8834                 case CEE_LDC_I4_0:
8835                 case CEE_LDC_I4_1:
8836                 case CEE_LDC_I4_2:
8837                 case CEE_LDC_I4_3:
8838                 case CEE_LDC_I4_4:
8839                 case CEE_LDC_I4_5:
8840                 case CEE_LDC_I4_6:
8841                 case CEE_LDC_I4_7:
8842                 case CEE_LDC_I4_8:
8843                         CHECK_STACK_OVF (1);
8844                         EMIT_NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
8845                         ++ip;
8846                         *sp++ = ins;
8847                         break;
8848                 case CEE_LDC_I4_S:
8849                         CHECK_OPSIZE (2);
8850                         CHECK_STACK_OVF (1);
8851                         ++ip;
8852                         EMIT_NEW_ICONST (cfg, ins, *((signed char*)ip));
8853                         ++ip;
8854                         *sp++ = ins;
8855                         break;
8856                 case CEE_LDC_I4:
8857                         CHECK_OPSIZE (5);
8858                         CHECK_STACK_OVF (1);
8859                         EMIT_NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
8860                         ip += 5;
8861                         *sp++ = ins;
8862                         break;
8863                 case CEE_LDC_I8:
8864                         CHECK_OPSIZE (9);
8865                         CHECK_STACK_OVF (1);
8866                         MONO_INST_NEW (cfg, ins, OP_I8CONST);
8867                         ins->type = STACK_I8;
8868                         ins->dreg = alloc_dreg (cfg, STACK_I8);
8869                         ++ip;
8870                         ins->inst_l = (gint64)read64 (ip);
8871                         MONO_ADD_INS (cfg->cbb, ins);
8872                         ip += 8;
8873                         *sp++ = ins;
8874                         break;
8875                 case CEE_LDC_R4: {
8876                         float *f;
8877                         gboolean use_aotconst = FALSE;
8878
8879 #ifdef TARGET_POWERPC
8880                         /* FIXME: Clean this up */
8881                         if (cfg->compile_aot)
8882                                 use_aotconst = TRUE;
8883 #endif
8884
8885                         /* FIXME: we should really allocate this only late in the compilation process */
8886                         f = (float *)mono_domain_alloc (cfg->domain, sizeof (float));
8887                         CHECK_OPSIZE (5);
8888                         CHECK_STACK_OVF (1);
8889
8890                         if (use_aotconst) {
8891                                 MonoInst *cons;
8892                                 int dreg;
8893
8894                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R4, f);
8895
8896                                 dreg = alloc_freg (cfg);
8897                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR4_MEMBASE, dreg, cons->dreg, 0);
8898                                 ins->type = cfg->r4_stack_type;
8899                         } else {
8900                                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
8901                                 ins->type = cfg->r4_stack_type;
8902                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8903                                 ins->inst_p0 = f;
8904                                 MONO_ADD_INS (cfg->cbb, ins);
8905                         }
8906                         ++ip;
8907                         readr4 (ip, f);
8908                         ip += 4;
8909                         *sp++ = ins;                    
8910                         break;
8911                 }
8912                 case CEE_LDC_R8: {
8913                         double *d;
8914                         gboolean use_aotconst = FALSE;
8915
8916 #ifdef TARGET_POWERPC
8917                         /* FIXME: Clean this up */
8918                         if (cfg->compile_aot)
8919                                 use_aotconst = TRUE;
8920 #endif
8921
8922                         /* FIXME: we should really allocate this only late in the compilation process */
8923                         d = (double *)mono_domain_alloc (cfg->domain, sizeof (double));
8924                         CHECK_OPSIZE (9);
8925                         CHECK_STACK_OVF (1);
8926
8927                         if (use_aotconst) {
8928                                 MonoInst *cons;
8929                                 int dreg;
8930
8931                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R8, d);
8932
8933                                 dreg = alloc_freg (cfg);
8934                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR8_MEMBASE, dreg, cons->dreg, 0);
8935                                 ins->type = STACK_R8;
8936                         } else {
8937                                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
8938                                 ins->type = STACK_R8;
8939                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8940                                 ins->inst_p0 = d;
8941                                 MONO_ADD_INS (cfg->cbb, ins);
8942                         }
8943                         ++ip;
8944                         readr8 (ip, d);
8945                         ip += 8;
8946                         *sp++ = ins;
8947                         break;
8948                 }
8949                 case CEE_DUP: {
8950                         MonoInst *temp, *store;
8951                         CHECK_STACK (1);
8952                         CHECK_STACK_OVF (1);
8953                         sp--;
8954                         ins = *sp;
8955
8956                         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
8957                         EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
8958
8959                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8960                         *sp++ = ins;
8961
8962                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8963                         *sp++ = ins;
8964
8965                         ++ip;
8966                         inline_costs += 2;
8967                         break;
8968                 }
8969                 case CEE_POP:
8970                         CHECK_STACK (1);
8971                         ip++;
8972                         --sp;
8973
8974 #ifdef TARGET_X86
8975                         if (sp [0]->type == STACK_R8)
8976                                 /* we need to pop the value from the x86 FP stack */
8977                                 MONO_EMIT_NEW_UNALU (cfg, OP_X86_FPOP, -1, sp [0]->dreg);
8978 #endif
8979                         break;
8980                 case CEE_JMP: {
8981                         MonoCallInst *call;
8982                         MonoMethodSignature *fsig;
8983                         int i, n;
8984
8985                         INLINE_FAILURE ("jmp");
8986                         GSHAREDVT_FAILURE (*ip);
8987
8988                         CHECK_OPSIZE (5);
8989                         if (stack_start != sp)
8990                                 UNVERIFIED;
8991                         token = read32 (ip + 1);
8992                         /* FIXME: check the signature matches */
8993                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
8994                         CHECK_CFG_ERROR;
8995  
8996                         if (cfg->gshared && mono_method_check_context_used (cmethod))
8997                                 GENERIC_SHARING_FAILURE (CEE_JMP);
8998
8999                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
9000
9001                         fsig = mono_method_signature (cmethod);
9002                         n = fsig->param_count + fsig->hasthis;
9003                         if (cfg->llvm_only) {
9004                                 MonoInst **args;
9005
9006                                 args = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
9007                                 for (i = 0; i < n; ++i)
9008                                         EMIT_NEW_ARGLOAD (cfg, args [i], i);
9009                                 ins = mono_emit_method_call_full (cfg, cmethod, fsig, TRUE, args, NULL, NULL, NULL);
9010                                 /*
9011                                  * The code in mono-basic-block.c treats the rest of the code as dead, but we
9012                                  * have to emit a normal return since llvm expects it.
9013                                  */
9014                                 if (cfg->ret)
9015                                         emit_setret (cfg, ins);
9016                                 MONO_INST_NEW (cfg, ins, OP_BR);
9017                                 ins->inst_target_bb = end_bblock;
9018                                 MONO_ADD_INS (cfg->cbb, ins);
9019                                 link_bblock (cfg, cfg->cbb, end_bblock);
9020                                 ip += 5;
9021                                 break;
9022                         } else if (cfg->backend->have_op_tail_call) {
9023                                 /* Handle tail calls similarly to calls */
9024                                 DISABLE_AOT (cfg);
9025
9026                                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
9027                                 call->method = cmethod;
9028                                 call->tail_call = TRUE;
9029                                 call->signature = mono_method_signature (cmethod);
9030                                 call->args = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
9031                                 call->inst.inst_p0 = cmethod;
9032                                 for (i = 0; i < n; ++i)
9033                                         EMIT_NEW_ARGLOAD (cfg, call->args [i], i);
9034
9035                                 mono_arch_emit_call (cfg, call);
9036                                 cfg->param_area = MAX(cfg->param_area, call->stack_usage);
9037                                 MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
9038                         } else {
9039                                 for (i = 0; i < num_args; ++i)
9040                                         /* Prevent arguments from being optimized away */
9041                                         arg_array [i]->flags |= MONO_INST_VOLATILE;
9042
9043                                 MONO_INST_NEW_CALL (cfg, call, OP_JMP);
9044                                 ins = (MonoInst*)call;
9045                                 ins->inst_p0 = cmethod;
9046                                 MONO_ADD_INS (cfg->cbb, ins);
9047                         }
9048
9049                         ip += 5;
9050                         start_new_bblock = 1;
9051                         break;
9052                 }
9053                 case CEE_CALLI: {
9054                         MonoInst *addr;
9055                         MonoMethodSignature *fsig;
9056
9057                         CHECK_OPSIZE (5);
9058                         token = read32 (ip + 1);
9059
9060                         ins = NULL;
9061
9062                         //GSHAREDVT_FAILURE (*ip);
9063                         cmethod = NULL;
9064                         CHECK_STACK (1);
9065                         --sp;
9066                         addr = *sp;
9067                         fsig = mini_get_signature (method, token, generic_context, &cfg->error);
9068                         CHECK_CFG_ERROR;
9069
9070                         if (method->dynamic && fsig->pinvoke) {
9071                                 MonoInst *args [3];
9072
9073                                 /*
9074                                  * This is a call through a function pointer using a pinvoke
9075                                  * signature. Have to create a wrapper and call that instead.
9076                                  * FIXME: This is very slow, need to create a wrapper at JIT time
9077                                  * instead based on the signature.
9078                                  */
9079                                 EMIT_NEW_IMAGECONST (cfg, args [0], method->klass->image);
9080                                 EMIT_NEW_PCONST (cfg, args [1], fsig);
9081                                 args [2] = addr;
9082                                 addr = mono_emit_jit_icall (cfg, mono_get_native_calli_wrapper, args);
9083                         }
9084
9085                         n = fsig->param_count + fsig->hasthis;
9086
9087                         CHECK_STACK (n);
9088
9089                         //g_assert (!virtual_ || fsig->hasthis);
9090
9091                         sp -= n;
9092
9093                         inline_costs += 10 * num_calls++;
9094
9095                         /*
9096                          * Making generic calls out of gsharedvt methods.
9097                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
9098                          * patching gshared method addresses into a gsharedvt method.
9099                          */
9100                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
9101                                 /*
9102                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
9103                                  */
9104                                 MonoInst *callee = addr;
9105
9106                                 if (method->wrapper_type != MONO_WRAPPER_DELEGATE_INVOKE)
9107                                         /* Not tested */
9108                                         GSHAREDVT_FAILURE (*ip);
9109
9110                                 if (cfg->llvm_only)
9111                                         // FIXME:
9112                                         GSHAREDVT_FAILURE (*ip);
9113
9114                                 addr = emit_get_rgctx_sig (cfg, context_used,
9115                                                                                           fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
9116                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
9117                                 goto calli_end;
9118                         }
9119
9120                         /* Prevent inlining of methods with indirect calls */
9121                         INLINE_FAILURE ("indirect call");
9122
9123                         if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST || addr->opcode == OP_GOT_ENTRY) {
9124                                 MonoJumpInfoType info_type;
9125                                 gpointer info_data;
9126
9127                                 /*
9128                                  * Instead of emitting an indirect call, emit a direct call
9129                                  * with the contents of the aotconst as the patch info.
9130                                  */
9131                                 if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST) {
9132                                         info_type = (MonoJumpInfoType)addr->inst_c1;
9133                                         info_data = addr->inst_p0;
9134                                 } else {
9135                                         info_type = (MonoJumpInfoType)addr->inst_right->inst_c1;
9136                                         info_data = addr->inst_right->inst_left;
9137                                 }
9138
9139                                 if (info_type == MONO_PATCH_INFO_ICALL_ADDR) {
9140                                         ins = (MonoInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_ICALL_ADDR_CALL, info_data, fsig, sp);
9141                                         NULLIFY_INS (addr);
9142                                         goto calli_end;
9143                                 } else if (info_type == MONO_PATCH_INFO_JIT_ICALL_ADDR) {
9144                                         ins = (MonoInst*)mono_emit_abs_call (cfg, info_type, info_data, fsig, sp);
9145                                         NULLIFY_INS (addr);
9146                                         goto calli_end;
9147                                 }
9148                         }
9149                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9150
9151                         calli_end:
9152
9153                         /* End of call, INS should contain the result of the call, if any */
9154
9155                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9156                                 g_assert (ins);
9157                                 *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
9158                         }
9159
9160                         CHECK_CFG_EXCEPTION;
9161
9162                         ip += 5;
9163                         ins_flag = 0;
9164                         constrained_class = NULL;
9165                         break;
9166                 }
9167                 case CEE_CALL:
9168                 case CEE_CALLVIRT: {
9169                         MonoInst *addr = NULL;
9170                         MonoMethodSignature *fsig = NULL;
9171                         int array_rank = 0;
9172                         int virtual_ = *ip == CEE_CALLVIRT;
9173                         gboolean pass_imt_from_rgctx = FALSE;
9174                         MonoInst *imt_arg = NULL;
9175                         MonoInst *keep_this_alive = NULL;
9176                         gboolean pass_vtable = FALSE;
9177                         gboolean pass_mrgctx = FALSE;
9178                         MonoInst *vtable_arg = NULL;
9179                         gboolean check_this = FALSE;
9180                         gboolean supported_tail_call = FALSE;
9181                         gboolean tail_call = FALSE;
9182                         gboolean need_seq_point = FALSE;
9183                         guint32 call_opcode = *ip;
9184                         gboolean emit_widen = TRUE;
9185                         gboolean push_res = TRUE;
9186                         gboolean skip_ret = FALSE;
9187                         gboolean delegate_invoke = FALSE;
9188                         gboolean direct_icall = FALSE;
9189                         gboolean constrained_partial_call = FALSE;
9190                         MonoMethod *cil_method;
9191
9192                         CHECK_OPSIZE (5);
9193                         token = read32 (ip + 1);
9194
9195                         ins = NULL;
9196
9197                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
9198                         CHECK_CFG_ERROR;
9199
9200                         cil_method = cmethod;
9201                                 
9202                         if (constrained_class) {
9203                                 if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->gshared) {
9204                                         if (!mini_is_gsharedvt_klass (constrained_class)) {
9205                                                 g_assert (!cmethod->klass->valuetype);
9206                                                 if (!mini_type_is_reference (&constrained_class->byval_arg))
9207                                                         constrained_partial_call = TRUE;
9208                                         }
9209                                 }
9210
9211                                 if (method->wrapper_type != MONO_WRAPPER_NONE) {
9212                                         if (cfg->verbose_level > 2)
9213                                                 printf ("DM Constrained call to %s\n", mono_type_get_full_name (constrained_class));
9214                                         if (!((constrained_class->byval_arg.type == MONO_TYPE_VAR ||
9215                                                    constrained_class->byval_arg.type == MONO_TYPE_MVAR) &&
9216                                                   cfg->gshared)) {
9217                                                 cmethod = mono_get_method_constrained_with_method (image, cil_method, constrained_class, generic_context, &cfg->error);
9218                                                 CHECK_CFG_ERROR;
9219                                         }
9220                                 } else {
9221                                         if (cfg->verbose_level > 2)
9222                                                 printf ("Constrained call to %s\n", mono_type_get_full_name (constrained_class));
9223
9224                                         if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->gshared) {
9225                                                 /* 
9226                                                  * This is needed since get_method_constrained can't find 
9227                                                  * the method in klass representing a type var.
9228                                                  * The type var is guaranteed to be a reference type in this
9229                                                  * case.
9230                                                  */
9231                                                 if (!mini_is_gsharedvt_klass (constrained_class))
9232                                                         g_assert (!cmethod->klass->valuetype);
9233                                         } else {
9234                                                 cmethod = mono_get_method_constrained_checked (image, token, constrained_class, generic_context, &cil_method, &cfg->error);
9235                                                 CHECK_CFG_ERROR;
9236                                         }
9237                                 }
9238                         }
9239                                         
9240                         if (!dont_verify && !cfg->skip_visibility) {
9241                                 MonoMethod *target_method = cil_method;
9242                                 if (method->is_inflated) {
9243                                         target_method = mini_get_method_allow_open (method, token, NULL, &(mono_method_get_generic_container (method_definition)->context), &cfg->error);
9244                                         CHECK_CFG_ERROR;
9245                                 }
9246                                 if (!mono_method_can_access_method (method_definition, target_method) &&
9247                                         !mono_method_can_access_method (method, cil_method))
9248                                         emit_method_access_failure (cfg, method, cil_method);
9249                         }
9250
9251                         if (mono_security_core_clr_enabled ())
9252                                 ensure_method_is_allowed_to_call_method (cfg, method, cil_method);
9253
9254                         if (!virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
9255                                 /* MS.NET seems to silently convert this to a callvirt */
9256                                 virtual_ = 1;
9257
9258                         {
9259                                 /*
9260                                  * MS.NET accepts non virtual calls to virtual final methods of transparent proxy classes and
9261                                  * converts to a callvirt.
9262                                  *
9263                                  * tests/bug-515884.il is an example of this behavior
9264                                  */
9265                                 const int test_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_STATIC;
9266                                 const int expected_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL;
9267                                 if (!virtual_ && mono_class_is_marshalbyref (cmethod->klass) && (cmethod->flags & test_flags) == expected_flags && cfg->method->wrapper_type == MONO_WRAPPER_NONE)
9268                                         virtual_ = 1;
9269                         }
9270
9271                         if (!cmethod->klass->inited)
9272                                 if (!mono_class_init (cmethod->klass))
9273                                         TYPE_LOAD_ERROR (cmethod->klass);
9274
9275                         fsig = mono_method_signature (cmethod);
9276                         if (!fsig)
9277                                 LOAD_ERROR;
9278                         if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
9279                                 mini_class_is_system_array (cmethod->klass)) {
9280                                 array_rank = cmethod->klass->rank;
9281                         } else if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && icall_is_direct_callable (cfg, cmethod)) {
9282                                 direct_icall = TRUE;
9283                         } else if (fsig->pinvoke) {
9284                                 MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
9285                                 fsig = mono_method_signature (wrapper);
9286                         } else if (constrained_class) {
9287                         } else {
9288                                 fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
9289                                 CHECK_CFG_ERROR;
9290                         }
9291
9292                         if (cfg->llvm_only && !cfg->method->wrapper_type && (!cmethod || cmethod->is_inflated))
9293                                 cfg->signatures = g_slist_prepend_mempool (cfg->mempool, cfg->signatures, fsig);
9294
9295                         /* See code below */
9296                         if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
9297                                 MonoBasicBlock *tbb;
9298
9299                                 GET_BBLOCK (cfg, tbb, ip + 5);
9300                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
9301                                         /*
9302                                          * We want to extend the try block to cover the call, but we can't do it if the
9303                                          * call is made directly since its followed by an exception check.
9304                                          */
9305                                         direct_icall = FALSE;
9306                                 }
9307                         }
9308
9309                         mono_save_token_info (cfg, image, token, cil_method);
9310
9311                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip + 5 - header->code)))
9312                                 need_seq_point = TRUE;
9313
9314                         /* Don't support calls made using type arguments for now */
9315                         /*
9316                           if (cfg->gsharedvt) {
9317                           if (mini_is_gsharedvt_signature (fsig))
9318                           GSHAREDVT_FAILURE (*ip);
9319                           }
9320                         */
9321
9322                         if (cmethod->string_ctor && method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE)
9323                                 g_assert_not_reached ();
9324
9325                         n = fsig->param_count + fsig->hasthis;
9326
9327                         if (!cfg->gshared && cmethod->klass->generic_container)
9328                                 UNVERIFIED;
9329
9330                         if (!cfg->gshared)
9331                                 g_assert (!mono_method_check_context_used (cmethod));
9332
9333                         CHECK_STACK (n);
9334
9335                         //g_assert (!virtual_ || fsig->hasthis);
9336
9337                         sp -= n;
9338
9339                         /*
9340                          * We have the `constrained.' prefix opcode.
9341                          */
9342                         if (constrained_class) {
9343                                 if (mini_is_gsharedvt_klass (constrained_class)) {
9344                                         if ((cmethod->klass != mono_defaults.object_class) && constrained_class->valuetype && cmethod->klass->valuetype) {
9345                                                 /* The 'Own method' case below */
9346                                         } else if (cmethod->klass->image != mono_defaults.corlib && !(cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !cmethod->klass->valuetype) {
9347                                                 /* 'The type parameter is instantiated as a reference type' case below. */
9348                                         } else {
9349                                                 ins = handle_constrained_gsharedvt_call (cfg, cmethod, fsig, sp, constrained_class, &emit_widen);
9350                                                 CHECK_CFG_EXCEPTION;
9351                                                 g_assert (ins);
9352                                                 goto call_end;
9353                                         }
9354                                 }
9355
9356                                 if (constrained_partial_call) {
9357                                         gboolean need_box = TRUE;
9358
9359                                         /*
9360                                          * The receiver is a valuetype, but the exact type is not known at compile time. This means the
9361                                          * called method is not known at compile time either. The called method could end up being
9362                                          * one of the methods on the parent classes (object/valuetype/enum), in which case we need
9363                                          * to box the receiver.
9364                                          * A simple solution would be to box always and make a normal virtual call, but that would
9365                                          * be bad performance wise.
9366                                          */
9367                                         if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE && cmethod->klass->generic_class) {
9368                                                 /*
9369                                                  * The parent classes implement no generic interfaces, so the called method will be a vtype method, so no boxing neccessary.
9370                                                  */
9371                                                 need_box = FALSE;
9372                                         }
9373
9374                                         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)) {
9375                                                 /* The called method is not virtual, i.e. Object:GetType (), the receiver is a vtype, has to box */
9376                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9377                                                 ins->klass = constrained_class;
9378                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9379                                                 CHECK_CFG_EXCEPTION;
9380                                         } else if (need_box) {
9381                                                 MonoInst *box_type;
9382                                                 MonoBasicBlock *is_ref_bb, *end_bb;
9383                                                 MonoInst *nonbox_call;
9384
9385                                                 /*
9386                                                  * Determine at runtime whenever the called method is defined on object/valuetype/enum, and emit a boxing call
9387                                                  * if needed.
9388                                                  * FIXME: It is possible to inline the called method in a lot of cases, i.e. for T_INT,
9389                                                  * the no-box case goes to a method in Int32, while the box case goes to a method in Enum.
9390                                                  */
9391                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
9392
9393                                                 NEW_BBLOCK (cfg, is_ref_bb);
9394                                                 NEW_BBLOCK (cfg, end_bb);
9395
9396                                                 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);
9397                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, box_type->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
9398                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
9399
9400                                                 /* Non-ref case */
9401                                                 nonbox_call = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9402
9403                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
9404
9405                                                 /* Ref case */
9406                                                 MONO_START_BB (cfg, is_ref_bb);
9407                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9408                                                 ins->klass = constrained_class;
9409                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9410                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9411
9412                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
9413
9414                                                 MONO_START_BB (cfg, end_bb);
9415                                                 cfg->cbb = end_bb;
9416
9417                                                 nonbox_call->dreg = ins->dreg;
9418                                                 goto call_end;
9419                                         } else {
9420                                                 g_assert (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE);
9421                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
9422                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9423                                                 goto call_end;
9424                                         }
9425                                 } else if (constrained_class->valuetype && (cmethod->klass == mono_defaults.object_class || cmethod->klass == mono_defaults.enum_class->parent || cmethod->klass == mono_defaults.enum_class)) {
9426                                         /*
9427                                          * The type parameter is instantiated as a valuetype,
9428                                          * but that type doesn't override the method we're
9429                                          * calling, so we need to box `this'.
9430                                          */
9431                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9432                                         ins->klass = constrained_class;
9433                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9434                                         CHECK_CFG_EXCEPTION;
9435                                 } else if (!constrained_class->valuetype) {
9436                                         int dreg = alloc_ireg_ref (cfg);
9437
9438                                         /*
9439                                          * The type parameter is instantiated as a reference
9440                                          * type.  We have a managed pointer on the stack, so
9441                                          * we need to dereference it here.
9442                                          */
9443                                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, sp [0]->dreg, 0);
9444                                         ins->type = STACK_OBJ;
9445                                         sp [0] = ins;
9446                                 } else {
9447                                         if (cmethod->klass->valuetype) {
9448                                                 /* Own method */
9449                                         } else {
9450                                                 /* Interface method */
9451                                                 int ioffset, slot;
9452
9453                                                 mono_class_setup_vtable (constrained_class);
9454                                                 CHECK_TYPELOAD (constrained_class);
9455                                                 ioffset = mono_class_interface_offset (constrained_class, cmethod->klass);
9456                                                 if (ioffset == -1)
9457                                                         TYPE_LOAD_ERROR (constrained_class);
9458                                                 slot = mono_method_get_vtable_slot (cmethod);
9459                                                 if (slot == -1)
9460                                                         TYPE_LOAD_ERROR (cmethod->klass);
9461                                                 cmethod = constrained_class->vtable [ioffset + slot];
9462
9463                                                 if (cmethod->klass == mono_defaults.enum_class) {
9464                                                         /* Enum implements some interfaces, so treat this as the first case */
9465                                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9466                                                         ins->klass = constrained_class;
9467                                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9468                                                         CHECK_CFG_EXCEPTION;
9469                                                 }
9470                                         }
9471                                         virtual_ = 0;
9472                                 }
9473                                 constrained_class = NULL;
9474                         }
9475
9476                         if (check_call_signature (cfg, fsig, sp))
9477                                 UNVERIFIED;
9478
9479                         if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (cmethod->name, "Invoke"))
9480                                 delegate_invoke = TRUE;
9481
9482                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_sharable_method (cfg, cmethod, fsig, sp))) {
9483                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9484                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
9485                                         emit_widen = FALSE;
9486                                 }
9487
9488                                 goto call_end;
9489                         }
9490
9491                         /* 
9492                          * If the callee is a shared method, then its static cctor
9493                          * might not get called after the call was patched.
9494                          */
9495                         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)) {
9496                                 emit_class_init (cfg, cmethod->klass);
9497                                 CHECK_TYPELOAD (cmethod->klass);
9498                         }
9499
9500                         check_method_sharing (cfg, cmethod, &pass_vtable, &pass_mrgctx);
9501
9502                         if (cfg->gshared) {
9503                                 MonoGenericContext *cmethod_context = mono_method_get_context (cmethod);
9504
9505                                 context_used = mini_method_check_context_used (cfg, cmethod);
9506
9507                                 if (context_used && (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
9508                                         /* Generic method interface
9509                                            calls are resolved via a
9510                                            helper function and don't
9511                                            need an imt. */
9512                                         if (!cmethod_context || !cmethod_context->method_inst)
9513                                                 pass_imt_from_rgctx = TRUE;
9514                                 }
9515
9516                                 /*
9517                                  * If a shared method calls another
9518                                  * shared method then the caller must
9519                                  * have a generic sharing context
9520                                  * because the magic trampoline
9521                                  * requires it.  FIXME: We shouldn't
9522                                  * have to force the vtable/mrgctx
9523                                  * variable here.  Instead there
9524                                  * should be a flag in the cfg to
9525                                  * request a generic sharing context.
9526                                  */
9527                                 if (context_used &&
9528                                                 ((method->flags & METHOD_ATTRIBUTE_STATIC) || method->klass->valuetype))
9529                                         mono_get_vtable_var (cfg);
9530                         }
9531
9532                         if (pass_vtable) {
9533                                 if (context_used) {
9534                                         vtable_arg = emit_get_rgctx_klass (cfg, context_used, cmethod->klass, MONO_RGCTX_INFO_VTABLE);
9535                                 } else {
9536                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
9537
9538                                         CHECK_TYPELOAD (cmethod->klass);
9539                                         EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
9540                                 }
9541                         }
9542
9543                         if (pass_mrgctx) {
9544                                 g_assert (!vtable_arg);
9545
9546                                 if (!cfg->compile_aot) {
9547                                         /* 
9548                                          * emit_get_rgctx_method () calls mono_class_vtable () so check 
9549                                          * for type load errors before.
9550                                          */
9551                                         mono_class_setup_vtable (cmethod->klass);
9552                                         CHECK_TYPELOAD (cmethod->klass);
9553                                 }
9554
9555                                 vtable_arg = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
9556
9557                                 /* !marshalbyref is needed to properly handle generic methods + remoting */
9558                                 if ((!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
9559                                          MONO_METHOD_IS_FINAL (cmethod)) &&
9560                                         !mono_class_is_marshalbyref (cmethod->klass)) {
9561                                         if (virtual_)
9562                                                 check_this = TRUE;
9563                                         virtual_ = 0;
9564                                 }
9565                         }
9566
9567                         if (pass_imt_from_rgctx) {
9568                                 g_assert (!pass_vtable);
9569
9570                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9571                                         cmethod, MONO_RGCTX_INFO_METHOD);
9572                         }
9573
9574                         if (check_this)
9575                                 MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9576
9577                         /* Calling virtual generic methods */
9578                         if (virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) &&
9579                             !(MONO_METHOD_IS_FINAL (cmethod) && 
9580                               cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) &&
9581                             fsig->generic_param_count && 
9582                                 !(cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) &&
9583                                 !cfg->llvm_only) {
9584                                 MonoInst *this_temp, *this_arg_temp, *store;
9585                                 MonoInst *iargs [4];
9586
9587                                 g_assert (fsig->is_inflated);
9588
9589                                 /* Prevent inlining of methods that contain indirect calls */
9590                                 INLINE_FAILURE ("virtual generic call");
9591
9592                                 if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))
9593                                         GSHAREDVT_FAILURE (*ip);
9594
9595                                 if (cfg->backend->have_generalized_imt_thunk && cfg->backend->gshared_supported && cmethod->wrapper_type == MONO_WRAPPER_NONE) {
9596                                         g_assert (!imt_arg);
9597                                         if (!context_used)
9598                                                 g_assert (cmethod->is_inflated);
9599                                         imt_arg = emit_get_rgctx_method (cfg, context_used,
9600                                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
9601                                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, sp [0], imt_arg, NULL);
9602                                 } else {
9603                                         this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
9604                                         NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
9605                                         MONO_ADD_INS (cfg->cbb, store);
9606
9607                                         /* FIXME: This should be a managed pointer */
9608                                         this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
9609
9610                                         EMIT_NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
9611                                         iargs [1] = emit_get_rgctx_method (cfg, context_used,
9612                                                                                                            cmethod, MONO_RGCTX_INFO_METHOD);
9613                                         EMIT_NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
9614                                         addr = mono_emit_jit_icall (cfg,
9615                                                                                                 mono_helper_compile_generic_method, iargs);
9616
9617                                         EMIT_NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
9618
9619                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9620                                 }
9621
9622                                 goto call_end;
9623                         }
9624
9625                         /*
9626                          * Implement a workaround for the inherent races involved in locking:
9627                          * Monitor.Enter ()
9628                          * try {
9629                          * } finally {
9630                          *    Monitor.Exit ()
9631                          * }
9632                          * If a thread abort happens between the call to Monitor.Enter () and the start of the
9633                          * try block, the Exit () won't be executed, see:
9634                          * http://www.bluebytesoftware.com/blog/2007/01/30/MonitorEnterThreadAbortsAndOrphanedLocks.aspx
9635                          * To work around this, we extend such try blocks to include the last x bytes
9636                          * of the Monitor.Enter () call.
9637                          */
9638                         if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
9639                                 MonoBasicBlock *tbb;
9640
9641                                 GET_BBLOCK (cfg, tbb, ip + 5);
9642                                 /* 
9643                                  * Only extend try blocks with a finally, to avoid catching exceptions thrown
9644                                  * from Monitor.Enter like ArgumentNullException.
9645                                  */
9646                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
9647                                         /* Mark this bblock as needing to be extended */
9648                                         tbb->extend_try_block = TRUE;
9649                                 }
9650                         }
9651
9652                         /* Conversion to a JIT intrinsic */
9653                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_method (cfg, cmethod, fsig, sp))) {
9654                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9655                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
9656                                         emit_widen = FALSE;
9657                                 }
9658                                 goto call_end;
9659                         }
9660                         CHECK_CFG_ERROR;
9661                         
9662                         /* Inlining */
9663                         if ((cfg->opt & MONO_OPT_INLINE) &&
9664                                 (!virtual_ || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || MONO_METHOD_IS_FINAL (cmethod)) &&
9665                             mono_method_check_inlining (cfg, cmethod)) {
9666                                 int costs;
9667                                 gboolean always = FALSE;
9668
9669                                 if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
9670                                         (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
9671                                         /* Prevent inlining of methods that call wrappers */
9672                                         INLINE_FAILURE ("wrapper call");
9673                                         cmethod = mono_marshal_get_native_wrapper (cmethod, TRUE, FALSE);
9674                                         always = TRUE;
9675                                 }
9676
9677                                 costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, always);
9678                                 if (costs) {
9679                                         cfg->real_offset += 5;
9680
9681                                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9682                                                 /* *sp is already set by inline_method */
9683                                                 sp++;
9684                                                 push_res = FALSE;
9685                                         }
9686
9687                                         inline_costs += costs;
9688
9689                                         goto call_end;
9690                                 }
9691                         }
9692
9693                         /* Tail recursion elimination */
9694                         if ((cfg->opt & MONO_OPT_TAILC) && call_opcode == CEE_CALL && cmethod == method && ip [5] == CEE_RET && !vtable_arg) {
9695                                 gboolean has_vtargs = FALSE;
9696                                 int i;
9697
9698                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9699                                 INLINE_FAILURE ("tail call");
9700
9701                                 /* keep it simple */
9702                                 for (i =  fsig->param_count - 1; i >= 0; i--) {
9703                                         if (MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->params [i])) 
9704                                                 has_vtargs = TRUE;
9705                                 }
9706
9707                                 if (!has_vtargs) {
9708                                         for (i = 0; i < n; ++i)
9709                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9710                                         MONO_INST_NEW (cfg, ins, OP_BR);
9711                                         MONO_ADD_INS (cfg->cbb, ins);
9712                                         tblock = start_bblock->out_bb [0];
9713                                         link_bblock (cfg, cfg->cbb, tblock);
9714                                         ins->inst_target_bb = tblock;
9715                                         start_new_bblock = 1;
9716
9717                                         /* skip the CEE_RET, too */
9718                                         if (ip_in_bb (cfg, cfg->cbb, ip + 5))
9719                                                 skip_ret = TRUE;
9720                                         push_res = FALSE;
9721                                         goto call_end;
9722                                 }
9723                         }
9724
9725                         inline_costs += 10 * num_calls++;
9726
9727                         /*
9728                          * Making generic calls out of gsharedvt methods.
9729                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
9730                          * patching gshared method addresses into a gsharedvt method.
9731                          */
9732                         if (cfg->gsharedvt && (mini_is_gsharedvt_signature (fsig) || cmethod->is_inflated || cmethod->klass->generic_class) &&
9733                                 !(cmethod->klass->rank && cmethod->klass->byval_arg.type != MONO_TYPE_SZARRAY) &&
9734                                 (!(cfg->llvm_only && virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL)))) {
9735                                 MonoRgctxInfoType info_type;
9736
9737                                 if (virtual_) {
9738                                         //if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
9739                                                 //GSHAREDVT_FAILURE (*ip);
9740                                         // disable for possible remoting calls
9741                                         if (fsig->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class))
9742                                                 GSHAREDVT_FAILURE (*ip);
9743                                         if (fsig->generic_param_count) {
9744                                                 /* virtual generic call */
9745                                                 g_assert (!imt_arg);
9746                                                 /* Same as the virtual generic case above */
9747                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9748                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9749                                                 /* This is not needed, as the trampoline code will pass one, and it might be passed in the same reg as the imt arg */
9750                                                 vtable_arg = NULL;
9751                                         } else if ((cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !imt_arg) {
9752                                                 /* This can happen when we call a fully instantiated iface method */
9753                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9754                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9755                                                 vtable_arg = NULL;
9756                                         }
9757                                 }
9758
9759                                 if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (cmethod->name, "Invoke")))
9760                                         keep_this_alive = sp [0];
9761
9762                                 if (virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))
9763                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
9764                                 else
9765                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE;
9766                                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, info_type);
9767
9768                                 if (cfg->llvm_only) {
9769                                         // FIXME: Avoid initializing vtable_arg
9770                                         ins = emit_llvmonly_calli (cfg, fsig, sp, addr);
9771                                 } else {
9772                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9773                                 }
9774                                 goto call_end;
9775                         }
9776
9777                         /* Generic sharing */
9778
9779                         /*
9780                          * Use this if the callee is gsharedvt sharable too, since
9781                          * at runtime we might find an instantiation so the call cannot
9782                          * be patched (the 'no_patch' code path in mini-trampolines.c).
9783                          */
9784                         if (context_used && !imt_arg && !array_rank && !delegate_invoke &&
9785                                 (!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
9786                                  !mono_class_generic_sharing_enabled (cmethod->klass)) &&
9787                                 (!virtual_ || MONO_METHOD_IS_FINAL (cmethod) ||
9788                                  !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))) {
9789                                 INLINE_FAILURE ("gshared");
9790
9791                                 g_assert (cfg->gshared && cmethod);
9792                                 g_assert (!addr);
9793
9794                                 /*
9795                                  * We are compiling a call to a
9796                                  * generic method from shared code,
9797                                  * which means that we have to look up
9798                                  * the method in the rgctx and do an
9799                                  * indirect call.
9800                                  */
9801                                 if (fsig->hasthis)
9802                                         MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9803
9804                                 if (cfg->llvm_only) {
9805                                         if (cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig))
9806                                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER);
9807                                         else
9808                                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
9809                                         // FIXME: Avoid initializing imt_arg/vtable_arg
9810                                         ins = emit_llvmonly_calli (cfg, fsig, sp, addr);
9811                                 } else {
9812                                         addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
9813                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9814                                 }
9815                                 goto call_end;
9816                         }
9817
9818                         /* Direct calls to icalls */
9819                         if (direct_icall) {
9820                                 MonoMethod *wrapper;
9821                                 int costs;
9822
9823                                 /* Inline the wrapper */
9824                                 wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
9825
9826                                 costs = inline_method (cfg, wrapper, fsig, sp, ip, cfg->real_offset, TRUE);
9827                                 g_assert (costs > 0);
9828                                 cfg->real_offset += 5;
9829
9830                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9831                                         /* *sp is already set by inline_method */
9832                                         sp++;
9833                                         push_res = FALSE;
9834                                 }
9835
9836                                 inline_costs += costs;
9837
9838                                 goto call_end;
9839                         }
9840                                         
9841                         /* Array methods */
9842                         if (array_rank) {
9843                                 MonoInst *addr;
9844
9845                                 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ 
9846                                         MonoInst *val = sp [fsig->param_count];
9847
9848                                         if (val->type == STACK_OBJ) {
9849                                                 MonoInst *iargs [2];
9850
9851                                                 iargs [0] = sp [0];
9852                                                 iargs [1] = val;
9853                                                 
9854                                                 mono_emit_jit_icall (cfg, mono_helper_stelem_ref_check, iargs);
9855                                         }
9856                                         
9857                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, TRUE);
9858                                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, fsig->params [fsig->param_count - 1], addr->dreg, 0, val->dreg);
9859                                         if (cfg->gen_write_barriers && val->type == STACK_OBJ && !(val->opcode == OP_PCONST && val->inst_c0 == 0))
9860                                                 emit_write_barrier (cfg, addr, val);
9861                                         if (cfg->gen_write_barriers && mini_is_gsharedvt_klass (cmethod->klass))
9862                                                 GSHAREDVT_FAILURE (*ip);
9863                                 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
9864                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9865
9866                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, addr->dreg, 0);
9867                                 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
9868                                         if (!cmethod->klass->element_class->valuetype && !readonly)
9869                                                 mini_emit_check_array_type (cfg, sp [0], cmethod->klass);
9870                                         CHECK_TYPELOAD (cmethod->klass);
9871                                         
9872                                         readonly = FALSE;
9873                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9874                                         ins = addr;
9875                                 } else {
9876                                         g_assert_not_reached ();
9877                                 }
9878
9879                                 emit_widen = FALSE;
9880                                 goto call_end;
9881                         }
9882
9883                         ins = mini_redirect_call (cfg, cmethod, fsig, sp, virtual_ ? sp [0] : NULL);
9884                         if (ins)
9885                                 goto call_end;
9886
9887                         /* Tail prefix / tail call optimization */
9888
9889                         /* FIXME: Enabling TAILC breaks some inlining/stack trace/etc tests */
9890                         /* FIXME: runtime generic context pointer for jumps? */
9891                         /* FIXME: handle this for generic sharing eventually */
9892                         if ((ins_flag & MONO_INST_TAILCALL) &&
9893                                 !vtable_arg && !cfg->gshared && is_supported_tail_call (cfg, method, cmethod, fsig, call_opcode))
9894                                 supported_tail_call = TRUE;
9895
9896                         if (supported_tail_call) {
9897                                 MonoCallInst *call;
9898
9899                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9900                                 INLINE_FAILURE ("tail call");
9901
9902                                 //printf ("HIT: %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
9903
9904                                 if (cfg->backend->have_op_tail_call) {
9905                                         /* Handle tail calls similarly to normal calls */
9906                                         tail_call = TRUE;
9907                                 } else {
9908                                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
9909
9910                                         MONO_INST_NEW_CALL (cfg, call, OP_JMP);
9911                                         call->tail_call = TRUE;
9912                                         call->method = cmethod;
9913                                         call->signature = mono_method_signature (cmethod);
9914
9915                                         /*
9916                                          * We implement tail calls by storing the actual arguments into the 
9917                                          * argument variables, then emitting a CEE_JMP.
9918                                          */
9919                                         for (i = 0; i < n; ++i) {
9920                                                 /* Prevent argument from being register allocated */
9921                                                 arg_array [i]->flags |= MONO_INST_VOLATILE;
9922                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9923                                         }
9924                                         ins = (MonoInst*)call;
9925                                         ins->inst_p0 = cmethod;
9926                                         ins->inst_p1 = arg_array [0];
9927                                         MONO_ADD_INS (cfg->cbb, ins);
9928                                         link_bblock (cfg, cfg->cbb, end_bblock);
9929                                         start_new_bblock = 1;
9930
9931                                         // FIXME: Eliminate unreachable epilogs
9932
9933                                         /*
9934                                          * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9935                                          * only reachable from this call.
9936                                          */
9937                                         GET_BBLOCK (cfg, tblock, ip + 5);
9938                                         if (tblock == cfg->cbb || tblock->in_count == 0)
9939                                                 skip_ret = TRUE;
9940                                         push_res = FALSE;
9941
9942                                         goto call_end;
9943                                 }
9944                         }
9945
9946                         /* 
9947                          * Synchronized wrappers.
9948                          * Its hard to determine where to replace a method with its synchronized
9949                          * wrapper without causing an infinite recursion. The current solution is
9950                          * to add the synchronized wrapper in the trampolines, and to
9951                          * change the called method to a dummy wrapper, and resolve that wrapper
9952                          * to the real method in mono_jit_compile_method ().
9953                          */
9954                         if (cfg->method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
9955                                 MonoMethod *orig = mono_marshal_method_from_wrapper (cfg->method);
9956                                 if (cmethod == orig || (cmethod->is_inflated && mono_method_get_declaring_generic_method (cmethod) == orig))
9957                                         cmethod = mono_marshal_get_synchronized_inner_wrapper (cmethod);
9958                         }
9959
9960                         /*
9961                          * Virtual calls in llvm-only mode.
9962                          */
9963                         if (cfg->llvm_only && virtual_ && cmethod && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
9964                                 ins = emit_llvmonly_virtual_call (cfg, cmethod, fsig, context_used, sp);
9965                                 goto call_end;
9966                         }
9967
9968                         /* Common call */
9969                         INLINE_FAILURE ("call");
9970                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, tail_call, sp, virtual_ ? sp [0] : NULL,
9971                                                                                           imt_arg, vtable_arg);
9972
9973                         if (tail_call && !cfg->llvm_only) {
9974                                 link_bblock (cfg, cfg->cbb, end_bblock);
9975                                 start_new_bblock = 1;
9976
9977                                 // FIXME: Eliminate unreachable epilogs
9978
9979                                 /*
9980                                  * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9981                                  * only reachable from this call.
9982                                  */
9983                                 GET_BBLOCK (cfg, tblock, ip + 5);
9984                                 if (tblock == cfg->cbb || tblock->in_count == 0)
9985                                         skip_ret = TRUE;
9986                                 push_res = FALSE;
9987                         }
9988
9989                         call_end:
9990
9991                         /* End of call, INS should contain the result of the call, if any */
9992
9993                         if (push_res && !MONO_TYPE_IS_VOID (fsig->ret)) {
9994                                 g_assert (ins);
9995                                 if (emit_widen)
9996                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
9997                                 else
9998                                         *sp++ = ins;
9999                         }
10000
10001                         if (keep_this_alive) {
10002                                 MonoInst *dummy_use;
10003
10004                                 /* See mono_emit_method_call_full () */
10005                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, keep_this_alive);
10006                         }
10007
10008                         CHECK_CFG_EXCEPTION;
10009
10010                         ip += 5;
10011                         if (skip_ret) {
10012                                 g_assert (*ip == CEE_RET);
10013                                 ip += 1;
10014                         }
10015                         ins_flag = 0;
10016                         constrained_class = NULL;
10017                         if (need_seq_point)
10018                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
10019                         break;
10020                 }
10021                 case CEE_RET:
10022                         if (cfg->method != method) {
10023                                 /* return from inlined method */
10024                                 /* 
10025                                  * If in_count == 0, that means the ret is unreachable due to
10026                                  * being preceeded by a throw. In that case, inline_method () will
10027                                  * handle setting the return value 
10028                                  * (test case: test_0_inline_throw ()).
10029                                  */
10030                                 if (return_var && cfg->cbb->in_count) {
10031                                         MonoType *ret_type = mono_method_signature (method)->ret;
10032
10033                                         MonoInst *store;
10034                                         CHECK_STACK (1);
10035                                         --sp;
10036
10037                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
10038                                                 UNVERIFIED;
10039
10040                                         //g_assert (returnvar != -1);
10041                                         EMIT_NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
10042                                         cfg->ret_var_set = TRUE;
10043                                 } 
10044                         } else {
10045                                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
10046
10047                                 if (cfg->lmf_var && cfg->cbb->in_count && !cfg->llvm_only)
10048                                         emit_pop_lmf (cfg);
10049
10050                                 if (cfg->ret) {
10051                                         MonoType *ret_type = mini_get_underlying_type (mono_method_signature (method)->ret);
10052
10053                                         if (seq_points && !sym_seq_points) {
10054                                                 /* 
10055                                                  * Place a seq point here too even through the IL stack is not
10056                                                  * empty, so a step over on
10057                                                  * call <FOO>
10058                                                  * ret
10059                                                  * will work correctly.
10060                                                  */
10061                                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, TRUE);
10062                                                 MONO_ADD_INS (cfg->cbb, ins);
10063                                         }
10064
10065                                         g_assert (!return_var);
10066                                         CHECK_STACK (1);
10067                                         --sp;
10068
10069                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
10070                                                 UNVERIFIED;
10071
10072                                         emit_setret (cfg, *sp);
10073                                 }
10074                         }
10075                         if (sp != stack_start)
10076                                 UNVERIFIED;
10077                         MONO_INST_NEW (cfg, ins, OP_BR);
10078                         ip++;
10079                         ins->inst_target_bb = end_bblock;
10080                         MONO_ADD_INS (cfg->cbb, ins);
10081                         link_bblock (cfg, cfg->cbb, end_bblock);
10082                         start_new_bblock = 1;
10083                         break;
10084                 case CEE_BR_S:
10085                         CHECK_OPSIZE (2);
10086                         MONO_INST_NEW (cfg, ins, OP_BR);
10087                         ip++;
10088                         target = ip + 1 + (signed char)(*ip);
10089                         ++ip;
10090                         GET_BBLOCK (cfg, tblock, target);
10091                         link_bblock (cfg, cfg->cbb, tblock);
10092                         ins->inst_target_bb = tblock;
10093                         if (sp != stack_start) {
10094                                 handle_stack_args (cfg, stack_start, sp - stack_start);
10095                                 sp = stack_start;
10096                                 CHECK_UNVERIFIABLE (cfg);
10097                         }
10098                         MONO_ADD_INS (cfg->cbb, ins);
10099                         start_new_bblock = 1;
10100                         inline_costs += BRANCH_COST;
10101                         break;
10102                 case CEE_BEQ_S:
10103                 case CEE_BGE_S:
10104                 case CEE_BGT_S:
10105                 case CEE_BLE_S:
10106                 case CEE_BLT_S:
10107                 case CEE_BNE_UN_S:
10108                 case CEE_BGE_UN_S:
10109                 case CEE_BGT_UN_S:
10110                 case CEE_BLE_UN_S:
10111                 case CEE_BLT_UN_S:
10112                         CHECK_OPSIZE (2);
10113                         CHECK_STACK (2);
10114                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
10115                         ip++;
10116                         target = ip + 1 + *(signed char*)ip;
10117                         ip++;
10118
10119                         ADD_BINCOND (NULL);
10120
10121                         sp = stack_start;
10122                         inline_costs += BRANCH_COST;
10123                         break;
10124                 case CEE_BR:
10125                         CHECK_OPSIZE (5);
10126                         MONO_INST_NEW (cfg, ins, OP_BR);
10127                         ip++;
10128
10129                         target = ip + 4 + (gint32)read32(ip);
10130                         ip += 4;
10131                         GET_BBLOCK (cfg, tblock, target);
10132                         link_bblock (cfg, cfg->cbb, tblock);
10133                         ins->inst_target_bb = tblock;
10134                         if (sp != stack_start) {
10135                                 handle_stack_args (cfg, stack_start, sp - stack_start);
10136                                 sp = stack_start;
10137                                 CHECK_UNVERIFIABLE (cfg);
10138                         }
10139
10140                         MONO_ADD_INS (cfg->cbb, ins);
10141
10142                         start_new_bblock = 1;
10143                         inline_costs += BRANCH_COST;
10144                         break;
10145                 case CEE_BRFALSE_S:
10146                 case CEE_BRTRUE_S:
10147                 case CEE_BRFALSE:
10148                 case CEE_BRTRUE: {
10149                         MonoInst *cmp;
10150                         gboolean is_short = ((*ip) == CEE_BRFALSE_S) || ((*ip) == CEE_BRTRUE_S);
10151                         gboolean is_true = ((*ip) == CEE_BRTRUE_S) || ((*ip) == CEE_BRTRUE);
10152                         guint32 opsize = is_short ? 1 : 4;
10153
10154                         CHECK_OPSIZE (opsize);
10155                         CHECK_STACK (1);
10156                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
10157                                 UNVERIFIED;
10158                         ip ++;
10159                         target = ip + opsize + (is_short ? *(signed char*)ip : (gint32)read32(ip));
10160                         ip += opsize;
10161
10162                         sp--;
10163
10164                         GET_BBLOCK (cfg, tblock, target);
10165                         link_bblock (cfg, cfg->cbb, tblock);
10166                         GET_BBLOCK (cfg, tblock, ip);
10167                         link_bblock (cfg, cfg->cbb, tblock);
10168
10169                         if (sp != stack_start) {
10170                                 handle_stack_args (cfg, stack_start, sp - stack_start);
10171                                 CHECK_UNVERIFIABLE (cfg);
10172                         }
10173
10174                         MONO_INST_NEW(cfg, cmp, OP_ICOMPARE_IMM);
10175                         cmp->sreg1 = sp [0]->dreg;
10176                         type_from_op (cfg, cmp, sp [0], NULL);
10177                         CHECK_TYPE (cmp);
10178
10179 #if SIZEOF_REGISTER == 4
10180                         if (cmp->opcode == OP_LCOMPARE_IMM) {
10181                                 /* Convert it to OP_LCOMPARE */
10182                                 MONO_INST_NEW (cfg, ins, OP_I8CONST);
10183                                 ins->type = STACK_I8;
10184                                 ins->dreg = alloc_dreg (cfg, STACK_I8);
10185                                 ins->inst_l = 0;
10186                                 MONO_ADD_INS (cfg->cbb, ins);
10187                                 cmp->opcode = OP_LCOMPARE;
10188                                 cmp->sreg2 = ins->dreg;
10189                         }
10190 #endif
10191                         MONO_ADD_INS (cfg->cbb, cmp);
10192
10193                         MONO_INST_NEW (cfg, ins, is_true ? CEE_BNE_UN : CEE_BEQ);
10194                         type_from_op (cfg, ins, sp [0], NULL);
10195                         MONO_ADD_INS (cfg->cbb, ins);
10196                         ins->inst_many_bb = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);
10197                         GET_BBLOCK (cfg, tblock, target);
10198                         ins->inst_true_bb = tblock;
10199                         GET_BBLOCK (cfg, tblock, ip);
10200                         ins->inst_false_bb = tblock;
10201                         start_new_bblock = 2;
10202
10203                         sp = stack_start;
10204                         inline_costs += BRANCH_COST;
10205                         break;
10206                 }
10207                 case CEE_BEQ:
10208                 case CEE_BGE:
10209                 case CEE_BGT:
10210                 case CEE_BLE:
10211                 case CEE_BLT:
10212                 case CEE_BNE_UN:
10213                 case CEE_BGE_UN:
10214                 case CEE_BGT_UN:
10215                 case CEE_BLE_UN:
10216                 case CEE_BLT_UN:
10217                         CHECK_OPSIZE (5);
10218                         CHECK_STACK (2);
10219                         MONO_INST_NEW (cfg, ins, *ip);
10220                         ip++;
10221                         target = ip + 4 + (gint32)read32(ip);
10222                         ip += 4;
10223
10224                         ADD_BINCOND (NULL);
10225
10226                         sp = stack_start;
10227                         inline_costs += BRANCH_COST;
10228                         break;
10229                 case CEE_SWITCH: {
10230                         MonoInst *src1;
10231                         MonoBasicBlock **targets;
10232                         MonoBasicBlock *default_bblock;
10233                         MonoJumpInfoBBTable *table;
10234                         int offset_reg = alloc_preg (cfg);
10235                         int target_reg = alloc_preg (cfg);
10236                         int table_reg = alloc_preg (cfg);
10237                         int sum_reg = alloc_preg (cfg);
10238                         gboolean use_op_switch;
10239
10240                         CHECK_OPSIZE (5);
10241                         CHECK_STACK (1);
10242                         n = read32 (ip + 1);
10243                         --sp;
10244                         src1 = sp [0];
10245                         if ((src1->type != STACK_I4) && (src1->type != STACK_PTR)) 
10246                                 UNVERIFIED;
10247
10248                         ip += 5;
10249                         CHECK_OPSIZE (n * sizeof (guint32));
10250                         target = ip + n * sizeof (guint32);
10251
10252                         GET_BBLOCK (cfg, default_bblock, target);
10253                         default_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
10254
10255                         targets = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * n);
10256                         for (i = 0; i < n; ++i) {
10257                                 GET_BBLOCK (cfg, tblock, target + (gint32)read32(ip));
10258                                 targets [i] = tblock;
10259                                 targets [i]->flags |= BB_INDIRECT_JUMP_TARGET;
10260                                 ip += 4;
10261                         }
10262
10263                         if (sp != stack_start) {
10264                                 /* 
10265                                  * Link the current bb with the targets as well, so handle_stack_args
10266                                  * will set their in_stack correctly.
10267                                  */
10268                                 link_bblock (cfg, cfg->cbb, default_bblock);
10269                                 for (i = 0; i < n; ++i)
10270                                         link_bblock (cfg, cfg->cbb, targets [i]);
10271
10272                                 handle_stack_args (cfg, stack_start, sp - stack_start);
10273                                 sp = stack_start;
10274                                 CHECK_UNVERIFIABLE (cfg);
10275
10276                                 /* Undo the links */
10277                                 mono_unlink_bblock (cfg, cfg->cbb, default_bblock);
10278                                 for (i = 0; i < n; ++i)
10279                                         mono_unlink_bblock (cfg, cfg->cbb, targets [i]);
10280                         }
10281
10282                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, src1->dreg, n);
10283                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBGE_UN, default_bblock);
10284
10285                         for (i = 0; i < n; ++i)
10286                                 link_bblock (cfg, cfg->cbb, targets [i]);
10287
10288                         table = (MonoJumpInfoBBTable *)mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
10289                         table->table = targets;
10290                         table->table_size = n;
10291
10292                         use_op_switch = FALSE;
10293 #ifdef TARGET_ARM
10294                         /* ARM implements SWITCH statements differently */
10295                         /* FIXME: Make it use the generic implementation */
10296                         if (!cfg->compile_aot)
10297                                 use_op_switch = TRUE;
10298 #endif
10299
10300                         if (COMPILE_LLVM (cfg))
10301                                 use_op_switch = TRUE;
10302
10303                         cfg->cbb->has_jump_table = 1;
10304
10305                         if (use_op_switch) {
10306                                 MONO_INST_NEW (cfg, ins, OP_SWITCH);
10307                                 ins->sreg1 = src1->dreg;
10308                                 ins->inst_p0 = table;
10309                                 ins->inst_many_bb = targets;
10310                                 ins->klass = (MonoClass *)GUINT_TO_POINTER (n);
10311                                 MONO_ADD_INS (cfg->cbb, ins);
10312                         } else {
10313                                 if (sizeof (gpointer) == 8)
10314                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 3);
10315                                 else
10316                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 2);
10317
10318 #if SIZEOF_REGISTER == 8
10319                                 /* The upper word might not be zero, and we add it to a 64 bit address later */
10320                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, offset_reg, offset_reg);
10321 #endif
10322
10323                                 if (cfg->compile_aot) {
10324                                         MONO_EMIT_NEW_AOTCONST (cfg, table_reg, table, MONO_PATCH_INFO_SWITCH);
10325                                 } else {
10326                                         MONO_INST_NEW (cfg, ins, OP_JUMP_TABLE);
10327                                         ins->inst_c1 = MONO_PATCH_INFO_SWITCH;
10328                                         ins->inst_p0 = table;
10329                                         ins->dreg = table_reg;
10330                                         MONO_ADD_INS (cfg->cbb, ins);
10331                                 }
10332
10333                                 /* FIXME: Use load_memindex */
10334                                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, table_reg, offset_reg);
10335                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, target_reg, sum_reg, 0);
10336                                 MONO_EMIT_NEW_UNALU (cfg, OP_BR_REG, -1, target_reg);
10337                         }
10338                         start_new_bblock = 1;
10339                         inline_costs += (BRANCH_COST * 2);
10340                         break;
10341                 }
10342                 case CEE_LDIND_I1:
10343                 case CEE_LDIND_U1:
10344                 case CEE_LDIND_I2:
10345                 case CEE_LDIND_U2:
10346                 case CEE_LDIND_I4:
10347                 case CEE_LDIND_U4:
10348                 case CEE_LDIND_I8:
10349                 case CEE_LDIND_I:
10350                 case CEE_LDIND_R4:
10351                 case CEE_LDIND_R8:
10352                 case CEE_LDIND_REF:
10353                         CHECK_STACK (1);
10354                         --sp;
10355
10356                         switch (*ip) {
10357                         case CEE_LDIND_R4:
10358                         case CEE_LDIND_R8:
10359                                 dreg = alloc_freg (cfg);
10360                                 break;
10361                         case CEE_LDIND_I8:
10362                                 dreg = alloc_lreg (cfg);
10363                                 break;
10364                         case CEE_LDIND_REF:
10365                                 dreg = alloc_ireg_ref (cfg);
10366                                 break;
10367                         default:
10368                                 dreg = alloc_preg (cfg);
10369                         }
10370
10371                         NEW_LOAD_MEMBASE (cfg, ins, ldind_to_load_membase (*ip), dreg, sp [0]->dreg, 0);
10372                         ins->type = ldind_type [*ip - CEE_LDIND_I1];
10373                         if (*ip == CEE_LDIND_R4)
10374                                 ins->type = cfg->r4_stack_type;
10375                         ins->flags |= ins_flag;
10376                         MONO_ADD_INS (cfg->cbb, ins);
10377                         *sp++ = ins;
10378                         if (ins_flag & MONO_INST_VOLATILE) {
10379                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10380                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10381                         }
10382                         ins_flag = 0;
10383                         ++ip;
10384                         break;
10385                 case CEE_STIND_REF:
10386                 case CEE_STIND_I1:
10387                 case CEE_STIND_I2:
10388                 case CEE_STIND_I4:
10389                 case CEE_STIND_I8:
10390                 case CEE_STIND_R4:
10391                 case CEE_STIND_R8:
10392                 case CEE_STIND_I:
10393                         CHECK_STACK (2);
10394                         sp -= 2;
10395
10396                         if (ins_flag & MONO_INST_VOLATILE) {
10397                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
10398                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
10399                         }
10400
10401                         NEW_STORE_MEMBASE (cfg, ins, stind_to_store_membase (*ip), sp [0]->dreg, 0, sp [1]->dreg);
10402                         ins->flags |= ins_flag;
10403                         ins_flag = 0;
10404
10405                         MONO_ADD_INS (cfg->cbb, ins);
10406
10407                         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)))
10408                                 emit_write_barrier (cfg, sp [0], sp [1]);
10409
10410                         inline_costs += 1;
10411                         ++ip;
10412                         break;
10413
10414                 case CEE_MUL:
10415                         CHECK_STACK (2);
10416
10417                         MONO_INST_NEW (cfg, ins, (*ip));
10418                         sp -= 2;
10419                         ins->sreg1 = sp [0]->dreg;
10420                         ins->sreg2 = sp [1]->dreg;
10421                         type_from_op (cfg, ins, sp [0], sp [1]);
10422                         CHECK_TYPE (ins);
10423                         ins->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type);
10424
10425                         /* Use the immediate opcodes if possible */
10426                         if ((sp [1]->opcode == OP_ICONST) && mono_arch_is_inst_imm (sp [1]->inst_c0)) {
10427                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
10428                                 if (imm_opcode != -1) {
10429                                         ins->opcode = imm_opcode;
10430                                         ins->inst_p1 = (gpointer)(gssize)(sp [1]->inst_c0);
10431                                         ins->sreg2 = -1;
10432
10433                                         NULLIFY_INS (sp [1]);
10434                                 }
10435                         }
10436
10437                         MONO_ADD_INS ((cfg)->cbb, (ins));
10438
10439                         *sp++ = mono_decompose_opcode (cfg, ins);
10440                         ip++;
10441                         break;
10442                 case CEE_ADD:
10443                 case CEE_SUB:
10444                 case CEE_DIV:
10445                 case CEE_DIV_UN:
10446                 case CEE_REM:
10447                 case CEE_REM_UN:
10448                 case CEE_AND:
10449                 case CEE_OR:
10450                 case CEE_XOR:
10451                 case CEE_SHL:
10452                 case CEE_SHR:
10453                 case CEE_SHR_UN:
10454                         CHECK_STACK (2);
10455
10456                         MONO_INST_NEW (cfg, ins, (*ip));
10457                         sp -= 2;
10458                         ins->sreg1 = sp [0]->dreg;
10459                         ins->sreg2 = sp [1]->dreg;
10460                         type_from_op (cfg, ins, sp [0], sp [1]);
10461                         CHECK_TYPE (ins);
10462                         add_widen_op (cfg, ins, &sp [0], &sp [1]);
10463                         ins->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type);
10464
10465                         /* FIXME: Pass opcode to is_inst_imm */
10466
10467                         /* Use the immediate opcodes if possible */
10468                         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)) {
10469                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
10470                                 if (imm_opcode != -1) {
10471                                         ins->opcode = imm_opcode;
10472                                         if (sp [1]->opcode == OP_I8CONST) {
10473 #if SIZEOF_REGISTER == 8
10474                                                 ins->inst_imm = sp [1]->inst_l;
10475 #else
10476                                                 ins->inst_ls_word = sp [1]->inst_ls_word;
10477                                                 ins->inst_ms_word = sp [1]->inst_ms_word;
10478 #endif
10479                                         }
10480                                         else
10481                                                 ins->inst_imm = (gssize)(sp [1]->inst_c0);
10482                                         ins->sreg2 = -1;
10483
10484                                         /* Might be followed by an instruction added by add_widen_op */
10485                                         if (sp [1]->next == NULL)
10486                                                 NULLIFY_INS (sp [1]);
10487                                 }
10488                         }
10489                         MONO_ADD_INS ((cfg)->cbb, (ins));
10490
10491                         *sp++ = mono_decompose_opcode (cfg, ins);
10492                         ip++;
10493                         break;
10494                 case CEE_NEG:
10495                 case CEE_NOT:
10496                 case CEE_CONV_I1:
10497                 case CEE_CONV_I2:
10498                 case CEE_CONV_I4:
10499                 case CEE_CONV_R4:
10500                 case CEE_CONV_R8:
10501                 case CEE_CONV_U4:
10502                 case CEE_CONV_I8:
10503                 case CEE_CONV_U8:
10504                 case CEE_CONV_OVF_I8:
10505                 case CEE_CONV_OVF_U8:
10506                 case CEE_CONV_R_UN:
10507                         CHECK_STACK (1);
10508
10509                         /* Special case this earlier so we have long constants in the IR */
10510                         if ((((*ip) == CEE_CONV_I8) || ((*ip) == CEE_CONV_U8)) && (sp [-1]->opcode == OP_ICONST)) {
10511                                 int data = sp [-1]->inst_c0;
10512                                 sp [-1]->opcode = OP_I8CONST;
10513                                 sp [-1]->type = STACK_I8;
10514 #if SIZEOF_REGISTER == 8
10515                                 if ((*ip) == CEE_CONV_U8)
10516                                         sp [-1]->inst_c0 = (guint32)data;
10517                                 else
10518                                         sp [-1]->inst_c0 = data;
10519 #else
10520                                 sp [-1]->inst_ls_word = data;
10521                                 if ((*ip) == CEE_CONV_U8)
10522                                         sp [-1]->inst_ms_word = 0;
10523                                 else
10524                                         sp [-1]->inst_ms_word = (data < 0) ? -1 : 0;
10525 #endif
10526                                 sp [-1]->dreg = alloc_dreg (cfg, STACK_I8);
10527                         }
10528                         else {
10529                                 ADD_UNOP (*ip);
10530                         }
10531                         ip++;
10532                         break;
10533                 case CEE_CONV_OVF_I4:
10534                 case CEE_CONV_OVF_I1:
10535                 case CEE_CONV_OVF_I2:
10536                 case CEE_CONV_OVF_I:
10537                 case CEE_CONV_OVF_U:
10538                         CHECK_STACK (1);
10539
10540                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
10541                                 ADD_UNOP (CEE_CONV_OVF_I8);
10542                                 ADD_UNOP (*ip);
10543                         } else {
10544                                 ADD_UNOP (*ip);
10545                         }
10546                         ip++;
10547                         break;
10548                 case CEE_CONV_OVF_U1:
10549                 case CEE_CONV_OVF_U2:
10550                 case CEE_CONV_OVF_U4:
10551                         CHECK_STACK (1);
10552
10553                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
10554                                 ADD_UNOP (CEE_CONV_OVF_U8);
10555                                 ADD_UNOP (*ip);
10556                         } else {
10557                                 ADD_UNOP (*ip);
10558                         }
10559                         ip++;
10560                         break;
10561                 case CEE_CONV_OVF_I1_UN:
10562                 case CEE_CONV_OVF_I2_UN:
10563                 case CEE_CONV_OVF_I4_UN:
10564                 case CEE_CONV_OVF_I8_UN:
10565                 case CEE_CONV_OVF_U1_UN:
10566                 case CEE_CONV_OVF_U2_UN:
10567                 case CEE_CONV_OVF_U4_UN:
10568                 case CEE_CONV_OVF_U8_UN:
10569                 case CEE_CONV_OVF_I_UN:
10570                 case CEE_CONV_OVF_U_UN:
10571                 case CEE_CONV_U2:
10572                 case CEE_CONV_U1:
10573                 case CEE_CONV_I:
10574                 case CEE_CONV_U:
10575                         CHECK_STACK (1);
10576                         ADD_UNOP (*ip);
10577                         CHECK_CFG_EXCEPTION;
10578                         ip++;
10579                         break;
10580                 case CEE_ADD_OVF:
10581                 case CEE_ADD_OVF_UN:
10582                 case CEE_MUL_OVF:
10583                 case CEE_MUL_OVF_UN:
10584                 case CEE_SUB_OVF:
10585                 case CEE_SUB_OVF_UN:
10586                         CHECK_STACK (2);
10587                         ADD_BINOP (*ip);
10588                         ip++;
10589                         break;
10590                 case CEE_CPOBJ:
10591                         GSHAREDVT_FAILURE (*ip);
10592                         CHECK_OPSIZE (5);
10593                         CHECK_STACK (2);
10594                         token = read32 (ip + 1);
10595                         klass = mini_get_class (method, token, generic_context);
10596                         CHECK_TYPELOAD (klass);
10597                         sp -= 2;
10598                         if (generic_class_is_reference_type (cfg, klass)) {
10599                                 MonoInst *store, *load;
10600                                 int dreg = alloc_ireg_ref (cfg);
10601
10602                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, dreg, sp [1]->dreg, 0);
10603                                 load->flags |= ins_flag;
10604                                 MONO_ADD_INS (cfg->cbb, load);
10605
10606                                 NEW_STORE_MEMBASE (cfg, store, OP_STORE_MEMBASE_REG, sp [0]->dreg, 0, dreg);
10607                                 store->flags |= ins_flag;
10608                                 MONO_ADD_INS (cfg->cbb, store);
10609
10610                                 if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER)
10611                                         emit_write_barrier (cfg, sp [0], sp [1]);
10612                         } else {
10613                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
10614                         }
10615                         ins_flag = 0;
10616                         ip += 5;
10617                         break;
10618                 case CEE_LDOBJ: {
10619                         int loc_index = -1;
10620                         int stloc_len = 0;
10621
10622                         CHECK_OPSIZE (5);
10623                         CHECK_STACK (1);
10624                         --sp;
10625                         token = read32 (ip + 1);
10626                         klass = mini_get_class (method, token, generic_context);
10627                         CHECK_TYPELOAD (klass);
10628
10629                         /* Optimize the common ldobj+stloc combination */
10630                         switch (ip [5]) {
10631                         case CEE_STLOC_S:
10632                                 loc_index = ip [6];
10633                                 stloc_len = 2;
10634                                 break;
10635                         case CEE_STLOC_0:
10636                         case CEE_STLOC_1:
10637                         case CEE_STLOC_2:
10638                         case CEE_STLOC_3:
10639                                 loc_index = ip [5] - CEE_STLOC_0;
10640                                 stloc_len = 1;
10641                                 break;
10642                         default:
10643                                 break;
10644                         }
10645
10646                         if ((loc_index != -1) && ip_in_bb (cfg, cfg->cbb, ip + 5)) {
10647                                 CHECK_LOCAL (loc_index);
10648
10649                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10650                                 ins->dreg = cfg->locals [loc_index]->dreg;
10651                                 ins->flags |= ins_flag;
10652                                 ip += 5;
10653                                 ip += stloc_len;
10654                                 if (ins_flag & MONO_INST_VOLATILE) {
10655                                         /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10656                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10657                                 }
10658                                 ins_flag = 0;
10659                                 break;
10660                         }
10661
10662                         /* Optimize the ldobj+stobj combination */
10663                         /* The reference case ends up being a load+store anyway */
10664                         /* Skip this if the operation is volatile. */
10665                         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)) {
10666                                 CHECK_STACK (1);
10667
10668                                 sp --;
10669
10670                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
10671
10672                                 ip += 5 + 5;
10673                                 ins_flag = 0;
10674                                 break;
10675                         }
10676
10677                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10678                         ins->flags |= ins_flag;
10679                         *sp++ = ins;
10680
10681                         if (ins_flag & MONO_INST_VOLATILE) {
10682                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10683                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10684                         }
10685
10686                         ip += 5;
10687                         ins_flag = 0;
10688                         inline_costs += 1;
10689                         break;
10690                 }
10691                 case CEE_LDSTR:
10692                         CHECK_STACK_OVF (1);
10693                         CHECK_OPSIZE (5);
10694                         n = read32 (ip + 1);
10695
10696                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
10697                                 EMIT_NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
10698                                 ins->type = STACK_OBJ;
10699                                 *sp = ins;
10700                         }
10701                         else if (method->wrapper_type != MONO_WRAPPER_NONE) {
10702                                 MonoInst *iargs [1];
10703                                 char *str = (char *)mono_method_get_wrapper_data (method, n);
10704
10705                                 if (cfg->compile_aot)
10706                                         EMIT_NEW_LDSTRLITCONST (cfg, iargs [0], str);
10707                                 else
10708                                         EMIT_NEW_PCONST (cfg, iargs [0], str);
10709                                 *sp = mono_emit_jit_icall (cfg, mono_string_new_wrapper, iargs);
10710                         } else {
10711                                 if (cfg->opt & MONO_OPT_SHARED) {
10712                                         MonoInst *iargs [3];
10713
10714                                         if (cfg->compile_aot) {
10715                                                 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
10716                                         }
10717                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10718                                         EMIT_NEW_IMAGECONST (cfg, iargs [1], image);
10719                                         EMIT_NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
10720                                         *sp = mono_emit_jit_icall (cfg, ves_icall_mono_ldstr, iargs);
10721                                         mono_ldstr_checked (cfg->domain, image, mono_metadata_token_index (n), &cfg->error);
10722                                         CHECK_CFG_ERROR;
10723                                 } else {
10724                                         if (cfg->cbb->out_of_line) {
10725                                                 MonoInst *iargs [2];
10726
10727                                                 if (image == mono_defaults.corlib) {
10728                                                         /* 
10729                                                          * Avoid relocations in AOT and save some space by using a 
10730                                                          * version of helper_ldstr specialized to mscorlib.
10731                                                          */
10732                                                         EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (n));
10733                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr_mscorlib, iargs);
10734                                                 } else {
10735                                                         /* Avoid creating the string object */
10736                                                         EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
10737                                                         EMIT_NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n));
10738                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr, iargs);
10739                                                 }
10740                                         } 
10741                                         else
10742                                         if (cfg->compile_aot) {
10743                                                 NEW_LDSTRCONST (cfg, ins, image, n);
10744                                                 *sp = ins;
10745                                                 MONO_ADD_INS (cfg->cbb, ins);
10746                                         } 
10747                                         else {
10748                                                 NEW_PCONST (cfg, ins, NULL);
10749                                                 ins->type = STACK_OBJ;
10750                                                 ins->inst_p0 = mono_ldstr_checked (cfg->domain, image, mono_metadata_token_index (n), &cfg->error);
10751                                                 CHECK_CFG_ERROR;
10752                                                 
10753                                                 if (!ins->inst_p0)
10754                                                         OUT_OF_MEMORY_FAILURE;
10755
10756                                                 *sp = ins;
10757                                                 MONO_ADD_INS (cfg->cbb, ins);
10758                                         }
10759                                 }
10760                         }
10761
10762                         sp++;
10763                         ip += 5;
10764                         break;
10765                 case CEE_NEWOBJ: {
10766                         MonoInst *iargs [2];
10767                         MonoMethodSignature *fsig;
10768                         MonoInst this_ins;
10769                         MonoInst *alloc;
10770                         MonoInst *vtable_arg = NULL;
10771
10772                         CHECK_OPSIZE (5);
10773                         token = read32 (ip + 1);
10774                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
10775                         CHECK_CFG_ERROR;
10776
10777                         fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
10778                         CHECK_CFG_ERROR;
10779
10780                         mono_save_token_info (cfg, image, token, cmethod);
10781
10782                         if (!mono_class_init (cmethod->klass))
10783                                 TYPE_LOAD_ERROR (cmethod->klass);
10784
10785                         context_used = mini_method_check_context_used (cfg, cmethod);
10786
10787                         if (mono_security_core_clr_enabled ())
10788                                 ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
10789
10790                         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)) {
10791                                 emit_class_init (cfg, cmethod->klass);
10792                                 CHECK_TYPELOAD (cmethod->klass);
10793                         }
10794
10795                         /*
10796                         if (cfg->gsharedvt) {
10797                                 if (mini_is_gsharedvt_variable_signature (sig))
10798                                         GSHAREDVT_FAILURE (*ip);
10799                         }
10800                         */
10801
10802                         n = fsig->param_count;
10803                         CHECK_STACK (n);
10804
10805                         /* 
10806                          * Generate smaller code for the common newobj <exception> instruction in
10807                          * argument checking code.
10808                          */
10809                         if (cfg->cbb->out_of_line && cmethod->klass->image == mono_defaults.corlib &&
10810                                 is_exception_class (cmethod->klass) && n <= 2 &&
10811                                 ((n < 1) || (!fsig->params [0]->byref && fsig->params [0]->type == MONO_TYPE_STRING)) && 
10812                                 ((n < 2) || (!fsig->params [1]->byref && fsig->params [1]->type == MONO_TYPE_STRING))) {
10813                                 MonoInst *iargs [3];
10814
10815                                 sp -= n;
10816
10817                                 EMIT_NEW_ICONST (cfg, iargs [0], cmethod->klass->type_token);
10818                                 switch (n) {
10819                                 case 0:
10820                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_0, iargs);
10821                                         break;
10822                                 case 1:
10823                                         iargs [1] = sp [0];
10824                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_1, iargs);
10825                                         break;
10826                                 case 2:
10827                                         iargs [1] = sp [0];
10828                                         iargs [2] = sp [1];
10829                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_2, iargs);
10830                                         break;
10831                                 default:
10832                                         g_assert_not_reached ();
10833                                 }
10834
10835                                 ip += 5;
10836                                 inline_costs += 5;
10837                                 break;
10838                         }
10839
10840                         /* move the args to allow room for 'this' in the first position */
10841                         while (n--) {
10842                                 --sp;
10843                                 sp [1] = sp [0];
10844                         }
10845
10846                         /* check_call_signature () requires sp[0] to be set */
10847                         this_ins.type = STACK_OBJ;
10848                         sp [0] = &this_ins;
10849                         if (check_call_signature (cfg, fsig, sp))
10850                                 UNVERIFIED;
10851
10852                         iargs [0] = NULL;
10853
10854                         if (mini_class_is_system_array (cmethod->klass)) {
10855                                 *sp = emit_get_rgctx_method (cfg, context_used,
10856                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
10857
10858                                 /* Avoid varargs in the common case */
10859                                 if (fsig->param_count == 1)
10860                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_1, sp);
10861                                 else if (fsig->param_count == 2)
10862                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_2, sp);
10863                                 else if (fsig->param_count == 3)
10864                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_3, sp);
10865                                 else if (fsig->param_count == 4)
10866                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_4, sp);
10867                                 else
10868                                         alloc = handle_array_new (cfg, fsig->param_count, sp, ip);
10869                         } else if (cmethod->string_ctor) {
10870                                 g_assert (!context_used);
10871                                 g_assert (!vtable_arg);
10872                                 /* we simply pass a null pointer */
10873                                 EMIT_NEW_PCONST (cfg, *sp, NULL); 
10874                                 /* now call the string ctor */
10875                                 alloc = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, NULL, NULL, NULL);
10876                         } else {
10877                                 if (cmethod->klass->valuetype) {
10878                                         iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
10879                                         emit_init_rvar (cfg, iargs [0]->dreg, &cmethod->klass->byval_arg);
10880                                         EMIT_NEW_TEMPLOADA (cfg, *sp, iargs [0]->inst_c0);
10881
10882                                         alloc = NULL;
10883
10884                                         /* 
10885                                          * The code generated by mini_emit_virtual_call () expects
10886                                          * iargs [0] to be a boxed instance, but luckily the vcall
10887                                          * will be transformed into a normal call there.
10888                                          */
10889                                 } else if (context_used) {
10890                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, context_used);
10891                                         *sp = alloc;
10892                                 } else {
10893                                         MonoVTable *vtable = NULL;
10894
10895                                         if (!cfg->compile_aot)
10896                                                 vtable = mono_class_vtable (cfg->domain, cmethod->klass);
10897                                         CHECK_TYPELOAD (cmethod->klass);
10898
10899                                         /*
10900                                          * TypeInitializationExceptions thrown from the mono_runtime_class_init
10901                                          * call in mono_jit_runtime_invoke () can abort the finalizer thread.
10902                                          * As a workaround, we call class cctors before allocating objects.
10903                                          */
10904                                         if (mini_field_access_needs_cctor_run (cfg, method, cmethod->klass, vtable) && !(g_slist_find (class_inits, cmethod->klass))) {
10905                                                 emit_class_init (cfg, cmethod->klass);
10906                                                 if (cfg->verbose_level > 2)
10907                                                         printf ("class %s.%s needs init call for ctor\n", cmethod->klass->name_space, cmethod->klass->name);
10908                                                 class_inits = g_slist_prepend (class_inits, cmethod->klass);
10909                                         }
10910
10911                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, 0);
10912                                         *sp = alloc;
10913                                 }
10914                                 CHECK_CFG_EXCEPTION; /*for handle_alloc*/
10915
10916                                 if (alloc)
10917                                         MONO_EMIT_NEW_UNALU (cfg, OP_NOT_NULL, -1, alloc->dreg);
10918
10919                                 /* Now call the actual ctor */
10920                                 handle_ctor_call (cfg, cmethod, fsig, context_used, sp, ip, &inline_costs);
10921                                 CHECK_CFG_EXCEPTION;
10922                         }
10923
10924                         if (alloc == NULL) {
10925                                 /* Valuetype */
10926                                 EMIT_NEW_TEMPLOAD (cfg, ins, iargs [0]->inst_c0);
10927                                 type_to_eval_stack_type (cfg, &ins->klass->byval_arg, ins);
10928                                 *sp++= ins;
10929                         } else {
10930                                 *sp++ = alloc;
10931                         }
10932                         
10933                         ip += 5;
10934                         inline_costs += 5;
10935                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip - header->code)))
10936                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
10937                         break;
10938                 }
10939                 case CEE_CASTCLASS:
10940                 case CEE_ISINST: {
10941                         CHECK_STACK (1);
10942                         --sp;
10943                         CHECK_OPSIZE (5);
10944                         token = read32 (ip + 1);
10945                         klass = mini_get_class (method, token, generic_context);
10946                         CHECK_TYPELOAD (klass);
10947                         if (sp [0]->type != STACK_OBJ)
10948                                 UNVERIFIED;
10949
10950                         MONO_INST_NEW (cfg, ins, *ip == CEE_ISINST ? OP_ISINST : OP_CASTCLASS);
10951                         ins->dreg = alloc_preg (cfg);
10952                         ins->sreg1 = (*sp)->dreg;
10953                         ins->klass = klass;
10954                         ins->type = STACK_OBJ;
10955                         MONO_ADD_INS (cfg->cbb, ins);
10956
10957                         CHECK_CFG_EXCEPTION;
10958                         *sp++ = ins;
10959                         ip += 5;
10960
10961                         cfg->flags |= MONO_CFG_HAS_TYPE_CHECK;
10962                         break;
10963                 }
10964                 case CEE_UNBOX_ANY: {
10965                         MonoInst *res, *addr;
10966
10967                         CHECK_STACK (1);
10968                         --sp;
10969                         CHECK_OPSIZE (5);
10970                         token = read32 (ip + 1);
10971                         klass = mini_get_class (method, token, generic_context);
10972                         CHECK_TYPELOAD (klass);
10973
10974                         mono_save_token_info (cfg, image, token, klass);
10975
10976                         context_used = mini_class_check_context_used (cfg, klass);
10977
10978                         if (mini_is_gsharedvt_klass (klass)) {
10979                                 res = handle_unbox_gsharedvt (cfg, klass, *sp);
10980                                 inline_costs += 2;
10981                         } else if (generic_class_is_reference_type (cfg, klass)) {
10982                                 MONO_INST_NEW (cfg, res, OP_CASTCLASS);
10983                                 res->dreg = alloc_preg (cfg);
10984                                 res->sreg1 = (*sp)->dreg;
10985                                 res->klass = klass;
10986                                 res->type = STACK_OBJ;
10987                                 MONO_ADD_INS (cfg->cbb, res);
10988                                 cfg->flags |= MONO_CFG_HAS_TYPE_CHECK;
10989                         } else if (mono_class_is_nullable (klass)) {
10990                                 res = handle_unbox_nullable (cfg, *sp, klass, context_used);
10991                         } else {
10992                                 addr = handle_unbox (cfg, klass, sp, context_used);
10993                                 /* LDOBJ */
10994                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
10995                                 res = ins;
10996                                 inline_costs += 2;
10997                         }
10998
10999                         *sp ++ = res;
11000                         ip += 5;
11001                         break;
11002                 }
11003                 case CEE_BOX: {
11004                         MonoInst *val;
11005                         MonoClass *enum_class;
11006                         MonoMethod *has_flag;
11007
11008                         CHECK_STACK (1);
11009                         --sp;
11010                         val = *sp;
11011                         CHECK_OPSIZE (5);
11012                         token = read32 (ip + 1);
11013                         klass = mini_get_class (method, token, generic_context);
11014                         CHECK_TYPELOAD (klass);
11015
11016                         mono_save_token_info (cfg, image, token, klass);
11017
11018                         context_used = mini_class_check_context_used (cfg, klass);
11019
11020                         if (generic_class_is_reference_type (cfg, klass)) {
11021                                 *sp++ = val;
11022                                 ip += 5;
11023                                 break;
11024                         }
11025
11026                         if (klass == mono_defaults.void_class)
11027                                 UNVERIFIED;
11028                         if (target_type_is_incompatible (cfg, &klass->byval_arg, *sp))
11029                                 UNVERIFIED;
11030                         /* frequent check in generic code: box (struct), brtrue */
11031
11032                         /*
11033                          * Look for:
11034                          *
11035                          *   <push int/long ptr>
11036                          *   <push int/long>
11037                          *   box MyFlags
11038                          *   constrained. MyFlags
11039                          *   callvirt instace bool class [mscorlib] System.Enum::HasFlag (class [mscorlib] System.Enum)
11040                          *
11041                          * If we find this sequence and the operand types on box and constrained
11042                          * are equal, we can emit a specialized instruction sequence instead of
11043                          * the very slow HasFlag () call.
11044                          */
11045                         if ((cfg->opt & MONO_OPT_INTRINS) &&
11046                             /* Cheap checks first. */
11047                             ip + 5 + 6 + 5 < end &&
11048                             ip [5] == CEE_PREFIX1 &&
11049                             ip [6] == CEE_CONSTRAINED_ &&
11050                             ip [11] == CEE_CALLVIRT &&
11051                             ip_in_bb (cfg, cfg->cbb, ip + 5 + 6 + 5) &&
11052                             mono_class_is_enum (klass) &&
11053                             (enum_class = mini_get_class (method, read32 (ip + 7), generic_context)) &&
11054                             (has_flag = mini_get_method (cfg, method, read32 (ip + 12), NULL, generic_context)) &&
11055                             has_flag->klass == mono_defaults.enum_class &&
11056                             !strcmp (has_flag->name, "HasFlag") &&
11057                             has_flag->signature->hasthis &&
11058                             has_flag->signature->param_count == 1) {
11059                                 CHECK_TYPELOAD (enum_class);
11060
11061                                 if (enum_class == klass) {
11062                                         MonoInst *enum_this, *enum_flag;
11063
11064                                         ip += 5 + 6 + 5;
11065                                         --sp;
11066
11067                                         enum_this = sp [0];
11068                                         enum_flag = sp [1];
11069
11070                                         *sp++ = handle_enum_has_flag (cfg, klass, enum_this, enum_flag);
11071                                         break;
11072                                 }
11073                         }
11074
11075                         // FIXME: LLVM can't handle the inconsistent bb linking
11076                         if (!mono_class_is_nullable (klass) &&
11077                                 !mini_is_gsharedvt_klass (klass) &&
11078                                 ip + 5 < end && ip_in_bb (cfg, cfg->cbb, ip + 5) &&
11079                                 (ip [5] == CEE_BRTRUE || 
11080                                  ip [5] == CEE_BRTRUE_S ||
11081                                  ip [5] == CEE_BRFALSE ||
11082                                  ip [5] == CEE_BRFALSE_S)) {
11083                                 gboolean is_true = ip [5] == CEE_BRTRUE || ip [5] == CEE_BRTRUE_S;
11084                                 int dreg;
11085                                 MonoBasicBlock *true_bb, *false_bb;
11086
11087                                 ip += 5;
11088
11089                                 if (cfg->verbose_level > 3) {
11090                                         printf ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
11091                                         printf ("<box+brtrue opt>\n");
11092                                 }
11093
11094                                 switch (*ip) {
11095                                 case CEE_BRTRUE_S:
11096                                 case CEE_BRFALSE_S:
11097                                         CHECK_OPSIZE (2);
11098                                         ip++;
11099                                         target = ip + 1 + (signed char)(*ip);
11100                                         ip++;
11101                                         break;
11102                                 case CEE_BRTRUE:
11103                                 case CEE_BRFALSE:
11104                                         CHECK_OPSIZE (5);
11105                                         ip++;
11106                                         target = ip + 4 + (gint)(read32 (ip));
11107                                         ip += 4;
11108                                         break;
11109                                 default:
11110                                         g_assert_not_reached ();
11111                                 }
11112
11113                                 /* 
11114                                  * We need to link both bblocks, since it is needed for handling stack
11115                                  * arguments correctly (See test_0_box_brtrue_opt_regress_81102).
11116                                  * Branching to only one of them would lead to inconsistencies, so
11117                                  * generate an ICONST+BRTRUE, the branch opts will get rid of them.
11118                                  */
11119                                 GET_BBLOCK (cfg, true_bb, target);
11120                                 GET_BBLOCK (cfg, false_bb, ip);
11121
11122                                 mono_link_bblock (cfg, cfg->cbb, true_bb);
11123                                 mono_link_bblock (cfg, cfg->cbb, false_bb);
11124
11125                                 if (sp != stack_start) {
11126                                         handle_stack_args (cfg, stack_start, sp - stack_start);
11127                                         sp = stack_start;
11128                                         CHECK_UNVERIFIABLE (cfg);
11129                                 }
11130
11131                                 if (COMPILE_LLVM (cfg)) {
11132                                         dreg = alloc_ireg (cfg);
11133                                         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
11134                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, dreg, is_true ? 0 : 1);
11135
11136                                         MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, OP_IBEQ, true_bb, false_bb);
11137                                 } else {
11138                                         /* The JIT can't eliminate the iconst+compare */
11139                                         MONO_INST_NEW (cfg, ins, OP_BR);
11140                                         ins->inst_target_bb = is_true ? true_bb : false_bb;
11141                                         MONO_ADD_INS (cfg->cbb, ins);
11142                                 }
11143
11144                                 start_new_bblock = 1;
11145                                 break;
11146                         }
11147
11148                         *sp++ = handle_box (cfg, val, klass, context_used);
11149
11150                         CHECK_CFG_EXCEPTION;
11151                         ip += 5;
11152                         inline_costs += 1;
11153                         break;
11154                 }
11155                 case CEE_UNBOX: {
11156                         CHECK_STACK (1);
11157                         --sp;
11158                         CHECK_OPSIZE (5);
11159                         token = read32 (ip + 1);
11160                         klass = mini_get_class (method, token, generic_context);
11161                         CHECK_TYPELOAD (klass);
11162
11163                         mono_save_token_info (cfg, image, token, klass);
11164
11165                         context_used = mini_class_check_context_used (cfg, klass);
11166
11167                         if (mono_class_is_nullable (klass)) {
11168                                 MonoInst *val;
11169
11170                                 val = handle_unbox_nullable (cfg, *sp, klass, context_used);
11171                                 EMIT_NEW_VARLOADA (cfg, ins, get_vreg_to_inst (cfg, val->dreg), &val->klass->byval_arg);
11172
11173                                 *sp++= ins;
11174                         } else {
11175                                 ins = handle_unbox (cfg, klass, sp, context_used);
11176                                 *sp++ = ins;
11177                         }
11178                         ip += 5;
11179                         inline_costs += 2;
11180                         break;
11181                 }
11182                 case CEE_LDFLD:
11183                 case CEE_LDFLDA:
11184                 case CEE_STFLD:
11185                 case CEE_LDSFLD:
11186                 case CEE_LDSFLDA:
11187                 case CEE_STSFLD: {
11188                         MonoClassField *field;
11189 #ifndef DISABLE_REMOTING
11190                         int costs;
11191 #endif
11192                         guint foffset;
11193                         gboolean is_instance;
11194                         int op;
11195                         gpointer addr = NULL;
11196                         gboolean is_special_static;
11197                         MonoType *ftype;
11198                         MonoInst *store_val = NULL;
11199                         MonoInst *thread_ins;
11200
11201                         op = *ip;
11202                         is_instance = (op == CEE_LDFLD || op == CEE_LDFLDA || op == CEE_STFLD);
11203                         if (is_instance) {
11204                                 if (op == CEE_STFLD) {
11205                                         CHECK_STACK (2);
11206                                         sp -= 2;
11207                                         store_val = sp [1];
11208                                 } else {
11209                                         CHECK_STACK (1);
11210                                         --sp;
11211                                 }
11212                                 if (sp [0]->type == STACK_I4 || sp [0]->type == STACK_I8 || sp [0]->type == STACK_R8)
11213                                         UNVERIFIED;
11214                                 if (*ip != CEE_LDFLD && sp [0]->type == STACK_VTYPE)
11215                                         UNVERIFIED;
11216                         } else {
11217                                 if (op == CEE_STSFLD) {
11218                                         CHECK_STACK (1);
11219                                         sp--;
11220                                         store_val = sp [0];
11221                                 }
11222                         }
11223
11224                         CHECK_OPSIZE (5);
11225                         token = read32 (ip + 1);
11226                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
11227                                 field = (MonoClassField *)mono_method_get_wrapper_data (method, token);
11228                                 klass = field->parent;
11229                         }
11230                         else {
11231                                 field = mono_field_from_token_checked (image, token, &klass, generic_context, &cfg->error);
11232                                 CHECK_CFG_ERROR;
11233                         }
11234                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
11235                                 FIELD_ACCESS_FAILURE (method, field);
11236                         mono_class_init (klass);
11237
11238                         /* if the class is Critical then transparent code cannot access it's fields */
11239                         if (!is_instance && mono_security_core_clr_enabled ())
11240                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
11241
11242                         /* XXX this is technically required but, so far (SL2), no [SecurityCritical] types (not many exists) have
11243                            any visible *instance* field  (in fact there's a single case for a static field in Marshal) XXX
11244                         if (mono_security_core_clr_enabled ())
11245                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
11246                         */
11247
11248                         ftype = mono_field_get_type (field);
11249
11250                         /*
11251                          * LDFLD etc. is usable on static fields as well, so convert those cases to
11252                          * the static case.
11253                          */
11254                         if (is_instance && ftype->attrs & FIELD_ATTRIBUTE_STATIC) {
11255                                 switch (op) {
11256                                 case CEE_LDFLD:
11257                                         op = CEE_LDSFLD;
11258                                         break;
11259                                 case CEE_STFLD:
11260                                         op = CEE_STSFLD;
11261                                         break;
11262                                 case CEE_LDFLDA:
11263                                         op = CEE_LDSFLDA;
11264                                         break;
11265                                 default:
11266                                         g_assert_not_reached ();
11267                                 }
11268                                 is_instance = FALSE;
11269                         }
11270
11271                         context_used = mini_class_check_context_used (cfg, klass);
11272
11273                         /* INSTANCE CASE */
11274
11275                         foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
11276                         if (op == CEE_STFLD) {
11277                                 if (target_type_is_incompatible (cfg, field->type, sp [1]))
11278                                         UNVERIFIED;
11279 #ifndef DISABLE_REMOTING
11280                                 if ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class) {
11281                                         MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type); 
11282                                         MonoInst *iargs [5];
11283
11284                                         GSHAREDVT_FAILURE (op);
11285
11286                                         iargs [0] = sp [0];
11287                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11288                                         EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
11289                                         EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : 
11290                                                     field->offset);
11291                                         iargs [4] = sp [1];
11292
11293                                         if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
11294                                                 costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), 
11295                                                                                            iargs, ip, cfg->real_offset, TRUE);
11296                                                 CHECK_CFG_EXCEPTION;
11297                                                 g_assert (costs > 0);
11298                                                       
11299                                                 cfg->real_offset += 5;
11300
11301                                                 inline_costs += costs;
11302                                         } else {
11303                                                 mono_emit_method_call (cfg, stfld_wrapper, iargs, NULL);
11304                                         }
11305                                 } else
11306 #endif
11307                                 {
11308                                         MonoInst *store, *wbarrier_ptr_ins = NULL;
11309
11310                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
11311
11312                                         if (mini_is_gsharedvt_klass (klass)) {
11313                                                 MonoInst *offset_ins;
11314
11315                                                 context_used = mini_class_check_context_used (cfg, klass);
11316
11317                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11318                                                 /* The value is offset by 1 */
11319                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
11320                                                 dreg = alloc_ireg_mp (cfg);
11321                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11322                                                 wbarrier_ptr_ins = ins;
11323                                                 /* The decomposition will call mini_emit_stobj () which will emit a wbarrier if needed */
11324                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, dreg, 0, sp [1]->dreg);
11325                                         } else {
11326                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, sp [0]->dreg, foffset, sp [1]->dreg);
11327                                         }
11328                                         if (sp [0]->opcode != OP_LDADDR)
11329                                                 store->flags |= MONO_INST_FAULT;
11330
11331                                         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)) {
11332                                                 if (mini_is_gsharedvt_klass (klass)) {
11333                                                         g_assert (wbarrier_ptr_ins);
11334                                                         emit_write_barrier (cfg, wbarrier_ptr_ins, sp [1]);
11335                                                 } else {
11336                                                         /* insert call to write barrier */
11337                                                         MonoInst *ptr;
11338                                                         int dreg;
11339
11340                                                         dreg = alloc_ireg_mp (cfg);
11341                                                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
11342                                                         emit_write_barrier (cfg, ptr, sp [1]);
11343                                                 }
11344                                         }
11345
11346                                         store->flags |= ins_flag;
11347                                 }
11348                                 ins_flag = 0;
11349                                 ip += 5;
11350                                 break;
11351                         }
11352
11353 #ifndef DISABLE_REMOTING
11354                         if (is_instance && ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class)) {
11355                                 MonoMethod *wrapper = (op == CEE_LDFLDA) ? mono_marshal_get_ldflda_wrapper (field->type) : mono_marshal_get_ldfld_wrapper (field->type); 
11356                                 MonoInst *iargs [4];
11357
11358                                 GSHAREDVT_FAILURE (op);
11359
11360                                 iargs [0] = sp [0];
11361                                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11362                                 EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
11363                                 EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
11364                                 if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
11365                                         costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), 
11366                                                                                    iargs, ip, cfg->real_offset, TRUE);
11367                                         CHECK_CFG_EXCEPTION;
11368                                         g_assert (costs > 0);
11369                                                       
11370                                         cfg->real_offset += 5;
11371
11372                                         *sp++ = iargs [0];
11373
11374                                         inline_costs += costs;
11375                                 } else {
11376                                         ins = mono_emit_method_call (cfg, wrapper, iargs, NULL);
11377                                         *sp++ = ins;
11378                                 }
11379                         } else 
11380 #endif
11381                         if (is_instance) {
11382                                 if (sp [0]->type == STACK_VTYPE) {
11383                                         MonoInst *var;
11384
11385                                         /* Have to compute the address of the variable */
11386
11387                                         var = get_vreg_to_inst (cfg, sp [0]->dreg);
11388                                         if (!var)
11389                                                 var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, sp [0]->dreg);
11390                                         else
11391                                                 g_assert (var->klass == klass);
11392                                         
11393                                         EMIT_NEW_VARLOADA (cfg, ins, var, &var->klass->byval_arg);
11394                                         sp [0] = ins;
11395                                 }
11396
11397                                 if (op == CEE_LDFLDA) {
11398                                         if (sp [0]->type == STACK_OBJ) {
11399                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
11400                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "NullReferenceException");
11401                                         }
11402
11403                                         dreg = alloc_ireg_mp (cfg);
11404
11405                                         if (mini_is_gsharedvt_klass (klass)) {
11406                                                 MonoInst *offset_ins;
11407
11408                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11409                                                 /* The value is offset by 1 */
11410                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
11411                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11412                                         } else {
11413                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
11414                                         }
11415                                         ins->klass = mono_class_from_mono_type (field->type);
11416                                         ins->type = STACK_MP;
11417                                         *sp++ = ins;
11418                                 } else {
11419                                         MonoInst *load;
11420
11421                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
11422
11423                                         if (mini_is_gsharedvt_klass (klass)) {
11424                                                 MonoInst *offset_ins;
11425
11426                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11427                                                 /* The value is offset by 1 */
11428                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
11429                                                 dreg = alloc_ireg_mp (cfg);
11430                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11431                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, dreg, 0);
11432                                         } else {
11433                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, sp [0]->dreg, foffset);
11434                                         }
11435                                         load->flags |= ins_flag;
11436                                         if (sp [0]->opcode != OP_LDADDR)
11437                                                 load->flags |= MONO_INST_FAULT;
11438                                         *sp++ = load;
11439                                 }
11440                         }
11441
11442                         if (is_instance) {
11443                                 ins_flag = 0;
11444                                 ip += 5;
11445                                 break;
11446                         }
11447
11448                         /* STATIC CASE */
11449                         context_used = mini_class_check_context_used (cfg, klass);
11450
11451                         if (ftype->attrs & FIELD_ATTRIBUTE_LITERAL) {
11452                                 mono_error_set_field_load (&cfg->error, field->parent, field->name, "Using static instructions with literal field");
11453                                 CHECK_CFG_ERROR;
11454                         }
11455
11456                         /* The special_static_fields field is init'd in mono_class_vtable, so it needs
11457                          * to be called here.
11458                          */
11459                         if (!context_used && !(cfg->opt & MONO_OPT_SHARED)) {
11460                                 mono_class_vtable (cfg->domain, klass);
11461                                 CHECK_TYPELOAD (klass);
11462                         }
11463                         mono_domain_lock (cfg->domain);
11464                         if (cfg->domain->special_static_fields)
11465                                 addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
11466                         mono_domain_unlock (cfg->domain);
11467
11468                         is_special_static = mono_class_field_is_special_static (field);
11469
11470                         if (is_special_static && ((gsize)addr & 0x80000000) == 0)
11471                                 thread_ins = mono_get_thread_intrinsic (cfg);
11472                         else
11473                                 thread_ins = NULL;
11474
11475                         /* Generate IR to compute the field address */
11476                         if (is_special_static && ((gsize)addr & 0x80000000) == 0 && thread_ins && !(cfg->opt & MONO_OPT_SHARED) && !context_used) {
11477                                 /*
11478                                  * Fast access to TLS data
11479                                  * Inline version of get_thread_static_data () in
11480                                  * threads.c.
11481                                  */
11482                                 guint32 offset;
11483                                 int idx, static_data_reg, array_reg, dreg;
11484
11485                                 GSHAREDVT_FAILURE (op);
11486
11487                                 MONO_ADD_INS (cfg->cbb, thread_ins);
11488                                 static_data_reg = alloc_ireg (cfg);
11489                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, MONO_STRUCT_OFFSET (MonoInternalThread, static_data));
11490
11491                                 if (cfg->compile_aot) {
11492                                         int offset_reg, offset2_reg, idx_reg;
11493
11494                                         /* For TLS variables, this will return the TLS offset */
11495                                         EMIT_NEW_SFLDACONST (cfg, ins, field);
11496                                         offset_reg = ins->dreg;
11497                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset_reg, offset_reg, 0x7fffffff);
11498                                         idx_reg = alloc_ireg (cfg);
11499                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, idx_reg, offset_reg, 0x3f);
11500                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
11501                                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
11502                                         array_reg = alloc_ireg (cfg);
11503                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
11504                                         offset2_reg = alloc_ireg (cfg);
11505                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, offset2_reg, offset_reg, 6);
11506                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset2_reg, 0x1ffffff);
11507                                         dreg = alloc_ireg (cfg);
11508                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, array_reg, offset2_reg);
11509                                 } else {
11510                                         offset = (gsize)addr & 0x7fffffff;
11511                                         idx = offset & 0x3f;
11512
11513                                         array_reg = alloc_ireg (cfg);
11514                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, idx * sizeof (gpointer));
11515                                         dreg = alloc_ireg (cfg);
11516                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_ADD_IMM, dreg, array_reg, ((offset >> 6) & 0x1ffffff));
11517                                 }
11518                         } else if ((cfg->opt & MONO_OPT_SHARED) ||
11519                                         (cfg->compile_aot && is_special_static) ||
11520                                         (context_used && is_special_static)) {
11521                                 MonoInst *iargs [2];
11522
11523                                 g_assert (field->parent);
11524                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11525                                 if (context_used) {
11526                                         iargs [1] = emit_get_rgctx_field (cfg, context_used,
11527                                                 field, MONO_RGCTX_INFO_CLASS_FIELD);
11528                                 } else {
11529                                         EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
11530                                 }
11531                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
11532                         } else if (context_used) {
11533                                 MonoInst *static_data;
11534
11535                                 /*
11536                                 g_print ("sharing static field access in %s.%s.%s - depth %d offset %d\n",
11537                                         method->klass->name_space, method->klass->name, method->name,
11538                                         depth, field->offset);
11539                                 */
11540
11541                                 if (mono_class_needs_cctor_run (klass, method))
11542                                         emit_class_init (cfg, klass);
11543
11544                                 /*
11545                                  * The pointer we're computing here is
11546                                  *
11547                                  *   super_info.static_data + field->offset
11548                                  */
11549                                 static_data = emit_get_rgctx_klass (cfg, context_used,
11550                                         klass, MONO_RGCTX_INFO_STATIC_DATA);
11551
11552                                 if (mini_is_gsharedvt_klass (klass)) {
11553                                         MonoInst *offset_ins;
11554
11555                                         offset_ins = emit_get_rgctx_field (cfg, context_used, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11556                                         /* The value is offset by 1 */
11557                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
11558                                         dreg = alloc_ireg_mp (cfg);
11559                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, static_data->dreg, offset_ins->dreg);
11560                                 } else if (field->offset == 0) {
11561                                         ins = static_data;
11562                                 } else {
11563                                         int addr_reg = mono_alloc_preg (cfg);
11564                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, addr_reg, static_data->dreg, field->offset);
11565                                 }
11566                                 } else if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
11567                                 MonoInst *iargs [2];
11568
11569                                 g_assert (field->parent);
11570                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11571                                 EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
11572                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
11573                         } else {
11574                                 MonoVTable *vtable = NULL;
11575
11576                                 if (!cfg->compile_aot)
11577                                         vtable = mono_class_vtable (cfg->domain, klass);
11578                                 CHECK_TYPELOAD (klass);
11579
11580                                 if (!addr) {
11581                                         if (mini_field_access_needs_cctor_run (cfg, method, klass, vtable)) {
11582                                                 if (!(g_slist_find (class_inits, klass))) {
11583                                                         emit_class_init (cfg, klass);
11584                                                         if (cfg->verbose_level > 2)
11585                                                                 printf ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, mono_field_get_name (field));
11586                                                         class_inits = g_slist_prepend (class_inits, klass);
11587                                                 }
11588                                         } else {
11589                                                 if (cfg->run_cctors) {
11590                                                         /* This makes so that inline cannot trigger */
11591                                                         /* .cctors: too many apps depend on them */
11592                                                         /* running with a specific order... */
11593                                                         g_assert (vtable);
11594                                                         if (! vtable->initialized)
11595                                                                 INLINE_FAILURE ("class init");
11596                                                         if (!mono_runtime_class_init_full (vtable, &cfg->error)) {
11597                                                                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
11598                                                                 goto exception_exit;
11599                                                         }
11600                                                 }
11601                                         }
11602                                         if (cfg->compile_aot)
11603                                                 EMIT_NEW_SFLDACONST (cfg, ins, field);
11604                                         else {
11605                                                 g_assert (vtable);
11606                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11607                                                 g_assert (addr);
11608                                                 EMIT_NEW_PCONST (cfg, ins, addr);
11609                                         }
11610                                 } else {
11611                                         MonoInst *iargs [1];
11612                                         EMIT_NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
11613                                         ins = mono_emit_jit_icall (cfg, mono_get_special_static_data, iargs);
11614                                 }
11615                         }
11616
11617                         /* Generate IR to do the actual load/store operation */
11618
11619                         if ((op == CEE_STFLD || op == CEE_STSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11620                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11621                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11622                         }
11623
11624                         if (op == CEE_LDSFLDA) {
11625                                 ins->klass = mono_class_from_mono_type (ftype);
11626                                 ins->type = STACK_PTR;
11627                                 *sp++ = ins;
11628                         } else if (op == CEE_STSFLD) {
11629                                 MonoInst *store;
11630
11631                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, ftype, ins->dreg, 0, store_val->dreg);
11632                                 store->flags |= ins_flag;
11633                         } else {
11634                                 gboolean is_const = FALSE;
11635                                 MonoVTable *vtable = NULL;
11636                                 gpointer addr = NULL;
11637
11638                                 if (!context_used) {
11639                                         vtable = mono_class_vtable (cfg->domain, klass);
11640                                         CHECK_TYPELOAD (klass);
11641                                 }
11642                                 if ((ftype->attrs & FIELD_ATTRIBUTE_INIT_ONLY) && (((addr = mono_aot_readonly_field_override (field)) != NULL) ||
11643                                                 (!context_used && !((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && vtable->initialized))) {
11644                                         int ro_type = ftype->type;
11645                                         if (!addr)
11646                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11647                                         if (ro_type == MONO_TYPE_VALUETYPE && ftype->data.klass->enumtype) {
11648                                                 ro_type = mono_class_enum_basetype (ftype->data.klass)->type;
11649                                         }
11650
11651                                         GSHAREDVT_FAILURE (op);
11652
11653                                         /* printf ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, mono_field_get_name (field));*/
11654                                         is_const = TRUE;
11655                                         switch (ro_type) {
11656                                         case MONO_TYPE_BOOLEAN:
11657                                         case MONO_TYPE_U1:
11658                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint8 *)addr));
11659                                                 sp++;
11660                                                 break;
11661                                         case MONO_TYPE_I1:
11662                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint8 *)addr));
11663                                                 sp++;
11664                                                 break;                                          
11665                                         case MONO_TYPE_CHAR:
11666                                         case MONO_TYPE_U2:
11667                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint16 *)addr));
11668                                                 sp++;
11669                                                 break;
11670                                         case MONO_TYPE_I2:
11671                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint16 *)addr));
11672                                                 sp++;
11673                                                 break;
11674                                                 break;
11675                                         case MONO_TYPE_I4:
11676                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint32 *)addr));
11677                                                 sp++;
11678                                                 break;                                          
11679                                         case MONO_TYPE_U4:
11680                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint32 *)addr));
11681                                                 sp++;
11682                                                 break;
11683                                         case MONO_TYPE_I:
11684                                         case MONO_TYPE_U:
11685                                         case MONO_TYPE_PTR:
11686                                         case MONO_TYPE_FNPTR:
11687                                                 EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11688                                                 type_to_eval_stack_type ((cfg), field->type, *sp);
11689                                                 sp++;
11690                                                 break;
11691                                         case MONO_TYPE_STRING:
11692                                         case MONO_TYPE_OBJECT:
11693                                         case MONO_TYPE_CLASS:
11694                                         case MONO_TYPE_SZARRAY:
11695                                         case MONO_TYPE_ARRAY:
11696                                                 if (!mono_gc_is_moving ()) {
11697                                                         EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11698                                                         type_to_eval_stack_type ((cfg), field->type, *sp);
11699                                                         sp++;
11700                                                 } else {
11701                                                         is_const = FALSE;
11702                                                 }
11703                                                 break;
11704                                         case MONO_TYPE_I8:
11705                                         case MONO_TYPE_U8:
11706                                                 EMIT_NEW_I8CONST (cfg, *sp, *((gint64 *)addr));
11707                                                 sp++;
11708                                                 break;
11709                                         case MONO_TYPE_R4:
11710                                         case MONO_TYPE_R8:
11711                                         case MONO_TYPE_VALUETYPE:
11712                                         default:
11713                                                 is_const = FALSE;
11714                                                 break;
11715                                         }
11716                                 }
11717
11718                                 if (!is_const) {
11719                                         MonoInst *load;
11720
11721                                         CHECK_STACK_OVF (1);
11722
11723                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, ins->dreg, 0);
11724                                         load->flags |= ins_flag;
11725                                         ins_flag = 0;
11726                                         *sp++ = load;
11727                                 }
11728                         }
11729
11730                         if ((op == CEE_LDFLD || op == CEE_LDSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11731                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
11732                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
11733                         }
11734
11735                         ins_flag = 0;
11736                         ip += 5;
11737                         break;
11738                 }
11739                 case CEE_STOBJ:
11740                         CHECK_STACK (2);
11741                         sp -= 2;
11742                         CHECK_OPSIZE (5);
11743                         token = read32 (ip + 1);
11744                         klass = mini_get_class (method, token, generic_context);
11745                         CHECK_TYPELOAD (klass);
11746                         if (ins_flag & MONO_INST_VOLATILE) {
11747                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11748                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11749                         }
11750                         /* FIXME: should check item at sp [1] is compatible with the type of the store. */
11751                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0, sp [1]->dreg);
11752                         ins->flags |= ins_flag;
11753                         if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER &&
11754                                         generic_class_is_reference_type (cfg, klass)) {
11755                                 /* insert call to write barrier */
11756                                 emit_write_barrier (cfg, sp [0], sp [1]);
11757                         }
11758                         ins_flag = 0;
11759                         ip += 5;
11760                         inline_costs += 1;
11761                         break;
11762
11763                         /*
11764                          * Array opcodes
11765                          */
11766                 case CEE_NEWARR: {
11767                         MonoInst *len_ins;
11768                         const char *data_ptr;
11769                         int data_size = 0;
11770                         guint32 field_token;
11771
11772                         CHECK_STACK (1);
11773                         --sp;
11774
11775                         CHECK_OPSIZE (5);
11776                         token = read32 (ip + 1);
11777
11778                         klass = mini_get_class (method, token, generic_context);
11779                         CHECK_TYPELOAD (klass);
11780
11781                         context_used = mini_class_check_context_used (cfg, klass);
11782
11783                         if (sp [0]->type == STACK_I8 || (SIZEOF_VOID_P == 8 && sp [0]->type == STACK_PTR)) {
11784                                 MONO_INST_NEW (cfg, ins, OP_LCONV_TO_OVF_U4);
11785                                 ins->sreg1 = sp [0]->dreg;
11786                                 ins->type = STACK_I4;
11787                                 ins->dreg = alloc_ireg (cfg);
11788                                 MONO_ADD_INS (cfg->cbb, ins);
11789                                 *sp = mono_decompose_opcode (cfg, ins);
11790                         }
11791
11792                         if (context_used) {
11793                                 MonoInst *args [3];
11794                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11795                                 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
11796
11797                                 /* FIXME: Use OP_NEWARR and decompose later to help abcrem */
11798
11799                                 /* vtable */
11800                                 args [0] = emit_get_rgctx_klass (cfg, context_used,
11801                                         array_class, MONO_RGCTX_INFO_VTABLE);
11802                                 /* array len */
11803                                 args [1] = sp [0];
11804
11805                                 if (managed_alloc)
11806                                         ins = mono_emit_method_call (cfg, managed_alloc, args, NULL);
11807                                 else
11808                                         ins = mono_emit_jit_icall (cfg, ves_icall_array_new_specific, args);
11809                         } else {
11810                                 if (cfg->opt & MONO_OPT_SHARED) {
11811                                         /* Decompose now to avoid problems with references to the domainvar */
11812                                         MonoInst *iargs [3];
11813
11814                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11815                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11816                                         iargs [2] = sp [0];
11817
11818                                         ins = mono_emit_jit_icall (cfg, ves_icall_array_new, iargs);
11819                                 } else {
11820                                         /* Decompose later since it is needed by abcrem */
11821                                         MonoClass *array_type = mono_array_class_get (klass, 1);
11822                                         mono_class_vtable (cfg->domain, array_type);
11823                                         CHECK_TYPELOAD (array_type);
11824
11825                                         MONO_INST_NEW (cfg, ins, OP_NEWARR);
11826                                         ins->dreg = alloc_ireg_ref (cfg);
11827                                         ins->sreg1 = sp [0]->dreg;
11828                                         ins->inst_newa_class = klass;
11829                                         ins->type = STACK_OBJ;
11830                                         ins->klass = array_type;
11831                                         MONO_ADD_INS (cfg->cbb, ins);
11832                                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11833                                         cfg->cbb->has_array_access = TRUE;
11834
11835                                         /* Needed so mono_emit_load_get_addr () gets called */
11836                                         mono_get_got_var (cfg);
11837                                 }
11838                         }
11839
11840                         len_ins = sp [0];
11841                         ip += 5;
11842                         *sp++ = ins;
11843                         inline_costs += 1;
11844
11845                         /* 
11846                          * we inline/optimize the initialization sequence if possible.
11847                          * we should also allocate the array as not cleared, since we spend as much time clearing to 0 as initializing
11848                          * for small sizes open code the memcpy
11849                          * ensure the rva field is big enough
11850                          */
11851                         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))) {
11852                                 MonoMethod *memcpy_method = get_memcpy_method ();
11853                                 MonoInst *iargs [3];
11854                                 int add_reg = alloc_ireg_mp (cfg);
11855
11856                                 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, add_reg, ins->dreg, MONO_STRUCT_OFFSET (MonoArray, vector));
11857                                 if (cfg->compile_aot) {
11858                                         EMIT_NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(field_token), STACK_PTR, NULL);
11859                                 } else {
11860                                         EMIT_NEW_PCONST (cfg, iargs [1], (char*)data_ptr);
11861                                 }
11862                                 EMIT_NEW_ICONST (cfg, iargs [2], data_size);
11863                                 mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
11864                                 ip += 11;
11865                         }
11866
11867                         break;
11868                 }
11869                 case CEE_LDLEN:
11870                         CHECK_STACK (1);
11871                         --sp;
11872                         if (sp [0]->type != STACK_OBJ)
11873                                 UNVERIFIED;
11874
11875                         MONO_INST_NEW (cfg, ins, OP_LDLEN);
11876                         ins->dreg = alloc_preg (cfg);
11877                         ins->sreg1 = sp [0]->dreg;
11878                         ins->type = STACK_I4;
11879                         /* This flag will be inherited by the decomposition */
11880                         ins->flags |= MONO_INST_FAULT;
11881                         MONO_ADD_INS (cfg->cbb, ins);
11882                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11883                         cfg->cbb->has_array_access = TRUE;
11884                         ip ++;
11885                         *sp++ = ins;
11886                         break;
11887                 case CEE_LDELEMA:
11888                         CHECK_STACK (2);
11889                         sp -= 2;
11890                         CHECK_OPSIZE (5);
11891                         if (sp [0]->type != STACK_OBJ)
11892                                 UNVERIFIED;
11893
11894                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11895
11896                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11897                         CHECK_TYPELOAD (klass);
11898                         /* we need to make sure that this array is exactly the type it needs
11899                          * to be for correctness. the wrappers are lax with their usage
11900                          * so we need to ignore them here
11901                          */
11902                         if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE && !readonly) {
11903                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11904                                 mini_emit_check_array_type (cfg, sp [0], array_class);
11905                                 CHECK_TYPELOAD (array_class);
11906                         }
11907
11908                         readonly = FALSE;
11909                         ins = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11910                         *sp++ = ins;
11911                         ip += 5;
11912                         break;
11913                 case CEE_LDELEM:
11914                 case CEE_LDELEM_I1:
11915                 case CEE_LDELEM_U1:
11916                 case CEE_LDELEM_I2:
11917                 case CEE_LDELEM_U2:
11918                 case CEE_LDELEM_I4:
11919                 case CEE_LDELEM_U4:
11920                 case CEE_LDELEM_I8:
11921                 case CEE_LDELEM_I:
11922                 case CEE_LDELEM_R4:
11923                 case CEE_LDELEM_R8:
11924                 case CEE_LDELEM_REF: {
11925                         MonoInst *addr;
11926
11927                         CHECK_STACK (2);
11928                         sp -= 2;
11929
11930                         if (*ip == CEE_LDELEM) {
11931                                 CHECK_OPSIZE (5);
11932                                 token = read32 (ip + 1);
11933                                 klass = mini_get_class (method, token, generic_context);
11934                                 CHECK_TYPELOAD (klass);
11935                                 mono_class_init (klass);
11936                         }
11937                         else
11938                                 klass = array_access_to_klass (*ip);
11939
11940                         if (sp [0]->type != STACK_OBJ)
11941                                 UNVERIFIED;
11942
11943                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11944
11945                         if (mini_is_gsharedvt_variable_klass (klass)) {
11946                                 // FIXME-VT: OP_ICONST optimization
11947                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11948                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11949                                 ins->opcode = OP_LOADV_MEMBASE;
11950                         } else if (sp [1]->opcode == OP_ICONST) {
11951                                 int array_reg = sp [0]->dreg;
11952                                 int index_reg = sp [1]->dreg;
11953                                 int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
11954
11955                                 if (SIZEOF_REGISTER == 8 && COMPILE_LLVM (cfg))
11956                                         MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, index_reg, index_reg);
11957
11958                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
11959                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset);
11960                         } else {
11961                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11962                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11963                         }
11964                         *sp++ = ins;
11965                         if (*ip == CEE_LDELEM)
11966                                 ip += 5;
11967                         else
11968                                 ++ip;
11969                         break;
11970                 }
11971                 case CEE_STELEM_I:
11972                 case CEE_STELEM_I1:
11973                 case CEE_STELEM_I2:
11974                 case CEE_STELEM_I4:
11975                 case CEE_STELEM_I8:
11976                 case CEE_STELEM_R4:
11977                 case CEE_STELEM_R8:
11978                 case CEE_STELEM_REF:
11979                 case CEE_STELEM: {
11980                         CHECK_STACK (3);
11981                         sp -= 3;
11982
11983                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11984
11985                         if (*ip == CEE_STELEM) {
11986                                 CHECK_OPSIZE (5);
11987                                 token = read32 (ip + 1);
11988                                 klass = mini_get_class (method, token, generic_context);
11989                                 CHECK_TYPELOAD (klass);
11990                                 mono_class_init (klass);
11991                         }
11992                         else
11993                                 klass = array_access_to_klass (*ip);
11994
11995                         if (sp [0]->type != STACK_OBJ)
11996                                 UNVERIFIED;
11997
11998                         emit_array_store (cfg, klass, sp, TRUE);
11999
12000                         if (*ip == CEE_STELEM)
12001                                 ip += 5;
12002                         else
12003                                 ++ip;
12004                         inline_costs += 1;
12005                         break;
12006                 }
12007                 case CEE_CKFINITE: {
12008                         CHECK_STACK (1);
12009                         --sp;
12010
12011                         if (cfg->llvm_only) {
12012                                 MonoInst *iargs [1];
12013
12014                                 iargs [0] = sp [0];
12015                                 *sp++ = mono_emit_jit_icall (cfg, mono_ckfinite, iargs);
12016                         } else  {
12017                                 MONO_INST_NEW (cfg, ins, OP_CKFINITE);
12018                                 ins->sreg1 = sp [0]->dreg;
12019                                 ins->dreg = alloc_freg (cfg);
12020                                 ins->type = STACK_R8;
12021                                 MONO_ADD_INS (cfg->cbb, ins);
12022
12023                                 *sp++ = mono_decompose_opcode (cfg, ins);
12024                         }
12025
12026                         ++ip;
12027                         break;
12028                 }
12029                 case CEE_REFANYVAL: {
12030                         MonoInst *src_var, *src;
12031
12032                         int klass_reg = alloc_preg (cfg);
12033                         int dreg = alloc_preg (cfg);
12034
12035                         GSHAREDVT_FAILURE (*ip);
12036
12037                         CHECK_STACK (1);
12038                         MONO_INST_NEW (cfg, ins, *ip);
12039                         --sp;
12040                         CHECK_OPSIZE (5);
12041                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
12042                         CHECK_TYPELOAD (klass);
12043
12044                         context_used = mini_class_check_context_used (cfg, klass);
12045
12046                         // FIXME:
12047                         src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
12048                         if (!src_var)
12049                                 src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
12050                         EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
12051                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass));
12052
12053                         if (context_used) {
12054                                 MonoInst *klass_ins;
12055
12056                                 klass_ins = emit_get_rgctx_klass (cfg, context_used,
12057                                                 klass, MONO_RGCTX_INFO_KLASS);
12058
12059                                 // FIXME:
12060                                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_ins->dreg);
12061                                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
12062                         } else {
12063                                 mini_emit_class_check (cfg, klass_reg, klass);
12064                         }
12065                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value));
12066                         ins->type = STACK_MP;
12067                         ins->klass = klass;
12068                         *sp++ = ins;
12069                         ip += 5;
12070                         break;
12071                 }
12072                 case CEE_MKREFANY: {
12073                         MonoInst *loc, *addr;
12074
12075                         GSHAREDVT_FAILURE (*ip);
12076
12077                         CHECK_STACK (1);
12078                         MONO_INST_NEW (cfg, ins, *ip);
12079                         --sp;
12080                         CHECK_OPSIZE (5);
12081                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
12082                         CHECK_TYPELOAD (klass);
12083
12084                         context_used = mini_class_check_context_used (cfg, klass);
12085
12086                         loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
12087                         EMIT_NEW_TEMPLOADA (cfg, addr, loc->inst_c0);
12088
12089                         if (context_used) {
12090                                 MonoInst *const_ins;
12091                                 int type_reg = alloc_preg (cfg);
12092
12093                                 const_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
12094                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_ins->dreg);
12095                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_ins->dreg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
12096                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
12097                         } else if (cfg->compile_aot) {
12098                                 int const_reg = alloc_preg (cfg);
12099                                 int type_reg = alloc_preg (cfg);
12100
12101                                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
12102                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_reg);
12103                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_reg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
12104                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
12105                         } else {
12106                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), &klass->byval_arg);
12107                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), klass);
12108                         }
12109                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value), sp [0]->dreg);
12110
12111                         EMIT_NEW_TEMPLOAD (cfg, ins, loc->inst_c0);
12112                         ins->type = STACK_VTYPE;
12113                         ins->klass = mono_defaults.typed_reference_class;
12114                         *sp++ = ins;
12115                         ip += 5;
12116                         break;
12117                 }
12118                 case CEE_LDTOKEN: {
12119                         gpointer handle;
12120                         MonoClass *handle_class;
12121
12122                         CHECK_STACK_OVF (1);
12123
12124                         CHECK_OPSIZE (5);
12125                         n = read32 (ip + 1);
12126
12127                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD ||
12128                                         method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
12129                                 handle = mono_method_get_wrapper_data (method, n);
12130                                 handle_class = (MonoClass *)mono_method_get_wrapper_data (method, n + 1);
12131                                 if (handle_class == mono_defaults.typehandle_class)
12132                                         handle = &((MonoClass*)handle)->byval_arg;
12133                         }
12134                         else {
12135                                 handle = mono_ldtoken_checked (image, n, &handle_class, generic_context, &cfg->error);
12136                                 CHECK_CFG_ERROR;
12137                         }
12138                         if (!handle)
12139                                 LOAD_ERROR;
12140                         mono_class_init (handle_class);
12141                         if (cfg->gshared) {
12142                                 if (mono_metadata_token_table (n) == MONO_TABLE_TYPEDEF ||
12143                                                 mono_metadata_token_table (n) == MONO_TABLE_TYPEREF) {
12144                                         /* This case handles ldtoken
12145                                            of an open type, like for
12146                                            typeof(Gen<>). */
12147                                         context_used = 0;
12148                                 } else if (handle_class == mono_defaults.typehandle_class) {
12149                                         context_used = mini_class_check_context_used (cfg, mono_class_from_mono_type ((MonoType *)handle));
12150                                 } else if (handle_class == mono_defaults.fieldhandle_class)
12151                                         context_used = mini_class_check_context_used (cfg, ((MonoClassField*)handle)->parent);
12152                                 else if (handle_class == mono_defaults.methodhandle_class)
12153                                         context_used = mini_method_check_context_used (cfg, (MonoMethod *)handle);
12154                                 else
12155                                         g_assert_not_reached ();
12156                         }
12157
12158                         if ((cfg->opt & MONO_OPT_SHARED) &&
12159                                         method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD &&
12160                                         method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED) {
12161                                 MonoInst *addr, *vtvar, *iargs [3];
12162                                 int method_context_used;
12163
12164                                 method_context_used = mini_method_check_context_used (cfg, method);
12165
12166                                 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL); 
12167
12168                                 EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
12169                                 EMIT_NEW_ICONST (cfg, iargs [1], n);
12170                                 if (method_context_used) {
12171                                         iargs [2] = emit_get_rgctx_method (cfg, method_context_used,
12172                                                 method, MONO_RGCTX_INFO_METHOD);
12173                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper_generic_shared, iargs);
12174                                 } else {
12175                                         EMIT_NEW_PCONST (cfg, iargs [2], generic_context);
12176                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper, iargs);
12177                                 }
12178                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
12179
12180                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
12181
12182                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
12183                         } else {
12184                                 if ((ip + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 5) && 
12185                                         ((ip [5] == CEE_CALL) || (ip [5] == CEE_CALLVIRT)) && 
12186                                         (cmethod = mini_get_method (cfg, method, read32 (ip + 6), NULL, generic_context)) &&
12187                                         (cmethod->klass == mono_defaults.systemtype_class) &&
12188                                         (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
12189                                         MonoClass *tclass = mono_class_from_mono_type ((MonoType *)handle);
12190
12191                                         mono_class_init (tclass);
12192                                         if (context_used) {
12193                                                 ins = emit_get_rgctx_klass (cfg, context_used,
12194                                                         tclass, MONO_RGCTX_INFO_REFLECTION_TYPE);
12195                                         } else if (cfg->compile_aot) {
12196                                                 if (method->wrapper_type) {
12197                                                         mono_error_init (&error); //got to do it since there are multiple conditionals below
12198                                                         if (mono_class_get_checked (tclass->image, tclass->type_token, &error) == tclass && !generic_context) {
12199                                                                 /* Special case for static synchronized wrappers */
12200                                                                 EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, tclass->image, tclass->type_token, generic_context);
12201                                                         } else {
12202                                                                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
12203                                                                 /* FIXME: n is not a normal token */
12204                                                                 DISABLE_AOT (cfg);
12205                                                                 EMIT_NEW_PCONST (cfg, ins, NULL);
12206                                                         }
12207                                                 } else {
12208                                                         EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n, generic_context);
12209                                                 }
12210                                         } else {
12211                                                 MonoReflectionType *rt = mono_type_get_object_checked (cfg->domain, (MonoType *)handle, &cfg->error);
12212                                                 CHECK_CFG_ERROR;
12213                                                 EMIT_NEW_PCONST (cfg, ins, rt);
12214                                         }
12215                                         ins->type = STACK_OBJ;
12216                                         ins->klass = cmethod->klass;
12217                                         ip += 5;
12218                                 } else {
12219                                         MonoInst *addr, *vtvar;
12220
12221                                         vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
12222
12223                                         if (context_used) {
12224                                                 if (handle_class == mono_defaults.typehandle_class) {
12225                                                         ins = emit_get_rgctx_klass (cfg, context_used,
12226                                                                         mono_class_from_mono_type ((MonoType *)handle),
12227                                                                         MONO_RGCTX_INFO_TYPE);
12228                                                 } else if (handle_class == mono_defaults.methodhandle_class) {
12229                                                         ins = emit_get_rgctx_method (cfg, context_used,
12230                                                                         (MonoMethod *)handle, MONO_RGCTX_INFO_METHOD);
12231                                                 } else if (handle_class == mono_defaults.fieldhandle_class) {
12232                                                         ins = emit_get_rgctx_field (cfg, context_used,
12233                                                                         (MonoClassField *)handle, MONO_RGCTX_INFO_CLASS_FIELD);
12234                                                 } else {
12235                                                         g_assert_not_reached ();
12236                                                 }
12237                                         } else if (cfg->compile_aot) {
12238                                                 EMIT_NEW_LDTOKENCONST (cfg, ins, image, n, generic_context);
12239                                         } else {
12240                                                 EMIT_NEW_PCONST (cfg, ins, handle);
12241                                         }
12242                                         EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
12243                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
12244                                         EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
12245                                 }
12246                         }
12247
12248                         *sp++ = ins;
12249                         ip += 5;
12250                         break;
12251                 }
12252                 case CEE_THROW:
12253                         CHECK_STACK (1);
12254                         MONO_INST_NEW (cfg, ins, OP_THROW);
12255                         --sp;
12256                         ins->sreg1 = sp [0]->dreg;
12257                         ip++;
12258                         cfg->cbb->out_of_line = TRUE;
12259                         MONO_ADD_INS (cfg->cbb, ins);
12260                         MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
12261                         MONO_ADD_INS (cfg->cbb, ins);
12262                         sp = stack_start;
12263                         
12264                         link_bblock (cfg, cfg->cbb, end_bblock);
12265                         start_new_bblock = 1;
12266                         /* This can complicate code generation for llvm since the return value might not be defined */
12267                         if (COMPILE_LLVM (cfg))
12268                                 INLINE_FAILURE ("throw");
12269                         break;
12270                 case CEE_ENDFINALLY:
12271                         /* mono_save_seq_point_info () depends on this */
12272                         if (sp != stack_start)
12273                                 emit_seq_point (cfg, method, ip, FALSE, FALSE);
12274                         MONO_INST_NEW (cfg, ins, OP_ENDFINALLY);
12275                         MONO_ADD_INS (cfg->cbb, ins);
12276                         ip++;
12277                         start_new_bblock = 1;
12278
12279                         /*
12280                          * Control will leave the method so empty the stack, otherwise
12281                          * the next basic block will start with a nonempty stack.
12282                          */
12283                         while (sp != stack_start) {
12284                                 sp--;
12285                         }
12286                         break;
12287                 case CEE_LEAVE:
12288                 case CEE_LEAVE_S: {
12289                         GList *handlers;
12290
12291                         if (*ip == CEE_LEAVE) {
12292                                 CHECK_OPSIZE (5);
12293                                 target = ip + 5 + (gint32)read32(ip + 1);
12294                         } else {
12295                                 CHECK_OPSIZE (2);
12296                                 target = ip + 2 + (signed char)(ip [1]);
12297                         }
12298
12299                         /* empty the stack */
12300                         while (sp != stack_start) {
12301                                 sp--;
12302                         }
12303
12304                         /* 
12305                          * If this leave statement is in a catch block, check for a
12306                          * pending exception, and rethrow it if necessary.
12307                          * We avoid doing this in runtime invoke wrappers, since those are called
12308                          * by native code which excepts the wrapper to catch all exceptions.
12309                          */
12310                         for (i = 0; i < header->num_clauses; ++i) {
12311                                 MonoExceptionClause *clause = &header->clauses [i];
12312
12313                                 /* 
12314                                  * Use <= in the final comparison to handle clauses with multiple
12315                                  * leave statements, like in bug #78024.
12316                                  * The ordering of the exception clauses guarantees that we find the
12317                                  * innermost clause.
12318                                  */
12319                                 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) {
12320                                         MonoInst *exc_ins;
12321                                         MonoBasicBlock *dont_throw;
12322
12323                                         /*
12324                                           MonoInst *load;
12325
12326                                           NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, clause->handler_offset)->inst_c0);
12327                                         */
12328
12329                                         exc_ins = mono_emit_jit_icall (cfg, mono_thread_get_undeniable_exception, NULL);
12330
12331                                         NEW_BBLOCK (cfg, dont_throw);
12332
12333                                         /*
12334                                          * Currently, we always rethrow the abort exception, despite the 
12335                                          * fact that this is not correct. See thread6.cs for an example. 
12336                                          * But propagating the abort exception is more important than 
12337                                          * getting the sematics right.
12338                                          */
12339                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, exc_ins->dreg, 0);
12340                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, dont_throw);
12341                                         MONO_EMIT_NEW_UNALU (cfg, OP_THROW, -1, exc_ins->dreg);
12342
12343                                         MONO_START_BB (cfg, dont_throw);
12344                                 }
12345                         }
12346
12347 #ifdef ENABLE_LLVM
12348                         cfg->cbb->try_end = (intptr_t)(ip - header->code);
12349 #endif
12350
12351                         if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
12352                                 GList *tmp;
12353                                 MonoExceptionClause *clause;
12354
12355                                 for (tmp = handlers; tmp; tmp = tmp->next) {
12356                                         clause = (MonoExceptionClause *)tmp->data;
12357                                         tblock = cfg->cil_offset_to_bb [clause->handler_offset];
12358                                         g_assert (tblock);
12359                                         link_bblock (cfg, cfg->cbb, tblock);
12360                                         MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
12361                                         ins->inst_target_bb = tblock;
12362                                         ins->inst_eh_block = clause;
12363                                         MONO_ADD_INS (cfg->cbb, ins);
12364                                         cfg->cbb->has_call_handler = 1;
12365                                         if (COMPILE_LLVM (cfg)) {
12366                                                 MonoBasicBlock *target_bb;
12367
12368                                                 /* 
12369                                                  * Link the finally bblock with the target, since it will
12370                                                  * conceptually branch there.
12371                                                  */
12372                                                 GET_BBLOCK (cfg, tblock, cfg->cil_start + clause->handler_offset + clause->handler_len - 1);
12373                                                 GET_BBLOCK (cfg, target_bb, target);
12374                                                 link_bblock (cfg, tblock, target_bb);
12375                                         }
12376                                 }
12377                                 g_list_free (handlers);
12378                         } 
12379
12380                         MONO_INST_NEW (cfg, ins, OP_BR);
12381                         MONO_ADD_INS (cfg->cbb, ins);
12382                         GET_BBLOCK (cfg, tblock, target);
12383                         link_bblock (cfg, cfg->cbb, tblock);
12384                         ins->inst_target_bb = tblock;
12385
12386                         start_new_bblock = 1;
12387
12388                         if (*ip == CEE_LEAVE)
12389                                 ip += 5;
12390                         else
12391                                 ip += 2;
12392
12393                         break;
12394                 }
12395
12396                         /*
12397                          * Mono specific opcodes
12398                          */
12399                 case MONO_CUSTOM_PREFIX: {
12400
12401                         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
12402
12403                         CHECK_OPSIZE (2);
12404                         switch (ip [1]) {
12405                         case CEE_MONO_ICALL: {
12406                                 gpointer func;
12407                                 MonoJitICallInfo *info;
12408
12409                                 token = read32 (ip + 2);
12410                                 func = mono_method_get_wrapper_data (method, token);
12411                                 info = mono_find_jit_icall_by_addr (func);
12412                                 if (!info)
12413                                         g_error ("Could not find icall address in wrapper %s", mono_method_full_name (method, 1));
12414                                 g_assert (info);
12415
12416                                 CHECK_STACK (info->sig->param_count);
12417                                 sp -= info->sig->param_count;
12418
12419                                 ins = mono_emit_jit_icall (cfg, info->func, sp);
12420                                 if (!MONO_TYPE_IS_VOID (info->sig->ret))
12421                                         *sp++ = ins;
12422
12423                                 ip += 6;
12424                                 inline_costs += 10 * num_calls++;
12425
12426                                 break;
12427                         }
12428                         case CEE_MONO_LDPTR_CARD_TABLE:
12429                         case CEE_MONO_LDPTR_NURSERY_START:
12430                         case CEE_MONO_LDPTR_NURSERY_BITS:
12431                         case CEE_MONO_LDPTR_INT_REQ_FLAG: {
12432                                 CHECK_STACK_OVF (1);
12433
12434                                 switch (ip [1]) {
12435                                         case CEE_MONO_LDPTR_CARD_TABLE:
12436                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR, NULL);
12437                                                 break;
12438                                         case CEE_MONO_LDPTR_NURSERY_START:
12439                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_NURSERY_START, NULL);
12440                                                 break;
12441                                         case CEE_MONO_LDPTR_NURSERY_BITS:
12442                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_NURSERY_BITS, NULL);
12443                                                 break;
12444                                         case CEE_MONO_LDPTR_INT_REQ_FLAG:
12445                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG, NULL);
12446                                                 break;
12447                                 }
12448
12449                                 *sp++ = ins;
12450                                 ip += 2;
12451                                 inline_costs += 10 * num_calls++;
12452                                 break;
12453                         }
12454                         case CEE_MONO_LDPTR: {
12455                                 gpointer ptr;
12456
12457                                 CHECK_STACK_OVF (1);
12458                                 CHECK_OPSIZE (6);
12459                                 token = read32 (ip + 2);
12460
12461                                 ptr = mono_method_get_wrapper_data (method, token);
12462                                 EMIT_NEW_PCONST (cfg, ins, ptr);
12463                                 *sp++ = ins;
12464                                 ip += 6;
12465                                 inline_costs += 10 * num_calls++;
12466                                 /* Can't embed random pointers into AOT code */
12467                                 DISABLE_AOT (cfg);
12468                                 break;
12469                         }
12470                         case CEE_MONO_JIT_ICALL_ADDR: {
12471                                 MonoJitICallInfo *callinfo;
12472                                 gpointer ptr;
12473
12474                                 CHECK_STACK_OVF (1);
12475                                 CHECK_OPSIZE (6);
12476                                 token = read32 (ip + 2);
12477
12478                                 ptr = mono_method_get_wrapper_data (method, token);
12479                                 callinfo = mono_find_jit_icall_by_addr (ptr);
12480                                 g_assert (callinfo);
12481                                 EMIT_NEW_JIT_ICALL_ADDRCONST (cfg, ins, (char*)callinfo->name);
12482                                 *sp++ = ins;
12483                                 ip += 6;
12484                                 inline_costs += 10 * num_calls++;
12485                                 break;
12486                         }
12487                         case CEE_MONO_ICALL_ADDR: {
12488                                 MonoMethod *cmethod;
12489                                 gpointer ptr;
12490
12491                                 CHECK_STACK_OVF (1);
12492                                 CHECK_OPSIZE (6);
12493                                 token = read32 (ip + 2);
12494
12495                                 cmethod = (MonoMethod *)mono_method_get_wrapper_data (method, token);
12496
12497                                 if (cfg->compile_aot) {
12498                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, cmethod);
12499                                 } else {
12500                                         ptr = mono_lookup_internal_call (cmethod);
12501                                         g_assert (ptr);
12502                                         EMIT_NEW_PCONST (cfg, ins, ptr);
12503                                 }
12504                                 *sp++ = ins;
12505                                 ip += 6;
12506                                 break;
12507                         }
12508                         case CEE_MONO_VTADDR: {
12509                                 MonoInst *src_var, *src;
12510
12511                                 CHECK_STACK (1);
12512                                 --sp;
12513
12514                                 // FIXME:
12515                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
12516                                 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
12517                                 *sp++ = src;
12518                                 ip += 2;
12519                                 break;
12520                         }
12521                         case CEE_MONO_NEWOBJ: {
12522                                 MonoInst *iargs [2];
12523
12524                                 CHECK_STACK_OVF (1);
12525                                 CHECK_OPSIZE (6);
12526                                 token = read32 (ip + 2);
12527                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12528                                 mono_class_init (klass);
12529                                 NEW_DOMAINCONST (cfg, iargs [0]);
12530                                 MONO_ADD_INS (cfg->cbb, iargs [0]);
12531                                 NEW_CLASSCONST (cfg, iargs [1], klass);
12532                                 MONO_ADD_INS (cfg->cbb, iargs [1]);
12533                                 *sp++ = mono_emit_jit_icall (cfg, ves_icall_object_new, iargs);
12534                                 ip += 6;
12535                                 inline_costs += 10 * num_calls++;
12536                                 break;
12537                         }
12538                         case CEE_MONO_OBJADDR:
12539                                 CHECK_STACK (1);
12540                                 --sp;
12541                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
12542                                 ins->dreg = alloc_ireg_mp (cfg);
12543                                 ins->sreg1 = sp [0]->dreg;
12544                                 ins->type = STACK_MP;
12545                                 MONO_ADD_INS (cfg->cbb, ins);
12546                                 *sp++ = ins;
12547                                 ip += 2;
12548                                 break;
12549                         case CEE_MONO_LDNATIVEOBJ:
12550                                 /*
12551                                  * Similar to LDOBJ, but instead load the unmanaged 
12552                                  * representation of the vtype to the stack.
12553                                  */
12554                                 CHECK_STACK (1);
12555                                 CHECK_OPSIZE (6);
12556                                 --sp;
12557                                 token = read32 (ip + 2);
12558                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12559                                 g_assert (klass->valuetype);
12560                                 mono_class_init (klass);
12561
12562                                 {
12563                                         MonoInst *src, *dest, *temp;
12564
12565                                         src = sp [0];
12566                                         temp = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
12567                                         temp->backend.is_pinvoke = 1;
12568                                         EMIT_NEW_TEMPLOADA (cfg, dest, temp->inst_c0);
12569                                         mini_emit_stobj (cfg, dest, src, klass, TRUE);
12570
12571                                         EMIT_NEW_TEMPLOAD (cfg, dest, temp->inst_c0);
12572                                         dest->type = STACK_VTYPE;
12573                                         dest->klass = klass;
12574
12575                                         *sp ++ = dest;
12576                                         ip += 6;
12577                                 }
12578                                 break;
12579                         case CEE_MONO_RETOBJ: {
12580                                 /*
12581                                  * Same as RET, but return the native representation of a vtype
12582                                  * to the caller.
12583                                  */
12584                                 g_assert (cfg->ret);
12585                                 g_assert (mono_method_signature (method)->pinvoke); 
12586                                 CHECK_STACK (1);
12587                                 --sp;
12588                                 
12589                                 CHECK_OPSIZE (6);
12590                                 token = read32 (ip + 2);    
12591                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12592
12593                                 if (!cfg->vret_addr) {
12594                                         g_assert (cfg->ret_var_is_local);
12595
12596                                         EMIT_NEW_VARLOADA (cfg, ins, cfg->ret, cfg->ret->inst_vtype);
12597                                 } else {
12598                                         EMIT_NEW_RETLOADA (cfg, ins);
12599                                 }
12600                                 mini_emit_stobj (cfg, ins, sp [0], klass, TRUE);
12601                                 
12602                                 if (sp != stack_start)
12603                                         UNVERIFIED;
12604                                 
12605                                 MONO_INST_NEW (cfg, ins, OP_BR);
12606                                 ins->inst_target_bb = end_bblock;
12607                                 MONO_ADD_INS (cfg->cbb, ins);
12608                                 link_bblock (cfg, cfg->cbb, end_bblock);
12609                                 start_new_bblock = 1;
12610                                 ip += 6;
12611                                 break;
12612                         }
12613                         case CEE_MONO_CISINST:
12614                         case CEE_MONO_CCASTCLASS: {
12615                                 int token;
12616                                 CHECK_STACK (1);
12617                                 --sp;
12618                                 CHECK_OPSIZE (6);
12619                                 token = read32 (ip + 2);
12620                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12621                                 if (ip [1] == CEE_MONO_CISINST)
12622                                         ins = handle_cisinst (cfg, klass, sp [0]);
12623                                 else
12624                                         ins = handle_ccastclass (cfg, klass, sp [0]);
12625                                 *sp++ = ins;
12626                                 ip += 6;
12627                                 break;
12628                         }
12629                         case CEE_MONO_SAVE_LMF:
12630                         case CEE_MONO_RESTORE_LMF:
12631                                 ip += 2;
12632                                 break;
12633                         case CEE_MONO_CLASSCONST:
12634                                 CHECK_STACK_OVF (1);
12635                                 CHECK_OPSIZE (6);
12636                                 token = read32 (ip + 2);
12637                                 EMIT_NEW_CLASSCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
12638                                 *sp++ = ins;
12639                                 ip += 6;
12640                                 inline_costs += 10 * num_calls++;
12641                                 break;
12642                         case CEE_MONO_NOT_TAKEN:
12643                                 cfg->cbb->out_of_line = TRUE;
12644                                 ip += 2;
12645                                 break;
12646                         case CEE_MONO_TLS: {
12647                                 MonoTlsKey key;
12648
12649                                 CHECK_STACK_OVF (1);
12650                                 CHECK_OPSIZE (6);
12651                                 key = (MonoTlsKey)read32 (ip + 2);
12652                                 g_assert (key < TLS_KEY_NUM);
12653
12654                                 ins = mono_create_tls_get (cfg, key);
12655                                 if (!ins) {
12656                                         if (cfg->compile_aot) {
12657                                                 DISABLE_AOT (cfg);
12658                                                 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
12659                                                 ins->dreg = alloc_preg (cfg);
12660                                                 ins->type = STACK_PTR;
12661                                         } else {
12662                                                 g_assert_not_reached ();
12663                                         }
12664                                 }
12665                                 ins->type = STACK_PTR;
12666                                 MONO_ADD_INS (cfg->cbb, ins);
12667                                 *sp++ = ins;
12668                                 ip += 6;
12669                                 break;
12670                         }
12671                         case CEE_MONO_DYN_CALL: {
12672                                 MonoCallInst *call;
12673
12674                                 /* It would be easier to call a trampoline, but that would put an
12675                                  * extra frame on the stack, confusing exception handling. So
12676                                  * implement it inline using an opcode for now.
12677                                  */
12678
12679                                 if (!cfg->dyn_call_var) {
12680                                         cfg->dyn_call_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12681                                         /* prevent it from being register allocated */
12682                                         cfg->dyn_call_var->flags |= MONO_INST_VOLATILE;
12683                                 }
12684
12685                                 /* Has to use a call inst since it local regalloc expects it */
12686                                 MONO_INST_NEW_CALL (cfg, call, OP_DYN_CALL);
12687                                 ins = (MonoInst*)call;
12688                                 sp -= 2;
12689                                 ins->sreg1 = sp [0]->dreg;
12690                                 ins->sreg2 = sp [1]->dreg;
12691                                 MONO_ADD_INS (cfg->cbb, ins);
12692
12693                                 cfg->param_area = MAX (cfg->param_area, cfg->backend->dyn_call_param_area);
12694
12695                                 ip += 2;
12696                                 inline_costs += 10 * num_calls++;
12697
12698                                 break;
12699                         }
12700                         case CEE_MONO_MEMORY_BARRIER: {
12701                                 CHECK_OPSIZE (6);
12702                                 emit_memory_barrier (cfg, (int)read32 (ip + 2));
12703                                 ip += 6;
12704                                 break;
12705                         }
12706                         case CEE_MONO_ATOMIC_STORE_I4: {
12707                                 g_assert (mono_arch_opcode_supported (OP_ATOMIC_STORE_I4));
12708
12709                                 CHECK_OPSIZE (6);
12710                                 CHECK_STACK (2);
12711                                 sp -= 2;
12712
12713                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_STORE_I4);
12714                                 ins->dreg = sp [0]->dreg;
12715                                 ins->sreg1 = sp [1]->dreg;
12716                                 ins->backend.memory_barrier_kind = (int) read32 (ip + 2);
12717                                 MONO_ADD_INS (cfg->cbb, ins);
12718
12719                                 ip += 6;
12720                                 break;
12721                         }
12722                         case CEE_MONO_JIT_ATTACH: {
12723                                 MonoInst *args [16], *domain_ins;
12724                                 MonoInst *ad_ins, *jit_tls_ins;
12725                                 MonoBasicBlock *next_bb = NULL, *call_bb = NULL;
12726
12727                                 g_assert (!mono_threads_is_coop_enabled ());
12728
12729                                 cfg->orig_domain_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12730
12731                                 EMIT_NEW_PCONST (cfg, ins, NULL);
12732                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12733
12734                                 ad_ins = mono_get_domain_intrinsic (cfg);
12735                                 jit_tls_ins = mono_get_jit_tls_intrinsic (cfg);
12736
12737                                 if (cfg->backend->have_tls_get && ad_ins && jit_tls_ins) {
12738                                         NEW_BBLOCK (cfg, next_bb);
12739                                         NEW_BBLOCK (cfg, call_bb);
12740
12741                                         if (cfg->compile_aot) {
12742                                                 /* AOT code is only used in the root domain */
12743                                                 EMIT_NEW_PCONST (cfg, domain_ins, NULL);
12744                                         } else {
12745                                                 EMIT_NEW_PCONST (cfg, domain_ins, cfg->domain);
12746                                         }
12747                                         MONO_ADD_INS (cfg->cbb, ad_ins);
12748                                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, ad_ins->dreg, domain_ins->dreg);
12749                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, call_bb);
12750
12751                                         MONO_ADD_INS (cfg->cbb, jit_tls_ins);
12752                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, jit_tls_ins->dreg, 0);
12753                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, call_bb);
12754
12755                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, next_bb);
12756                                         MONO_START_BB (cfg, call_bb);
12757                                 }
12758
12759                                 /* AOT code is only used in the root domain */
12760                                 EMIT_NEW_PCONST (cfg, args [0], cfg->compile_aot ? NULL : cfg->domain);
12761                                 ins = mono_emit_jit_icall (cfg, mono_jit_thread_attach, args);
12762                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12763
12764                                 if (next_bb)
12765                                         MONO_START_BB (cfg, next_bb);
12766
12767
12768                                 ip += 2;
12769                                 break;
12770                         }
12771                         case CEE_MONO_JIT_DETACH: {
12772                                 MonoInst *args [16];
12773
12774                                 /* Restore the original domain */
12775                                 dreg = alloc_ireg (cfg);
12776                                 EMIT_NEW_UNALU (cfg, args [0], OP_MOVE, dreg, cfg->orig_domain_var->dreg);
12777                                 mono_emit_jit_icall (cfg, mono_jit_set_domain, args);
12778                                 ip += 2;
12779                                 break;
12780                         }
12781                         case CEE_MONO_CALLI_EXTRA_ARG: {
12782                                 MonoInst *addr;
12783                                 MonoMethodSignature *fsig;
12784                                 MonoInst *arg;
12785
12786                                 /*
12787                                  * This is the same as CEE_CALLI, but passes an additional argument
12788                                  * to the called method in llvmonly mode.
12789                                  * This is only used by delegate invoke wrappers to call the
12790                                  * actual delegate method.
12791                                  */
12792                                 g_assert (method->wrapper_type == MONO_WRAPPER_DELEGATE_INVOKE);
12793
12794                                 CHECK_OPSIZE (6);
12795                                 token = read32 (ip + 2);
12796
12797                                 ins = NULL;
12798
12799                                 cmethod = NULL;
12800                                 CHECK_STACK (1);
12801                                 --sp;
12802                                 addr = *sp;
12803                                 fsig = mini_get_signature (method, token, generic_context, &cfg->error);
12804                                 CHECK_CFG_ERROR;
12805
12806                                 if (cfg->llvm_only)
12807                                         cfg->signatures = g_slist_prepend_mempool (cfg->mempool, cfg->signatures, fsig);
12808
12809                                 n = fsig->param_count + fsig->hasthis + 1;
12810
12811                                 CHECK_STACK (n);
12812
12813                                 sp -= n;
12814                                 arg = sp [n - 1];
12815
12816                                 if (cfg->llvm_only) {
12817                                         /*
12818                                          * The lowest bit of 'arg' determines whenever the callee uses the gsharedvt
12819                                          * cconv. This is set by mono_init_delegate ().
12820                                          */
12821                                         if (cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig)) {
12822                                                 MonoInst *callee = addr;
12823                                                 MonoInst *call, *localloc_ins;
12824                                                 MonoBasicBlock *is_gsharedvt_bb, *end_bb;
12825                                                 int low_bit_reg = alloc_preg (cfg);
12826
12827                                                 NEW_BBLOCK (cfg, is_gsharedvt_bb);
12828                                                 NEW_BBLOCK (cfg, end_bb);
12829
12830                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, low_bit_reg, arg->dreg, 1);
12831                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_bit_reg, 0);
12832                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, is_gsharedvt_bb);
12833
12834                                                 /* Normal case: callee uses a normal cconv, have to add an out wrapper */
12835                                                 addr = emit_get_rgctx_sig (cfg, context_used,
12836                                                                                                    fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
12837                                                 /*
12838                                                  * ADDR points to a gsharedvt-out wrapper, have to pass <callee, arg> as an extra arg.
12839                                                  */
12840                                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
12841                                                 ins->dreg = alloc_preg (cfg);
12842                                                 ins->inst_imm = 2 * SIZEOF_VOID_P;
12843                                                 MONO_ADD_INS (cfg->cbb, ins);
12844                                                 localloc_ins = ins;
12845                                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12846                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, 0, callee->dreg);
12847                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, SIZEOF_VOID_P, arg->dreg);
12848
12849                                                 call = emit_extra_arg_calli (cfg, fsig, sp, localloc_ins->dreg, addr);
12850                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12851
12852                                                 /* Gsharedvt case: callee uses a gsharedvt cconv, no conversion is needed */
12853                                                 MONO_START_BB (cfg, is_gsharedvt_bb);
12854                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PXOR_IMM, arg->dreg, arg->dreg, 1);
12855                                                 ins = emit_extra_arg_calli (cfg, fsig, sp, arg->dreg, callee);
12856                                                 ins->dreg = call->dreg;
12857
12858                                                 MONO_START_BB (cfg, end_bb);
12859                                         } else {
12860                                                 /* Caller uses a normal calling conv */
12861
12862                                                 MonoInst *callee = addr;
12863                                                 MonoInst *call, *localloc_ins;
12864                                                 MonoBasicBlock *is_gsharedvt_bb, *end_bb;
12865                                                 int low_bit_reg = alloc_preg (cfg);
12866
12867                                                 NEW_BBLOCK (cfg, is_gsharedvt_bb);
12868                                                 NEW_BBLOCK (cfg, end_bb);
12869
12870                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, low_bit_reg, arg->dreg, 1);
12871                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_bit_reg, 0);
12872                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, is_gsharedvt_bb);
12873
12874                                                 /* Normal case: callee uses a normal cconv, no conversion is needed */
12875                                                 call = emit_extra_arg_calli (cfg, fsig, sp, arg->dreg, callee);
12876                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12877                                                 /* Gsharedvt case: callee uses a gsharedvt cconv, have to add an in wrapper */
12878                                                 MONO_START_BB (cfg, is_gsharedvt_bb);
12879                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PXOR_IMM, arg->dreg, arg->dreg, 1);
12880                                                 NEW_AOTCONST (cfg, addr, MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER, fsig);
12881                                                 MONO_ADD_INS (cfg->cbb, addr);
12882                                                 /*
12883                                                  * ADDR points to a gsharedvt-in wrapper, have to pass <callee, arg> as an extra arg.
12884                                                  */
12885                                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
12886                                                 ins->dreg = alloc_preg (cfg);
12887                                                 ins->inst_imm = 2 * SIZEOF_VOID_P;
12888                                                 MONO_ADD_INS (cfg->cbb, ins);
12889                                                 localloc_ins = ins;
12890                                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12891                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, 0, callee->dreg);
12892                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, SIZEOF_VOID_P, arg->dreg);
12893
12894                                                 ins = emit_extra_arg_calli (cfg, fsig, sp, localloc_ins->dreg, addr);
12895                                                 ins->dreg = call->dreg;
12896                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12897
12898                                                 MONO_START_BB (cfg, end_bb);
12899                                         }
12900                                 } else {
12901                                         /* Same as CEE_CALLI */
12902                                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
12903                                                 /*
12904                                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
12905                                                  */
12906                                                 MonoInst *callee = addr;
12907
12908                                                 addr = emit_get_rgctx_sig (cfg, context_used,
12909                                                                                                    fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
12910                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
12911                                         } else {
12912                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
12913                                         }
12914                                 }
12915
12916                                 if (!MONO_TYPE_IS_VOID (fsig->ret))
12917                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
12918
12919                                 CHECK_CFG_EXCEPTION;
12920
12921                                 ip += 6;
12922                                 ins_flag = 0;
12923                                 constrained_class = NULL;
12924                                 break;
12925                         }
12926                         case CEE_MONO_LDDOMAIN:
12927                                 CHECK_STACK_OVF (1);
12928                                 EMIT_NEW_PCONST (cfg, ins, cfg->compile_aot ? NULL : cfg->domain);
12929                                 ip += 2;
12930                                 *sp++ = ins;
12931                                 break;
12932                         default:
12933                                 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
12934                                 break;
12935                         }
12936                         break;
12937                 }
12938
12939                 case CEE_PREFIX1: {
12940                         CHECK_OPSIZE (2);
12941                         switch (ip [1]) {
12942                         case CEE_ARGLIST: {
12943                                 /* somewhat similar to LDTOKEN */
12944                                 MonoInst *addr, *vtvar;
12945                                 CHECK_STACK_OVF (1);
12946                                 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL); 
12947
12948                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
12949                                 EMIT_NEW_UNALU (cfg, ins, OP_ARGLIST, -1, addr->dreg);
12950
12951                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
12952                                 ins->type = STACK_VTYPE;
12953                                 ins->klass = mono_defaults.argumenthandle_class;
12954                                 *sp++ = ins;
12955                                 ip += 2;
12956                                 break;
12957                         }
12958                         case CEE_CEQ:
12959                         case CEE_CGT:
12960                         case CEE_CGT_UN:
12961                         case CEE_CLT:
12962                         case CEE_CLT_UN: {
12963                                 MonoInst *cmp, *arg1, *arg2;
12964
12965                                 CHECK_STACK (2);
12966                                 sp -= 2;
12967                                 arg1 = sp [0];
12968                                 arg2 = sp [1];
12969
12970                                 /*
12971                                  * The following transforms:
12972                                  *    CEE_CEQ    into OP_CEQ
12973                                  *    CEE_CGT    into OP_CGT
12974                                  *    CEE_CGT_UN into OP_CGT_UN
12975                                  *    CEE_CLT    into OP_CLT
12976                                  *    CEE_CLT_UN into OP_CLT_UN
12977                                  */
12978                                 MONO_INST_NEW (cfg, cmp, (OP_CEQ - CEE_CEQ) + ip [1]);
12979
12980                                 MONO_INST_NEW (cfg, ins, cmp->opcode);
12981                                 cmp->sreg1 = arg1->dreg;
12982                                 cmp->sreg2 = arg2->dreg;
12983                                 type_from_op (cfg, cmp, arg1, arg2);
12984                                 CHECK_TYPE (cmp);
12985                                 add_widen_op (cfg, cmp, &arg1, &arg2);
12986                                 if ((arg1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((arg1->type == STACK_PTR) || (arg1->type == STACK_OBJ) || (arg1->type == STACK_MP))))
12987                                         cmp->opcode = OP_LCOMPARE;
12988                                 else if (arg1->type == STACK_R4)
12989                                         cmp->opcode = OP_RCOMPARE;
12990                                 else if (arg1->type == STACK_R8)
12991                                         cmp->opcode = OP_FCOMPARE;
12992                                 else
12993                                         cmp->opcode = OP_ICOMPARE;
12994                                 MONO_ADD_INS (cfg->cbb, cmp);
12995                                 ins->type = STACK_I4;
12996                                 ins->dreg = alloc_dreg (cfg, (MonoStackType)ins->type);
12997                                 type_from_op (cfg, ins, arg1, arg2);
12998
12999                                 if (cmp->opcode == OP_FCOMPARE || cmp->opcode == OP_RCOMPARE) {
13000                                         /*
13001                                          * The backends expect the fceq opcodes to do the
13002                                          * comparison too.
13003                                          */
13004                                         ins->sreg1 = cmp->sreg1;
13005                                         ins->sreg2 = cmp->sreg2;
13006                                         NULLIFY_INS (cmp);
13007                                 }
13008                                 MONO_ADD_INS (cfg->cbb, ins);
13009                                 *sp++ = ins;
13010                                 ip += 2;
13011                                 break;
13012                         }
13013                         case CEE_LDFTN: {
13014                                 MonoInst *argconst;
13015                                 MonoMethod *cil_method;
13016
13017                                 CHECK_STACK_OVF (1);
13018                                 CHECK_OPSIZE (6);
13019                                 n = read32 (ip + 2);
13020                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
13021                                 CHECK_CFG_ERROR;
13022
13023                                 mono_class_init (cmethod->klass);
13024
13025                                 mono_save_token_info (cfg, image, n, cmethod);
13026
13027                                 context_used = mini_method_check_context_used (cfg, cmethod);
13028
13029                                 cil_method = cmethod;
13030                                 if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
13031                                         emit_method_access_failure (cfg, method, cil_method);
13032
13033                                 if (mono_security_core_clr_enabled ())
13034                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
13035
13036                                 /* 
13037                                  * Optimize the common case of ldftn+delegate creation
13038                                  */
13039                                 if ((sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 6) && (ip [6] == CEE_NEWOBJ)) {
13040                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
13041                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
13042                                                 MonoInst *target_ins, *handle_ins;
13043                                                 MonoMethod *invoke;
13044                                                 int invoke_context_used;
13045
13046                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
13047                                                 if (!invoke || !mono_method_signature (invoke))
13048                                                         LOAD_ERROR;
13049
13050                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
13051
13052                                                 target_ins = sp [-1];
13053
13054                                                 if (mono_security_core_clr_enabled ())
13055                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
13056
13057                                                 if (!(cmethod->flags & METHOD_ATTRIBUTE_STATIC)) {
13058                                                         /*LAME IMPL: We must not add a null check for virtual invoke delegates.*/
13059                                                         if (mono_method_signature (invoke)->param_count == mono_method_signature (cmethod)->param_count) {
13060                                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, target_ins->dreg, 0);
13061                                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "ArgumentException");
13062                                                         }
13063                                                 }
13064
13065                                                 /* FIXME: SGEN support */
13066                                                 if (invoke_context_used == 0 || cfg->llvm_only) {
13067                                                         ip += 6;
13068                                                         if (cfg->verbose_level > 3)
13069                                                                 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));
13070                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, FALSE))) {
13071                                                                 sp --;
13072                                                                 *sp = handle_ins;
13073                                                                 CHECK_CFG_EXCEPTION;
13074                                                                 ip += 5;
13075                                                                 sp ++;
13076                                                                 break;
13077                                                         }
13078                                                         ip -= 6;
13079                                                 }
13080                                         }
13081                                 }
13082
13083                                 argconst = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD);
13084                                 ins = mono_emit_jit_icall (cfg, mono_ldftn, &argconst);
13085                                 *sp++ = ins;
13086                                 
13087                                 ip += 6;
13088                                 inline_costs += 10 * num_calls++;
13089                                 break;
13090                         }
13091                         case CEE_LDVIRTFTN: {
13092                                 MonoInst *args [2];
13093
13094                                 CHECK_STACK (1);
13095                                 CHECK_OPSIZE (6);
13096                                 n = read32 (ip + 2);
13097                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
13098                                 CHECK_CFG_ERROR;
13099
13100                                 mono_class_init (cmethod->klass);
13101  
13102                                 context_used = mini_method_check_context_used (cfg, cmethod);
13103
13104                                 if (mono_security_core_clr_enabled ())
13105                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
13106
13107                                 /*
13108                                  * Optimize the common case of ldvirtftn+delegate creation
13109                                  */
13110                                 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)) {
13111                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
13112                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
13113                                                 MonoInst *target_ins, *handle_ins;
13114                                                 MonoMethod *invoke;
13115                                                 int invoke_context_used;
13116                                                 gboolean is_virtual = cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL;
13117
13118                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
13119                                                 if (!invoke || !mono_method_signature (invoke))
13120                                                         LOAD_ERROR;
13121
13122                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
13123
13124                                                 target_ins = sp [-1];
13125
13126                                                 if (mono_security_core_clr_enabled ())
13127                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
13128
13129                                                 /* FIXME: SGEN support */
13130                                                 if (invoke_context_used == 0 || cfg->llvm_only) {
13131                                                         ip += 6;
13132                                                         if (cfg->verbose_level > 3)
13133                                                                 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));
13134                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, is_virtual))) {
13135                                                                 sp -= 2;
13136                                                                 *sp = handle_ins;
13137                                                                 CHECK_CFG_EXCEPTION;
13138                                                                 ip += 5;
13139                                                                 sp ++;
13140                                                                 break;
13141                                                         }
13142                                                         ip -= 6;
13143                                                 }
13144                                         }
13145                                 }
13146
13147                                 --sp;
13148                                 args [0] = *sp;
13149
13150                                 args [1] = emit_get_rgctx_method (cfg, context_used,
13151                                                                                                   cmethod, MONO_RGCTX_INFO_METHOD);
13152
13153                                 if (context_used)
13154                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn_gshared, args);
13155                                 else
13156                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn, args);
13157
13158                                 ip += 6;
13159                                 inline_costs += 10 * num_calls++;
13160                                 break;
13161                         }
13162                         case CEE_LDARG:
13163                                 CHECK_STACK_OVF (1);
13164                                 CHECK_OPSIZE (4);
13165                                 n = read16 (ip + 2);
13166                                 CHECK_ARG (n);
13167                                 EMIT_NEW_ARGLOAD (cfg, ins, n);
13168                                 *sp++ = ins;
13169                                 ip += 4;
13170                                 break;
13171                         case CEE_LDARGA:
13172                                 CHECK_STACK_OVF (1);
13173                                 CHECK_OPSIZE (4);
13174                                 n = read16 (ip + 2);
13175                                 CHECK_ARG (n);
13176                                 NEW_ARGLOADA (cfg, ins, n);
13177                                 MONO_ADD_INS (cfg->cbb, ins);
13178                                 *sp++ = ins;
13179                                 ip += 4;
13180                                 break;
13181                         case CEE_STARG:
13182                                 CHECK_STACK (1);
13183                                 --sp;
13184                                 CHECK_OPSIZE (4);
13185                                 n = read16 (ip + 2);
13186                                 CHECK_ARG (n);
13187                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
13188                                         UNVERIFIED;
13189                                 EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
13190                                 ip += 4;
13191                                 break;
13192                         case CEE_LDLOC:
13193                                 CHECK_STACK_OVF (1);
13194                                 CHECK_OPSIZE (4);
13195                                 n = read16 (ip + 2);
13196                                 CHECK_LOCAL (n);
13197                                 EMIT_NEW_LOCLOAD (cfg, ins, n);
13198                                 *sp++ = ins;
13199                                 ip += 4;
13200                                 break;
13201                         case CEE_LDLOCA: {
13202                                 unsigned char *tmp_ip;
13203                                 CHECK_STACK_OVF (1);
13204                                 CHECK_OPSIZE (4);
13205                                 n = read16 (ip + 2);
13206                                 CHECK_LOCAL (n);
13207
13208                                 if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 2))) {
13209                                         ip = tmp_ip;
13210                                         inline_costs += 1;
13211                                         break;
13212                                 }                       
13213                                 
13214                                 EMIT_NEW_LOCLOADA (cfg, ins, n);
13215                                 *sp++ = ins;
13216                                 ip += 4;
13217                                 break;
13218                         }
13219                         case CEE_STLOC:
13220                                 CHECK_STACK (1);
13221                                 --sp;
13222                                 CHECK_OPSIZE (4);
13223                                 n = read16 (ip + 2);
13224                                 CHECK_LOCAL (n);
13225                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
13226                                         UNVERIFIED;
13227                                 emit_stloc_ir (cfg, sp, header, n);
13228                                 ip += 4;
13229                                 inline_costs += 1;
13230                                 break;
13231                         case CEE_LOCALLOC: {
13232                                 CHECK_STACK (1);
13233                                 MonoBasicBlock *non_zero_bb, *end_bb;
13234                                 int alloc_ptr = alloc_preg (cfg);
13235                                 --sp;
13236                                 if (sp != stack_start) 
13237                                         UNVERIFIED;
13238                                 if (cfg->method != method) 
13239                                         /* 
13240                                          * Inlining this into a loop in a parent could lead to 
13241                                          * stack overflows which is different behavior than the
13242                                          * non-inlined case, thus disable inlining in this case.
13243                                          */
13244                                         INLINE_FAILURE("localloc");
13245
13246                                 NEW_BBLOCK (cfg, non_zero_bb);
13247                                 NEW_BBLOCK (cfg, end_bb);
13248
13249                                 /* if size != zero */
13250                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
13251                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, non_zero_bb);
13252
13253                                 //size is zero, so result is NULL
13254                                 MONO_EMIT_NEW_PCONST (cfg, alloc_ptr, NULL);
13255                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
13256
13257                                 MONO_START_BB (cfg, non_zero_bb);
13258                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
13259                                 ins->dreg = alloc_ptr;
13260                                 ins->sreg1 = sp [0]->dreg;
13261                                 ins->type = STACK_PTR;
13262                                 MONO_ADD_INS (cfg->cbb, ins);
13263
13264                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
13265                                 if (init_locals)
13266                                         ins->flags |= MONO_INST_INIT;
13267
13268                                 MONO_START_BB (cfg, end_bb);
13269                                 EMIT_NEW_UNALU (cfg, ins, OP_MOVE, alloc_preg (cfg), alloc_ptr);
13270                                 ins->type = STACK_PTR;
13271
13272                                 *sp++ = ins;
13273                                 ip += 2;
13274                                 break;
13275                         }
13276                         case CEE_ENDFILTER: {
13277                                 MonoExceptionClause *clause, *nearest;
13278                                 int cc;
13279
13280                                 CHECK_STACK (1);
13281                                 --sp;
13282                                 if ((sp != stack_start) || (sp [0]->type != STACK_I4)) 
13283                                         UNVERIFIED;
13284                                 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
13285                                 ins->sreg1 = (*sp)->dreg;
13286                                 MONO_ADD_INS (cfg->cbb, ins);
13287                                 start_new_bblock = 1;
13288                                 ip += 2;
13289
13290                                 nearest = NULL;
13291                                 for (cc = 0; cc < header->num_clauses; ++cc) {
13292                                         clause = &header->clauses [cc];
13293                                         if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
13294                                                 ((ip - header->code) > clause->data.filter_offset && (ip - header->code) <= clause->handler_offset) &&
13295                                             (!nearest || (clause->data.filter_offset < nearest->data.filter_offset)))
13296                                                 nearest = clause;
13297                                 }
13298                                 g_assert (nearest);
13299                                 if ((ip - header->code) != nearest->handler_offset)
13300                                         UNVERIFIED;
13301
13302                                 break;
13303                         }
13304                         case CEE_UNALIGNED_:
13305                                 ins_flag |= MONO_INST_UNALIGNED;
13306                                 /* FIXME: record alignment? we can assume 1 for now */
13307                                 CHECK_OPSIZE (3);
13308                                 ip += 3;
13309                                 break;
13310                         case CEE_VOLATILE_:
13311                                 ins_flag |= MONO_INST_VOLATILE;
13312                                 ip += 2;
13313                                 break;
13314                         case CEE_TAIL_:
13315                                 ins_flag   |= MONO_INST_TAILCALL;
13316                                 cfg->flags |= MONO_CFG_HAS_TAIL;
13317                                 /* Can't inline tail calls at this time */
13318                                 inline_costs += 100000;
13319                                 ip += 2;
13320                                 break;
13321                         case CEE_INITOBJ:
13322                                 CHECK_STACK (1);
13323                                 --sp;
13324                                 CHECK_OPSIZE (6);
13325                                 token = read32 (ip + 2);
13326                                 klass = mini_get_class (method, token, generic_context);
13327                                 CHECK_TYPELOAD (klass);
13328                                 if (generic_class_is_reference_type (cfg, klass))
13329                                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, sp [0]->dreg, 0, 0);
13330                                 else
13331                                         mini_emit_initobj (cfg, *sp, NULL, klass);
13332                                 ip += 6;
13333                                 inline_costs += 1;
13334                                 break;
13335                         case CEE_CONSTRAINED_:
13336                                 CHECK_OPSIZE (6);
13337                                 token = read32 (ip + 2);
13338                                 constrained_class = mini_get_class (method, token, generic_context);
13339                                 CHECK_TYPELOAD (constrained_class);
13340                                 ip += 6;
13341                                 break;
13342                         case CEE_CPBLK:
13343                         case CEE_INITBLK: {
13344                                 MonoInst *iargs [3];
13345                                 CHECK_STACK (3);
13346                                 sp -= 3;
13347
13348                                 /* Skip optimized paths for volatile operations. */
13349                                 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)) {
13350                                         mini_emit_memcpy (cfg, sp [0]->dreg, 0, sp [1]->dreg, 0, sp [2]->inst_c0, 0);
13351                                 } 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)) {
13352                                         /* emit_memset only works when val == 0 */
13353                                         mini_emit_memset (cfg, sp [0]->dreg, 0, sp [2]->inst_c0, sp [1]->inst_c0, 0);
13354                                 } else {
13355                                         MonoInst *call;
13356                                         iargs [0] = sp [0];
13357                                         iargs [1] = sp [1];
13358                                         iargs [2] = sp [2];
13359                                         if (ip [1] == CEE_CPBLK) {
13360                                                 /*
13361                                                  * FIXME: It's unclear whether we should be emitting both the acquire
13362                                                  * and release barriers for cpblk. It is technically both a load and
13363                                                  * store operation, so it seems like that's the sensible thing to do.
13364                                                  *
13365                                                  * FIXME: We emit full barriers on both sides of the operation for
13366                                                  * simplicity. We should have a separate atomic memcpy method instead.
13367                                                  */
13368                                                 MonoMethod *memcpy_method = get_memcpy_method ();
13369
13370                                                 if (ins_flag & MONO_INST_VOLATILE)
13371                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
13372
13373                                                 call = mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
13374                                                 call->flags |= ins_flag;
13375
13376                                                 if (ins_flag & MONO_INST_VOLATILE)
13377                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
13378                                         } else {
13379                                                 MonoMethod *memset_method = get_memset_method ();
13380                                                 if (ins_flag & MONO_INST_VOLATILE) {
13381                                                         /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
13382                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
13383                                                 }
13384                                                 call = mono_emit_method_call (cfg, memset_method, iargs, NULL);
13385                                                 call->flags |= ins_flag;
13386                                         }
13387                                 }
13388                                 ip += 2;
13389                                 ins_flag = 0;
13390                                 inline_costs += 1;
13391                                 break;
13392                         }
13393                         case CEE_NO_:
13394                                 CHECK_OPSIZE (3);
13395                                 if (ip [2] & 0x1)
13396                                         ins_flag |= MONO_INST_NOTYPECHECK;
13397                                 if (ip [2] & 0x2)
13398                                         ins_flag |= MONO_INST_NORANGECHECK;
13399                                 /* we ignore the no-nullcheck for now since we
13400                                  * really do it explicitly only when doing callvirt->call
13401                                  */
13402                                 ip += 3;
13403                                 break;
13404                         case CEE_RETHROW: {
13405                                 MonoInst *load;
13406                                 int handler_offset = -1;
13407
13408                                 for (i = 0; i < header->num_clauses; ++i) {
13409                                         MonoExceptionClause *clause = &header->clauses [i];
13410                                         if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
13411                                                 handler_offset = clause->handler_offset;
13412                                                 break;
13413                                         }
13414                                 }
13415
13416                                 cfg->cbb->flags |= BB_EXCEPTION_UNSAFE;
13417
13418                                 if (handler_offset == -1)
13419                                         UNVERIFIED;
13420
13421                                 EMIT_NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
13422                                 MONO_INST_NEW (cfg, ins, OP_RETHROW);
13423                                 ins->sreg1 = load->dreg;
13424                                 MONO_ADD_INS (cfg->cbb, ins);
13425
13426                                 MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
13427                                 MONO_ADD_INS (cfg->cbb, ins);
13428
13429                                 sp = stack_start;
13430                                 link_bblock (cfg, cfg->cbb, end_bblock);
13431                                 start_new_bblock = 1;
13432                                 ip += 2;
13433                                 break;
13434                         }
13435                         case CEE_SIZEOF: {
13436                                 guint32 val;
13437                                 int ialign;
13438
13439                                 CHECK_STACK_OVF (1);
13440                                 CHECK_OPSIZE (6);
13441                                 token = read32 (ip + 2);
13442                                 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC && !image_is_dynamic (method->klass->image) && !generic_context) {
13443                                         MonoType *type = mono_type_create_from_typespec_checked (image, token, &cfg->error);
13444                                         CHECK_CFG_ERROR;
13445
13446                                         val = mono_type_size (type, &ialign);
13447                                 } else {
13448                                         MonoClass *klass = mini_get_class (method, token, generic_context);
13449                                         CHECK_TYPELOAD (klass);
13450
13451                                         val = mono_type_size (&klass->byval_arg, &ialign);
13452
13453                                         if (mini_is_gsharedvt_klass (klass))
13454                                                 GSHAREDVT_FAILURE (*ip);
13455                                 }
13456                                 EMIT_NEW_ICONST (cfg, ins, val);
13457                                 *sp++= ins;
13458                                 ip += 6;
13459                                 break;
13460                         }
13461                         case CEE_REFANYTYPE: {
13462                                 MonoInst *src_var, *src;
13463
13464                                 GSHAREDVT_FAILURE (*ip);
13465
13466                                 CHECK_STACK (1);
13467                                 --sp;
13468
13469                                 // FIXME:
13470                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
13471                                 if (!src_var)
13472                                         src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
13473                                 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
13474                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &mono_defaults.typehandle_class->byval_arg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type));
13475                                 *sp++ = ins;
13476                                 ip += 2;
13477                                 break;
13478                         }
13479                         case CEE_READONLY_:
13480                                 readonly = TRUE;
13481                                 ip += 2;
13482                                 break;
13483
13484                         case CEE_UNUSED56:
13485                         case CEE_UNUSED57:
13486                         case CEE_UNUSED70:
13487                         case CEE_UNUSED:
13488                         case CEE_UNUSED99:
13489                                 UNVERIFIED;
13490                                 
13491                         default:
13492                                 g_warning ("opcode 0xfe 0x%02x not handled", ip [1]);
13493                                 UNVERIFIED;
13494                         }
13495                         break;
13496                 }
13497                 case CEE_UNUSED58:
13498                 case CEE_UNUSED1:
13499                         UNVERIFIED;
13500
13501                 default:
13502                         g_warning ("opcode 0x%02x not handled", *ip);
13503                         UNVERIFIED;
13504                 }
13505         }
13506         if (start_new_bblock != 1)
13507                 UNVERIFIED;
13508
13509         cfg->cbb->cil_length = ip - cfg->cbb->cil_code;
13510         if (cfg->cbb->next_bb) {
13511                 /* This could already be set because of inlining, #693905 */
13512                 MonoBasicBlock *bb = cfg->cbb;
13513
13514                 while (bb->next_bb)
13515                         bb = bb->next_bb;
13516                 bb->next_bb = end_bblock;
13517         } else {
13518                 cfg->cbb->next_bb = end_bblock;
13519         }
13520
13521         if (cfg->method == method && cfg->domainvar) {
13522                 MonoInst *store;
13523                 MonoInst *get_domain;
13524
13525                 cfg->cbb = init_localsbb;
13526
13527                 if ((get_domain = mono_get_domain_intrinsic (cfg))) {
13528                         MONO_ADD_INS (cfg->cbb, get_domain);
13529                 } else {
13530                         get_domain = mono_emit_jit_icall (cfg, mono_domain_get, NULL);
13531                 }
13532                 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, get_domain);
13533                 MONO_ADD_INS (cfg->cbb, store);
13534         }
13535
13536 #if defined(TARGET_POWERPC) || defined(TARGET_X86)
13537         if (cfg->compile_aot)
13538                 /* FIXME: The plt slots require a GOT var even if the method doesn't use it */
13539                 mono_get_got_var (cfg);
13540 #endif
13541
13542         if (cfg->method == method && cfg->got_var)
13543                 mono_emit_load_got_addr (cfg);
13544
13545         if (init_localsbb) {
13546                 cfg->cbb = init_localsbb;
13547                 cfg->ip = NULL;
13548                 for (i = 0; i < header->num_locals; ++i) {
13549                         emit_init_local (cfg, i, header->locals [i], init_locals);
13550                 }
13551         }
13552
13553         if (cfg->init_ref_vars && cfg->method == method) {
13554                 /* Emit initialization for ref vars */
13555                 // FIXME: Avoid duplication initialization for IL locals.
13556                 for (i = 0; i < cfg->num_varinfo; ++i) {
13557                         MonoInst *ins = cfg->varinfo [i];
13558
13559                         if (ins->opcode == OP_LOCAL && ins->type == STACK_OBJ)
13560                                 MONO_EMIT_NEW_PCONST (cfg, ins->dreg, NULL);
13561                 }
13562         }
13563
13564         if (cfg->lmf_var && cfg->method == method && !cfg->llvm_only) {
13565                 cfg->cbb = init_localsbb;
13566                 emit_push_lmf (cfg);
13567         }
13568
13569         cfg->cbb = init_localsbb;
13570         emit_instrumentation_call (cfg, mono_profiler_method_enter);
13571
13572         if (seq_points) {
13573                 MonoBasicBlock *bb;
13574
13575                 /*
13576                  * Make seq points at backward branch targets interruptable.
13577                  */
13578                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
13579                         if (bb->code && bb->in_count > 1 && bb->code->opcode == OP_SEQ_POINT)
13580                                 bb->code->flags |= MONO_INST_SINGLE_STEP_LOC;
13581         }
13582
13583         /* Add a sequence point for method entry/exit events */
13584         if (seq_points && cfg->gen_sdb_seq_points) {
13585                 NEW_SEQ_POINT (cfg, ins, METHOD_ENTRY_IL_OFFSET, FALSE);
13586                 MONO_ADD_INS (init_localsbb, ins);
13587                 NEW_SEQ_POINT (cfg, ins, METHOD_EXIT_IL_OFFSET, FALSE);
13588                 MONO_ADD_INS (cfg->bb_exit, ins);
13589         }
13590
13591         /*
13592          * Add seq points for IL offsets which have line number info, but wasn't generated a seq point during JITting because
13593          * the code they refer to was dead (#11880).
13594          */
13595         if (sym_seq_points) {
13596                 for (i = 0; i < header->code_size; ++i) {
13597                         if (mono_bitset_test_fast (seq_point_locs, i) && !mono_bitset_test_fast (seq_point_set_locs, i)) {
13598                                 MonoInst *ins;
13599
13600                                 NEW_SEQ_POINT (cfg, ins, i, FALSE);
13601                                 mono_add_seq_point (cfg, NULL, ins, SEQ_POINT_NATIVE_OFFSET_DEAD_CODE);
13602                         }
13603                 }
13604         }
13605
13606         cfg->ip = NULL;
13607
13608         if (cfg->method == method) {
13609                 MonoBasicBlock *bb;
13610                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13611                         bb->region = mono_find_block_region (cfg, bb->real_offset);
13612                         if (cfg->spvars)
13613                                 mono_create_spvar_for_region (cfg, bb->region);
13614                         if (cfg->verbose_level > 2)
13615                                 printf ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
13616                 }
13617         } else {
13618                 MonoBasicBlock *bb;
13619                 /* get_most_deep_clause () in mini-llvm.c depends on this for inlined bblocks */
13620                 for (bb = start_bblock; bb != end_bblock; bb  = bb->next_bb) {
13621                         bb->real_offset = inline_offset;
13622                 }
13623         }
13624
13625         if (inline_costs < 0) {
13626                 char *mname;
13627
13628                 /* Method is too large */
13629                 mname = mono_method_full_name (method, TRUE);
13630                 mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("Method %s is too complex.", mname));
13631                 g_free (mname);
13632         }
13633
13634         if ((cfg->verbose_level > 2) && (cfg->method == method)) 
13635                 mono_print_code (cfg, "AFTER METHOD-TO-IR");
13636
13637         goto cleanup;
13638
13639 mono_error_exit:
13640         g_assert (!mono_error_ok (&cfg->error));
13641         goto cleanup;
13642  
13643  exception_exit:
13644         g_assert (cfg->exception_type != MONO_EXCEPTION_NONE);
13645         goto cleanup;
13646
13647  unverified:
13648         set_exception_type_from_invalid_il (cfg, method, ip);
13649         goto cleanup;
13650
13651  cleanup:
13652         g_slist_free (class_inits);
13653         mono_basic_block_free (original_bb);
13654         cfg->dont_inline = g_list_remove (cfg->dont_inline, method);
13655         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
13656         if (cfg->exception_type)
13657                 return -1;
13658         else
13659                 return inline_costs;
13660 }
13661
13662 static int
13663 store_membase_reg_to_store_membase_imm (int opcode)
13664 {
13665         switch (opcode) {
13666         case OP_STORE_MEMBASE_REG:
13667                 return OP_STORE_MEMBASE_IMM;
13668         case OP_STOREI1_MEMBASE_REG:
13669                 return OP_STOREI1_MEMBASE_IMM;
13670         case OP_STOREI2_MEMBASE_REG:
13671                 return OP_STOREI2_MEMBASE_IMM;
13672         case OP_STOREI4_MEMBASE_REG:
13673                 return OP_STOREI4_MEMBASE_IMM;
13674         case OP_STOREI8_MEMBASE_REG:
13675                 return OP_STOREI8_MEMBASE_IMM;
13676         default:
13677                 g_assert_not_reached ();
13678         }
13679
13680         return -1;
13681 }               
13682
13683 int
13684 mono_op_to_op_imm (int opcode)
13685 {
13686         switch (opcode) {
13687         case OP_IADD:
13688                 return OP_IADD_IMM;
13689         case OP_ISUB:
13690                 return OP_ISUB_IMM;
13691         case OP_IDIV:
13692                 return OP_IDIV_IMM;
13693         case OP_IDIV_UN:
13694                 return OP_IDIV_UN_IMM;
13695         case OP_IREM:
13696                 return OP_IREM_IMM;
13697         case OP_IREM_UN:
13698                 return OP_IREM_UN_IMM;
13699         case OP_IMUL:
13700                 return OP_IMUL_IMM;
13701         case OP_IAND:
13702                 return OP_IAND_IMM;
13703         case OP_IOR:
13704                 return OP_IOR_IMM;
13705         case OP_IXOR:
13706                 return OP_IXOR_IMM;
13707         case OP_ISHL:
13708                 return OP_ISHL_IMM;
13709         case OP_ISHR:
13710                 return OP_ISHR_IMM;
13711         case OP_ISHR_UN:
13712                 return OP_ISHR_UN_IMM;
13713
13714         case OP_LADD:
13715                 return OP_LADD_IMM;
13716         case OP_LSUB:
13717                 return OP_LSUB_IMM;
13718         case OP_LAND:
13719                 return OP_LAND_IMM;
13720         case OP_LOR:
13721                 return OP_LOR_IMM;
13722         case OP_LXOR:
13723                 return OP_LXOR_IMM;
13724         case OP_LSHL:
13725                 return OP_LSHL_IMM;
13726         case OP_LSHR:
13727                 return OP_LSHR_IMM;
13728         case OP_LSHR_UN:
13729                 return OP_LSHR_UN_IMM;
13730 #if SIZEOF_REGISTER == 8
13731         case OP_LREM:
13732                 return OP_LREM_IMM;
13733 #endif
13734
13735         case OP_COMPARE:
13736                 return OP_COMPARE_IMM;
13737         case OP_ICOMPARE:
13738                 return OP_ICOMPARE_IMM;
13739         case OP_LCOMPARE:
13740                 return OP_LCOMPARE_IMM;
13741
13742         case OP_STORE_MEMBASE_REG:
13743                 return OP_STORE_MEMBASE_IMM;
13744         case OP_STOREI1_MEMBASE_REG:
13745                 return OP_STOREI1_MEMBASE_IMM;
13746         case OP_STOREI2_MEMBASE_REG:
13747                 return OP_STOREI2_MEMBASE_IMM;
13748         case OP_STOREI4_MEMBASE_REG:
13749                 return OP_STOREI4_MEMBASE_IMM;
13750
13751 #if defined(TARGET_X86) || defined (TARGET_AMD64)
13752         case OP_X86_PUSH:
13753                 return OP_X86_PUSH_IMM;
13754         case OP_X86_COMPARE_MEMBASE_REG:
13755                 return OP_X86_COMPARE_MEMBASE_IMM;
13756 #endif
13757 #if defined(TARGET_AMD64)
13758         case OP_AMD64_ICOMPARE_MEMBASE_REG:
13759                 return OP_AMD64_ICOMPARE_MEMBASE_IMM;
13760 #endif
13761         case OP_VOIDCALL_REG:
13762                 return OP_VOIDCALL;
13763         case OP_CALL_REG:
13764                 return OP_CALL;
13765         case OP_LCALL_REG:
13766                 return OP_LCALL;
13767         case OP_FCALL_REG:
13768                 return OP_FCALL;
13769         case OP_LOCALLOC:
13770                 return OP_LOCALLOC_IMM;
13771         }
13772
13773         return -1;
13774 }
13775
13776 static int
13777 ldind_to_load_membase (int opcode)
13778 {
13779         switch (opcode) {
13780         case CEE_LDIND_I1:
13781                 return OP_LOADI1_MEMBASE;
13782         case CEE_LDIND_U1:
13783                 return OP_LOADU1_MEMBASE;
13784         case CEE_LDIND_I2:
13785                 return OP_LOADI2_MEMBASE;
13786         case CEE_LDIND_U2:
13787                 return OP_LOADU2_MEMBASE;
13788         case CEE_LDIND_I4:
13789                 return OP_LOADI4_MEMBASE;
13790         case CEE_LDIND_U4:
13791                 return OP_LOADU4_MEMBASE;
13792         case CEE_LDIND_I:
13793                 return OP_LOAD_MEMBASE;
13794         case CEE_LDIND_REF:
13795                 return OP_LOAD_MEMBASE;
13796         case CEE_LDIND_I8:
13797                 return OP_LOADI8_MEMBASE;
13798         case CEE_LDIND_R4:
13799                 return OP_LOADR4_MEMBASE;
13800         case CEE_LDIND_R8:
13801                 return OP_LOADR8_MEMBASE;
13802         default:
13803                 g_assert_not_reached ();
13804         }
13805
13806         return -1;
13807 }
13808
13809 static int
13810 stind_to_store_membase (int opcode)
13811 {
13812         switch (opcode) {
13813         case CEE_STIND_I1:
13814                 return OP_STOREI1_MEMBASE_REG;
13815         case CEE_STIND_I2:
13816                 return OP_STOREI2_MEMBASE_REG;
13817         case CEE_STIND_I4:
13818                 return OP_STOREI4_MEMBASE_REG;
13819         case CEE_STIND_I:
13820         case CEE_STIND_REF:
13821                 return OP_STORE_MEMBASE_REG;
13822         case CEE_STIND_I8:
13823                 return OP_STOREI8_MEMBASE_REG;
13824         case CEE_STIND_R4:
13825                 return OP_STORER4_MEMBASE_REG;
13826         case CEE_STIND_R8:
13827                 return OP_STORER8_MEMBASE_REG;
13828         default:
13829                 g_assert_not_reached ();
13830         }
13831
13832         return -1;
13833 }
13834
13835 int
13836 mono_load_membase_to_load_mem (int opcode)
13837 {
13838         // FIXME: Add a MONO_ARCH_HAVE_LOAD_MEM macro
13839 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13840         switch (opcode) {
13841         case OP_LOAD_MEMBASE:
13842                 return OP_LOAD_MEM;
13843         case OP_LOADU1_MEMBASE:
13844                 return OP_LOADU1_MEM;
13845         case OP_LOADU2_MEMBASE:
13846                 return OP_LOADU2_MEM;
13847         case OP_LOADI4_MEMBASE:
13848                 return OP_LOADI4_MEM;
13849         case OP_LOADU4_MEMBASE:
13850                 return OP_LOADU4_MEM;
13851 #if SIZEOF_REGISTER == 8
13852         case OP_LOADI8_MEMBASE:
13853                 return OP_LOADI8_MEM;
13854 #endif
13855         }
13856 #endif
13857
13858         return -1;
13859 }
13860
13861 static inline int
13862 op_to_op_dest_membase (int store_opcode, int opcode)
13863 {
13864 #if defined(TARGET_X86)
13865         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG)))
13866                 return -1;
13867
13868         switch (opcode) {
13869         case OP_IADD:
13870                 return OP_X86_ADD_MEMBASE_REG;
13871         case OP_ISUB:
13872                 return OP_X86_SUB_MEMBASE_REG;
13873         case OP_IAND:
13874                 return OP_X86_AND_MEMBASE_REG;
13875         case OP_IOR:
13876                 return OP_X86_OR_MEMBASE_REG;
13877         case OP_IXOR:
13878                 return OP_X86_XOR_MEMBASE_REG;
13879         case OP_ADD_IMM:
13880         case OP_IADD_IMM:
13881                 return OP_X86_ADD_MEMBASE_IMM;
13882         case OP_SUB_IMM:
13883         case OP_ISUB_IMM:
13884                 return OP_X86_SUB_MEMBASE_IMM;
13885         case OP_AND_IMM:
13886         case OP_IAND_IMM:
13887                 return OP_X86_AND_MEMBASE_IMM;
13888         case OP_OR_IMM:
13889         case OP_IOR_IMM:
13890                 return OP_X86_OR_MEMBASE_IMM;
13891         case OP_XOR_IMM:
13892         case OP_IXOR_IMM:
13893                 return OP_X86_XOR_MEMBASE_IMM;
13894         case OP_MOVE:
13895                 return OP_NOP;
13896         }
13897 #endif
13898
13899 #if defined(TARGET_AMD64)
13900         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG) || (store_opcode == OP_STOREI8_MEMBASE_REG)))
13901                 return -1;
13902
13903         switch (opcode) {
13904         case OP_IADD:
13905                 return OP_X86_ADD_MEMBASE_REG;
13906         case OP_ISUB:
13907                 return OP_X86_SUB_MEMBASE_REG;
13908         case OP_IAND:
13909                 return OP_X86_AND_MEMBASE_REG;
13910         case OP_IOR:
13911                 return OP_X86_OR_MEMBASE_REG;
13912         case OP_IXOR:
13913                 return OP_X86_XOR_MEMBASE_REG;
13914         case OP_IADD_IMM:
13915                 return OP_X86_ADD_MEMBASE_IMM;
13916         case OP_ISUB_IMM:
13917                 return OP_X86_SUB_MEMBASE_IMM;
13918         case OP_IAND_IMM:
13919                 return OP_X86_AND_MEMBASE_IMM;
13920         case OP_IOR_IMM:
13921                 return OP_X86_OR_MEMBASE_IMM;
13922         case OP_IXOR_IMM:
13923                 return OP_X86_XOR_MEMBASE_IMM;
13924         case OP_LADD:
13925                 return OP_AMD64_ADD_MEMBASE_REG;
13926         case OP_LSUB:
13927                 return OP_AMD64_SUB_MEMBASE_REG;
13928         case OP_LAND:
13929                 return OP_AMD64_AND_MEMBASE_REG;
13930         case OP_LOR:
13931                 return OP_AMD64_OR_MEMBASE_REG;
13932         case OP_LXOR:
13933                 return OP_AMD64_XOR_MEMBASE_REG;
13934         case OP_ADD_IMM:
13935         case OP_LADD_IMM:
13936                 return OP_AMD64_ADD_MEMBASE_IMM;
13937         case OP_SUB_IMM:
13938         case OP_LSUB_IMM:
13939                 return OP_AMD64_SUB_MEMBASE_IMM;
13940         case OP_AND_IMM:
13941         case OP_LAND_IMM:
13942                 return OP_AMD64_AND_MEMBASE_IMM;
13943         case OP_OR_IMM:
13944         case OP_LOR_IMM:
13945                 return OP_AMD64_OR_MEMBASE_IMM;
13946         case OP_XOR_IMM:
13947         case OP_LXOR_IMM:
13948                 return OP_AMD64_XOR_MEMBASE_IMM;
13949         case OP_MOVE:
13950                 return OP_NOP;
13951         }
13952 #endif
13953
13954         return -1;
13955 }
13956
13957 static inline int
13958 op_to_op_store_membase (int store_opcode, int opcode)
13959 {
13960 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13961         switch (opcode) {
13962         case OP_ICEQ:
13963                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13964                         return OP_X86_SETEQ_MEMBASE;
13965         case OP_CNE:
13966                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13967                         return OP_X86_SETNE_MEMBASE;
13968         }
13969 #endif
13970
13971         return -1;
13972 }
13973
13974 static inline int
13975 op_to_op_src1_membase (MonoCompile *cfg, int load_opcode, int opcode)
13976 {
13977 #ifdef TARGET_X86
13978         /* FIXME: This has sign extension issues */
13979         /*
13980         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
13981                 return OP_X86_COMPARE_MEMBASE8_IMM;
13982         */
13983
13984         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
13985                 return -1;
13986
13987         switch (opcode) {
13988         case OP_X86_PUSH:
13989                 return OP_X86_PUSH_MEMBASE;
13990         case OP_COMPARE_IMM:
13991         case OP_ICOMPARE_IMM:
13992                 return OP_X86_COMPARE_MEMBASE_IMM;
13993         case OP_COMPARE:
13994         case OP_ICOMPARE:
13995                 return OP_X86_COMPARE_MEMBASE_REG;
13996         }
13997 #endif
13998
13999 #ifdef TARGET_AMD64
14000         /* FIXME: This has sign extension issues */
14001         /*
14002         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
14003                 return OP_X86_COMPARE_MEMBASE8_IMM;
14004         */
14005
14006         switch (opcode) {
14007         case OP_X86_PUSH:
14008                 if ((load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32) || (load_opcode == OP_LOADI8_MEMBASE))
14009                         return OP_X86_PUSH_MEMBASE;
14010                 break;
14011                 /* FIXME: This only works for 32 bit immediates
14012         case OP_COMPARE_IMM:
14013         case OP_LCOMPARE_IMM:
14014                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
14015                         return OP_AMD64_COMPARE_MEMBASE_IMM;
14016                 */
14017         case OP_ICOMPARE_IMM:
14018                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
14019                         return OP_AMD64_ICOMPARE_MEMBASE_IMM;
14020                 break;
14021         case OP_COMPARE:
14022         case OP_LCOMPARE:
14023                 if (cfg->backend->ilp32 && load_opcode == OP_LOAD_MEMBASE)
14024                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
14025                 if ((load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32) || (load_opcode == OP_LOADI8_MEMBASE))
14026                         return OP_AMD64_COMPARE_MEMBASE_REG;
14027                 break;
14028         case OP_ICOMPARE:
14029                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
14030                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
14031                 break;
14032         }
14033 #endif
14034
14035         return -1;
14036 }
14037
14038 static inline int
14039 op_to_op_src2_membase (MonoCompile *cfg, int load_opcode, int opcode)
14040 {
14041 #ifdef TARGET_X86
14042         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
14043                 return -1;
14044         
14045         switch (opcode) {
14046         case OP_COMPARE:
14047         case OP_ICOMPARE:
14048                 return OP_X86_COMPARE_REG_MEMBASE;
14049         case OP_IADD:
14050                 return OP_X86_ADD_REG_MEMBASE;
14051         case OP_ISUB:
14052                 return OP_X86_SUB_REG_MEMBASE;
14053         case OP_IAND:
14054                 return OP_X86_AND_REG_MEMBASE;
14055         case OP_IOR:
14056                 return OP_X86_OR_REG_MEMBASE;
14057         case OP_IXOR:
14058                 return OP_X86_XOR_REG_MEMBASE;
14059         }
14060 #endif
14061
14062 #ifdef TARGET_AMD64
14063         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE && cfg->backend->ilp32)) {
14064                 switch (opcode) {
14065                 case OP_ICOMPARE:
14066                         return OP_AMD64_ICOMPARE_REG_MEMBASE;
14067                 case OP_IADD:
14068                         return OP_X86_ADD_REG_MEMBASE;
14069                 case OP_ISUB:
14070                         return OP_X86_SUB_REG_MEMBASE;
14071                 case OP_IAND:
14072                         return OP_X86_AND_REG_MEMBASE;
14073                 case OP_IOR:
14074                         return OP_X86_OR_REG_MEMBASE;
14075                 case OP_IXOR:
14076                         return OP_X86_XOR_REG_MEMBASE;
14077                 }
14078         } else if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32)) {
14079                 switch (opcode) {
14080                 case OP_COMPARE:
14081                 case OP_LCOMPARE:
14082                         return OP_AMD64_COMPARE_REG_MEMBASE;
14083                 case OP_LADD:
14084                         return OP_AMD64_ADD_REG_MEMBASE;
14085                 case OP_LSUB:
14086                         return OP_AMD64_SUB_REG_MEMBASE;
14087                 case OP_LAND:
14088                         return OP_AMD64_AND_REG_MEMBASE;
14089                 case OP_LOR:
14090                         return OP_AMD64_OR_REG_MEMBASE;
14091                 case OP_LXOR:
14092                         return OP_AMD64_XOR_REG_MEMBASE;
14093                 }
14094         }
14095 #endif
14096
14097         return -1;
14098 }
14099
14100 int
14101 mono_op_to_op_imm_noemul (int opcode)
14102 {
14103         switch (opcode) {
14104 #if SIZEOF_REGISTER == 4 && !defined(MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS)
14105         case OP_LSHR:
14106         case OP_LSHL:
14107         case OP_LSHR_UN:
14108                 return -1;
14109 #endif
14110 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
14111         case OP_IDIV:
14112         case OP_IDIV_UN:
14113         case OP_IREM:
14114         case OP_IREM_UN:
14115                 return -1;
14116 #endif
14117 #if defined(MONO_ARCH_EMULATE_MUL_DIV)
14118         case OP_IMUL:
14119                 return -1;
14120 #endif
14121         default:
14122                 return mono_op_to_op_imm (opcode);
14123         }
14124 }
14125
14126 /**
14127  * mono_handle_global_vregs:
14128  *
14129  *   Make vregs used in more than one bblock 'global', i.e. allocate a variable
14130  * for them.
14131  */
14132 void
14133 mono_handle_global_vregs (MonoCompile *cfg)
14134 {
14135         gint32 *vreg_to_bb;
14136         MonoBasicBlock *bb;
14137         int i, pos;
14138
14139         vreg_to_bb = (gint32 *)mono_mempool_alloc0 (cfg->mempool, sizeof (gint32*) * cfg->next_vreg + 1);
14140
14141 #ifdef MONO_ARCH_SIMD_INTRINSICS
14142         if (cfg->uses_simd_intrinsics)
14143                 mono_simd_simplify_indirection (cfg);
14144 #endif
14145
14146         /* Find local vregs used in more than one bb */
14147         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
14148                 MonoInst *ins = bb->code;       
14149                 int block_num = bb->block_num;
14150
14151                 if (cfg->verbose_level > 2)
14152                         printf ("\nHANDLE-GLOBAL-VREGS BLOCK %d:\n", bb->block_num);
14153
14154                 cfg->cbb = bb;
14155                 for (; ins; ins = ins->next) {
14156                         const char *spec = INS_INFO (ins->opcode);
14157                         int regtype = 0, regindex;
14158                         gint32 prev_bb;
14159
14160                         if (G_UNLIKELY (cfg->verbose_level > 2))
14161                                 mono_print_ins (ins);
14162
14163                         g_assert (ins->opcode >= MONO_CEE_LAST);
14164
14165                         for (regindex = 0; regindex < 4; regindex ++) {
14166                                 int vreg = 0;
14167
14168                                 if (regindex == 0) {
14169                                         regtype = spec [MONO_INST_DEST];
14170                                         if (regtype == ' ')
14171                                                 continue;
14172                                         vreg = ins->dreg;
14173                                 } else if (regindex == 1) {
14174                                         regtype = spec [MONO_INST_SRC1];
14175                                         if (regtype == ' ')
14176                                                 continue;
14177                                         vreg = ins->sreg1;
14178                                 } else if (regindex == 2) {
14179                                         regtype = spec [MONO_INST_SRC2];
14180                                         if (regtype == ' ')
14181                                                 continue;
14182                                         vreg = ins->sreg2;
14183                                 } else if (regindex == 3) {
14184                                         regtype = spec [MONO_INST_SRC3];
14185                                         if (regtype == ' ')
14186                                                 continue;
14187                                         vreg = ins->sreg3;
14188                                 }
14189
14190 #if SIZEOF_REGISTER == 4
14191                                 /* In the LLVM case, the long opcodes are not decomposed */
14192                                 if (regtype == 'l' && !COMPILE_LLVM (cfg)) {
14193                                         /*
14194                                          * Since some instructions reference the original long vreg,
14195                                          * and some reference the two component vregs, it is quite hard
14196                                          * to determine when it needs to be global. So be conservative.
14197                                          */
14198                                         if (!get_vreg_to_inst (cfg, vreg)) {
14199                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
14200
14201                                                 if (cfg->verbose_level > 2)
14202                                                         printf ("LONG VREG R%d made global.\n", vreg);
14203                                         }
14204
14205                                         /*
14206                                          * Make the component vregs volatile since the optimizations can
14207                                          * get confused otherwise.
14208                                          */
14209                                         get_vreg_to_inst (cfg, MONO_LVREG_LS (vreg))->flags |= MONO_INST_VOLATILE;
14210                                         get_vreg_to_inst (cfg, MONO_LVREG_MS (vreg))->flags |= MONO_INST_VOLATILE;
14211                                 }
14212 #endif
14213
14214                                 g_assert (vreg != -1);
14215
14216                                 prev_bb = vreg_to_bb [vreg];
14217                                 if (prev_bb == 0) {
14218                                         /* 0 is a valid block num */
14219                                         vreg_to_bb [vreg] = block_num + 1;
14220                                 } else if ((prev_bb != block_num + 1) && (prev_bb != -1)) {
14221                                         if (((regtype == 'i' && (vreg < MONO_MAX_IREGS))) || (regtype == 'f' && (vreg < MONO_MAX_FREGS)))
14222                                                 continue;
14223
14224                                         if (!get_vreg_to_inst (cfg, vreg)) {
14225                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
14226                                                         printf ("VREG R%d used in BB%d and BB%d made global.\n", vreg, vreg_to_bb [vreg], block_num);
14227
14228                                                 switch (regtype) {
14229                                                 case 'i':
14230                                                         if (vreg_is_ref (cfg, vreg))
14231                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL, vreg);
14232                                                         else
14233                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL, vreg);
14234                                                         break;
14235                                                 case 'l':
14236                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
14237                                                         break;
14238                                                 case 'f':
14239                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL, vreg);
14240                                                         break;
14241                                                 case 'v':
14242                                                         mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, vreg);
14243                                                         break;
14244                                                 default:
14245                                                         g_assert_not_reached ();
14246                                                 }
14247                                         }
14248
14249                                         /* Flag as having been used in more than one bb */
14250                                         vreg_to_bb [vreg] = -1;
14251                                 }
14252                         }
14253                 }
14254         }
14255
14256         /* If a variable is used in only one bblock, convert it into a local vreg */
14257         for (i = 0; i < cfg->num_varinfo; i++) {
14258                 MonoInst *var = cfg->varinfo [i];
14259                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
14260
14261                 switch (var->type) {
14262                 case STACK_I4:
14263                 case STACK_OBJ:
14264                 case STACK_PTR:
14265                 case STACK_MP:
14266                 case STACK_VTYPE:
14267 #if SIZEOF_REGISTER == 8
14268                 case STACK_I8:
14269 #endif
14270 #if !defined(TARGET_X86)
14271                 /* Enabling this screws up the fp stack on x86 */
14272                 case STACK_R8:
14273 #endif
14274                         if (mono_arch_is_soft_float ())
14275                                 break;
14276
14277                         /*
14278                         if (var->type == STACK_VTYPE && cfg->gsharedvt && mini_is_gsharedvt_variable_type (var->inst_vtype))
14279                                 break;
14280                         */
14281
14282                         /* Arguments are implicitly global */
14283                         /* Putting R4 vars into registers doesn't work currently */
14284                         /* The gsharedvt vars are implicitly referenced by ldaddr opcodes, but those opcodes are only generated later */
14285                         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) {
14286                                 /* 
14287                                  * Make that the variable's liveness interval doesn't contain a call, since
14288                                  * that would cause the lvreg to be spilled, making the whole optimization
14289                                  * useless.
14290                                  */
14291                                 /* This is too slow for JIT compilation */
14292 #if 0
14293                                 if (cfg->compile_aot && vreg_to_bb [var->dreg]) {
14294                                         MonoInst *ins;
14295                                         int def_index, call_index, ins_index;
14296                                         gboolean spilled = FALSE;
14297
14298                                         def_index = -1;
14299                                         call_index = -1;
14300                                         ins_index = 0;
14301                                         for (ins = vreg_to_bb [var->dreg]->code; ins; ins = ins->next) {
14302                                                 const char *spec = INS_INFO (ins->opcode);
14303
14304                                                 if ((spec [MONO_INST_DEST] != ' ') && (ins->dreg == var->dreg))
14305                                                         def_index = ins_index;
14306
14307                                                 if (((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg)) ||
14308                                                         ((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg))) {
14309                                                         if (call_index > def_index) {
14310                                                                 spilled = TRUE;
14311                                                                 break;
14312                                                         }
14313                                                 }
14314
14315                                                 if (MONO_IS_CALL (ins))
14316                                                         call_index = ins_index;
14317
14318                                                 ins_index ++;
14319                                         }
14320
14321                                         if (spilled)
14322                                                 break;
14323                                 }
14324 #endif
14325
14326                                 if (G_UNLIKELY (cfg->verbose_level > 2))
14327                                         printf ("CONVERTED R%d(%d) TO VREG.\n", var->dreg, vmv->idx);
14328                                 var->flags |= MONO_INST_IS_DEAD;
14329                                 cfg->vreg_to_inst [var->dreg] = NULL;
14330                         }
14331                         break;
14332                 }
14333         }
14334
14335         /* 
14336          * Compress the varinfo and vars tables so the liveness computation is faster and
14337          * takes up less space.
14338          */
14339         pos = 0;
14340         for (i = 0; i < cfg->num_varinfo; ++i) {
14341                 MonoInst *var = cfg->varinfo [i];
14342                 if (pos < i && cfg->locals_start == i)
14343                         cfg->locals_start = pos;
14344                 if (!(var->flags & MONO_INST_IS_DEAD)) {
14345                         if (pos < i) {
14346                                 cfg->varinfo [pos] = cfg->varinfo [i];
14347                                 cfg->varinfo [pos]->inst_c0 = pos;
14348                                 memcpy (&cfg->vars [pos], &cfg->vars [i], sizeof (MonoMethodVar));
14349                                 cfg->vars [pos].idx = pos;
14350 #if SIZEOF_REGISTER == 4
14351                                 if (cfg->varinfo [pos]->type == STACK_I8) {
14352                                         /* Modify the two component vars too */
14353                                         MonoInst *var1;
14354
14355                                         var1 = get_vreg_to_inst (cfg, MONO_LVREG_LS (cfg->varinfo [pos]->dreg));
14356                                         var1->inst_c0 = pos;
14357                                         var1 = get_vreg_to_inst (cfg, MONO_LVREG_MS (cfg->varinfo [pos]->dreg));
14358                                         var1->inst_c0 = pos;
14359                                 }
14360 #endif
14361                         }
14362                         pos ++;
14363                 }
14364         }
14365         cfg->num_varinfo = pos;
14366         if (cfg->locals_start > cfg->num_varinfo)
14367                 cfg->locals_start = cfg->num_varinfo;
14368 }
14369
14370 /*
14371  * mono_allocate_gsharedvt_vars:
14372  *
14373  *   Allocate variables with gsharedvt types to entries in the MonoGSharedVtMethodRuntimeInfo.entries array.
14374  * Initialize cfg->gsharedvt_vreg_to_idx with the mapping between vregs and indexes.
14375  */
14376 void
14377 mono_allocate_gsharedvt_vars (MonoCompile *cfg)
14378 {
14379         int i;
14380
14381         cfg->gsharedvt_vreg_to_idx = (int *)mono_mempool_alloc0 (cfg->mempool, sizeof (int) * cfg->next_vreg);
14382
14383         for (i = 0; i < cfg->num_varinfo; ++i) {
14384                 MonoInst *ins = cfg->varinfo [i];
14385                 int idx;
14386
14387                 if (mini_is_gsharedvt_variable_type (ins->inst_vtype)) {
14388                         if (i >= cfg->locals_start) {
14389                                 /* Local */
14390                                 idx = get_gsharedvt_info_slot (cfg, ins->inst_vtype, MONO_RGCTX_INFO_LOCAL_OFFSET);
14391                                 cfg->gsharedvt_vreg_to_idx [ins->dreg] = idx + 1;
14392                                 ins->opcode = OP_GSHAREDVT_LOCAL;
14393                                 ins->inst_imm = idx;
14394                         } else {
14395                                 /* Arg */
14396                                 cfg->gsharedvt_vreg_to_idx [ins->dreg] = -1;
14397                                 ins->opcode = OP_GSHAREDVT_ARG_REGOFFSET;
14398                         }
14399                 }
14400         }
14401 }
14402
14403 /**
14404  * mono_spill_global_vars:
14405  *
14406  *   Generate spill code for variables which are not allocated to registers, 
14407  * and replace vregs with their allocated hregs. *need_local_opts is set to TRUE if
14408  * code is generated which could be optimized by the local optimization passes.
14409  */
14410 void
14411 mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
14412 {
14413         MonoBasicBlock *bb;
14414         char spec2 [16];
14415         int orig_next_vreg;
14416         guint32 *vreg_to_lvreg;
14417         guint32 *lvregs;
14418         guint32 i, lvregs_len;
14419         gboolean dest_has_lvreg = FALSE;
14420         MonoStackType stacktypes [128];
14421         MonoInst **live_range_start, **live_range_end;
14422         MonoBasicBlock **live_range_start_bb, **live_range_end_bb;
14423
14424         *need_local_opts = FALSE;
14425
14426         memset (spec2, 0, sizeof (spec2));
14427
14428         /* FIXME: Move this function to mini.c */
14429         stacktypes ['i'] = STACK_PTR;
14430         stacktypes ['l'] = STACK_I8;
14431         stacktypes ['f'] = STACK_R8;
14432 #ifdef MONO_ARCH_SIMD_INTRINSICS
14433         stacktypes ['x'] = STACK_VTYPE;
14434 #endif
14435
14436 #if SIZEOF_REGISTER == 4
14437         /* Create MonoInsts for longs */
14438         for (i = 0; i < cfg->num_varinfo; i++) {
14439                 MonoInst *ins = cfg->varinfo [i];
14440
14441                 if ((ins->opcode != OP_REGVAR) && !(ins->flags & MONO_INST_IS_DEAD)) {
14442                         switch (ins->type) {
14443                         case STACK_R8:
14444                         case STACK_I8: {
14445                                 MonoInst *tree;
14446
14447                                 if (ins->type == STACK_R8 && !COMPILE_SOFT_FLOAT (cfg))
14448                                         break;
14449
14450                                 g_assert (ins->opcode == OP_REGOFFSET);
14451
14452                                 tree = get_vreg_to_inst (cfg, MONO_LVREG_LS (ins->dreg));
14453                                 g_assert (tree);
14454                                 tree->opcode = OP_REGOFFSET;
14455                                 tree->inst_basereg = ins->inst_basereg;
14456                                 tree->inst_offset = ins->inst_offset + MINI_LS_WORD_OFFSET;
14457
14458                                 tree = get_vreg_to_inst (cfg, MONO_LVREG_MS (ins->dreg));
14459                                 g_assert (tree);
14460                                 tree->opcode = OP_REGOFFSET;
14461                                 tree->inst_basereg = ins->inst_basereg;
14462                                 tree->inst_offset = ins->inst_offset + MINI_MS_WORD_OFFSET;
14463                                 break;
14464                         }
14465                         default:
14466                                 break;
14467                         }
14468                 }
14469         }
14470 #endif
14471
14472         if (cfg->compute_gc_maps) {
14473                 /* registers need liveness info even for !non refs */
14474                 for (i = 0; i < cfg->num_varinfo; i++) {
14475                         MonoInst *ins = cfg->varinfo [i];
14476
14477                         if (ins->opcode == OP_REGVAR)
14478                                 ins->flags |= MONO_INST_GC_TRACK;
14479                 }
14480         }
14481                 
14482         /* FIXME: widening and truncation */
14483
14484         /*
14485          * As an optimization, when a variable allocated to the stack is first loaded into 
14486          * an lvreg, we will remember the lvreg and use it the next time instead of loading
14487          * the variable again.
14488          */
14489         orig_next_vreg = cfg->next_vreg;
14490         vreg_to_lvreg = (guint32 *)mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * cfg->next_vreg);
14491         lvregs = (guint32 *)mono_mempool_alloc (cfg->mempool, sizeof (guint32) * 1024);
14492         lvregs_len = 0;
14493
14494         /* 
14495          * These arrays contain the first and last instructions accessing a given
14496          * variable.
14497          * Since we emit bblocks in the same order we process them here, and we
14498          * don't split live ranges, these will precisely describe the live range of
14499          * the variable, i.e. the instruction range where a valid value can be found
14500          * in the variables location.
14501          * The live range is computed using the liveness info computed by the liveness pass.
14502          * We can't use vmv->range, since that is an abstract live range, and we need
14503          * one which is instruction precise.
14504          * FIXME: Variables used in out-of-line bblocks have a hole in their live range.
14505          */
14506         /* FIXME: Only do this if debugging info is requested */
14507         live_range_start = g_new0 (MonoInst*, cfg->next_vreg);
14508         live_range_end = g_new0 (MonoInst*, cfg->next_vreg);
14509         live_range_start_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
14510         live_range_end_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
14511         
14512         /* Add spill loads/stores */
14513         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
14514                 MonoInst *ins;
14515
14516                 if (cfg->verbose_level > 2)
14517                         printf ("\nSPILL BLOCK %d:\n", bb->block_num);
14518
14519                 /* Clear vreg_to_lvreg array */
14520                 for (i = 0; i < lvregs_len; i++)
14521                         vreg_to_lvreg [lvregs [i]] = 0;
14522                 lvregs_len = 0;
14523
14524                 cfg->cbb = bb;
14525                 MONO_BB_FOR_EACH_INS (bb, ins) {
14526                         const char *spec = INS_INFO (ins->opcode);
14527                         int regtype, srcindex, sreg, tmp_reg, prev_dreg, num_sregs;
14528                         gboolean store, no_lvreg;
14529                         int sregs [MONO_MAX_SRC_REGS];
14530
14531                         if (G_UNLIKELY (cfg->verbose_level > 2))
14532                                 mono_print_ins (ins);
14533
14534                         if (ins->opcode == OP_NOP)
14535                                 continue;
14536
14537                         /* 
14538                          * We handle LDADDR here as well, since it can only be decomposed
14539                          * when variable addresses are known.
14540                          */
14541                         if (ins->opcode == OP_LDADDR) {
14542                                 MonoInst *var = (MonoInst *)ins->inst_p0;
14543
14544                                 if (var->opcode == OP_VTARG_ADDR) {
14545                                         /* Happens on SPARC/S390 where vtypes are passed by reference */
14546                                         MonoInst *vtaddr = var->inst_left;
14547                                         if (vtaddr->opcode == OP_REGVAR) {
14548                                                 ins->opcode = OP_MOVE;
14549                                                 ins->sreg1 = vtaddr->dreg;
14550                                         }
14551                                         else if (var->inst_left->opcode == OP_REGOFFSET) {
14552                                                 ins->opcode = OP_LOAD_MEMBASE;
14553                                                 ins->inst_basereg = vtaddr->inst_basereg;
14554                                                 ins->inst_offset = vtaddr->inst_offset;
14555                                         } else
14556                                                 NOT_IMPLEMENTED;
14557                                 } else if (cfg->gsharedvt && cfg->gsharedvt_vreg_to_idx [var->dreg] < 0) {
14558                                         /* gsharedvt arg passed by ref */
14559                                         g_assert (var->opcode == OP_GSHAREDVT_ARG_REGOFFSET);
14560
14561                                         ins->opcode = OP_LOAD_MEMBASE;
14562                                         ins->inst_basereg = var->inst_basereg;
14563                                         ins->inst_offset = var->inst_offset;
14564                                 } else if (cfg->gsharedvt && cfg->gsharedvt_vreg_to_idx [var->dreg]) {
14565                                         MonoInst *load, *load2, *load3;
14566                                         int idx = cfg->gsharedvt_vreg_to_idx [var->dreg] - 1;
14567                                         int reg1, reg2, reg3;
14568                                         MonoInst *info_var = cfg->gsharedvt_info_var;
14569                                         MonoInst *locals_var = cfg->gsharedvt_locals_var;
14570
14571                                         /*
14572                                          * gsharedvt local.
14573                                          * Compute the address of the local as gsharedvt_locals_var + gsharedvt_info_var->locals_offsets [idx].
14574                                          */
14575
14576                                         g_assert (var->opcode == OP_GSHAREDVT_LOCAL);
14577
14578                                         g_assert (info_var);
14579                                         g_assert (locals_var);
14580
14581                                         /* Mark the instruction used to compute the locals var as used */
14582                                         cfg->gsharedvt_locals_var_ins = NULL;
14583
14584                                         /* Load the offset */
14585                                         if (info_var->opcode == OP_REGOFFSET) {
14586                                                 reg1 = alloc_ireg (cfg);
14587                                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, reg1, info_var->inst_basereg, info_var->inst_offset);
14588                                         } else if (info_var->opcode == OP_REGVAR) {
14589                                                 load = NULL;
14590                                                 reg1 = info_var->dreg;
14591                                         } else {
14592                                                 g_assert_not_reached ();
14593                                         }
14594                                         reg2 = alloc_ireg (cfg);
14595                                         NEW_LOAD_MEMBASE (cfg, load2, OP_LOADI4_MEMBASE, reg2, reg1, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
14596                                         /* Load the locals area address */
14597                                         reg3 = alloc_ireg (cfg);
14598                                         if (locals_var->opcode == OP_REGOFFSET) {
14599                                                 NEW_LOAD_MEMBASE (cfg, load3, OP_LOAD_MEMBASE, reg3, locals_var->inst_basereg, locals_var->inst_offset);
14600                                         } else if (locals_var->opcode == OP_REGVAR) {
14601                                                 NEW_UNALU (cfg, load3, OP_MOVE, reg3, locals_var->dreg);
14602                                         } else {
14603                                                 g_assert_not_reached ();
14604                                         }
14605                                         /* Compute the address */
14606                                         ins->opcode = OP_PADD;
14607                                         ins->sreg1 = reg3;
14608                                         ins->sreg2 = reg2;
14609
14610                                         mono_bblock_insert_before_ins (bb, ins, load3);
14611                                         mono_bblock_insert_before_ins (bb, load3, load2);
14612                                         if (load)
14613                                                 mono_bblock_insert_before_ins (bb, load2, load);
14614                                 } else {
14615                                         g_assert (var->opcode == OP_REGOFFSET);
14616
14617                                         ins->opcode = OP_ADD_IMM;
14618                                         ins->sreg1 = var->inst_basereg;
14619                                         ins->inst_imm = var->inst_offset;
14620                                 }
14621
14622                                 *need_local_opts = TRUE;
14623                                 spec = INS_INFO (ins->opcode);
14624                         }
14625
14626                         if (ins->opcode < MONO_CEE_LAST) {
14627                                 mono_print_ins (ins);
14628                                 g_assert_not_reached ();
14629                         }
14630
14631                         /*
14632                          * Store opcodes have destbasereg in the dreg, but in reality, it is an
14633                          * src register.
14634                          * FIXME:
14635                          */
14636                         if (MONO_IS_STORE_MEMBASE (ins)) {
14637                                 tmp_reg = ins->dreg;
14638                                 ins->dreg = ins->sreg2;
14639                                 ins->sreg2 = tmp_reg;
14640                                 store = TRUE;
14641
14642                                 spec2 [MONO_INST_DEST] = ' ';
14643                                 spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14644                                 spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14645                                 spec2 [MONO_INST_SRC3] = ' ';
14646                                 spec = spec2;
14647                         } else if (MONO_IS_STORE_MEMINDEX (ins))
14648                                 g_assert_not_reached ();
14649                         else
14650                                 store = FALSE;
14651                         no_lvreg = FALSE;
14652
14653                         if (G_UNLIKELY (cfg->verbose_level > 2)) {
14654                                 printf ("\t %.3s %d", spec, ins->dreg);
14655                                 num_sregs = mono_inst_get_src_registers (ins, sregs);
14656                                 for (srcindex = 0; srcindex < num_sregs; ++srcindex)
14657                                         printf (" %d", sregs [srcindex]);
14658                                 printf ("\n");
14659                         }
14660
14661                         /***************/
14662                         /*    DREG     */
14663                         /***************/
14664                         regtype = spec [MONO_INST_DEST];
14665                         g_assert (((ins->dreg == -1) && (regtype == ' ')) || ((ins->dreg != -1) && (regtype != ' ')));
14666                         prev_dreg = -1;
14667
14668                         if ((ins->dreg != -1) && get_vreg_to_inst (cfg, ins->dreg)) {
14669                                 MonoInst *var = get_vreg_to_inst (cfg, ins->dreg);
14670                                 MonoInst *store_ins;
14671                                 int store_opcode;
14672                                 MonoInst *def_ins = ins;
14673                                 int dreg = ins->dreg; /* The original vreg */
14674
14675                                 store_opcode = mono_type_to_store_membase (cfg, var->inst_vtype);
14676
14677                                 if (var->opcode == OP_REGVAR) {
14678                                         ins->dreg = var->dreg;
14679                                 } 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)) {
14680                                         /* 
14681                                          * Instead of emitting a load+store, use a _membase opcode.
14682                                          */
14683                                         g_assert (var->opcode == OP_REGOFFSET);
14684                                         if (ins->opcode == OP_MOVE) {
14685                                                 NULLIFY_INS (ins);
14686                                                 def_ins = NULL;
14687                                         } else {
14688                                                 ins->opcode = op_to_op_dest_membase (store_opcode, ins->opcode);
14689                                                 ins->inst_basereg = var->inst_basereg;
14690                                                 ins->inst_offset = var->inst_offset;
14691                                                 ins->dreg = -1;
14692                                         }
14693                                         spec = INS_INFO (ins->opcode);
14694                                 } else {
14695                                         guint32 lvreg;
14696
14697                                         g_assert (var->opcode == OP_REGOFFSET);
14698
14699                                         prev_dreg = ins->dreg;
14700
14701                                         /* Invalidate any previous lvreg for this vreg */
14702                                         vreg_to_lvreg [ins->dreg] = 0;
14703
14704                                         lvreg = 0;
14705
14706                                         if (COMPILE_SOFT_FLOAT (cfg) && store_opcode == OP_STORER8_MEMBASE_REG) {
14707                                                 regtype = 'l';
14708                                                 store_opcode = OP_STOREI8_MEMBASE_REG;
14709                                         }
14710
14711                                         ins->dreg = alloc_dreg (cfg, stacktypes [regtype]);
14712
14713 #if SIZEOF_REGISTER != 8
14714                                         if (regtype == 'l') {
14715                                                 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));
14716                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14717                                                 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));
14718                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14719                                                 def_ins = store_ins;
14720                                         }
14721                                         else
14722 #endif
14723                                         {
14724                                                 g_assert (store_opcode != OP_STOREV_MEMBASE);
14725
14726                                                 /* Try to fuse the store into the instruction itself */
14727                                                 /* FIXME: Add more instructions */
14728                                                 if (!lvreg && ((ins->opcode == OP_ICONST) || ((ins->opcode == OP_I8CONST) && (ins->inst_c0 == 0)))) {
14729                                                         ins->opcode = store_membase_reg_to_store_membase_imm (store_opcode);
14730                                                         ins->inst_imm = ins->inst_c0;
14731                                                         ins->inst_destbasereg = var->inst_basereg;
14732                                                         ins->inst_offset = var->inst_offset;
14733                                                         spec = INS_INFO (ins->opcode);
14734                                                 } else if (!lvreg && ((ins->opcode == OP_MOVE) || (ins->opcode == OP_FMOVE) || (ins->opcode == OP_LMOVE) || (ins->opcode == OP_RMOVE))) {
14735                                                         ins->opcode = store_opcode;
14736                                                         ins->inst_destbasereg = var->inst_basereg;
14737                                                         ins->inst_offset = var->inst_offset;
14738
14739                                                         no_lvreg = TRUE;
14740
14741                                                         tmp_reg = ins->dreg;
14742                                                         ins->dreg = ins->sreg2;
14743                                                         ins->sreg2 = tmp_reg;
14744                                                         store = TRUE;
14745
14746                                                         spec2 [MONO_INST_DEST] = ' ';
14747                                                         spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14748                                                         spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14749                                                         spec2 [MONO_INST_SRC3] = ' ';
14750                                                         spec = spec2;
14751                                                 } else if (!lvreg && (op_to_op_store_membase (store_opcode, ins->opcode) != -1)) {
14752                                                         // FIXME: The backends expect the base reg to be in inst_basereg
14753                                                         ins->opcode = op_to_op_store_membase (store_opcode, ins->opcode);
14754                                                         ins->dreg = -1;
14755                                                         ins->inst_basereg = var->inst_basereg;
14756                                                         ins->inst_offset = var->inst_offset;
14757                                                         spec = INS_INFO (ins->opcode);
14758                                                 } else {
14759                                                         /* printf ("INS: "); mono_print_ins (ins); */
14760                                                         /* Create a store instruction */
14761                                                         NEW_STORE_MEMBASE (cfg, store_ins, store_opcode, var->inst_basereg, var->inst_offset, ins->dreg);
14762
14763                                                         /* Insert it after the instruction */
14764                                                         mono_bblock_insert_after_ins (bb, ins, store_ins);
14765
14766                                                         def_ins = store_ins;
14767
14768                                                         /* 
14769                                                          * We can't assign ins->dreg to var->dreg here, since the
14770                                                          * sregs could use it. So set a flag, and do it after
14771                                                          * the sregs.
14772                                                          */
14773                                                         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)))
14774                                                                 dest_has_lvreg = TRUE;
14775                                                 }
14776                                         }
14777                                 }
14778
14779                                 if (def_ins && !live_range_start [dreg]) {
14780                                         live_range_start [dreg] = def_ins;
14781                                         live_range_start_bb [dreg] = bb;
14782                                 }
14783
14784                                 if (cfg->compute_gc_maps && def_ins && (var->flags & MONO_INST_GC_TRACK)) {
14785                                         MonoInst *tmp;
14786
14787                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
14788                                         tmp->inst_c1 = dreg;
14789                                         mono_bblock_insert_after_ins (bb, def_ins, tmp);
14790                                 }
14791                         }
14792
14793                         /************/
14794                         /*  SREGS   */
14795                         /************/
14796                         num_sregs = mono_inst_get_src_registers (ins, sregs);
14797                         for (srcindex = 0; srcindex < 3; ++srcindex) {
14798                                 regtype = spec [MONO_INST_SRC1 + srcindex];
14799                                 sreg = sregs [srcindex];
14800
14801                                 g_assert (((sreg == -1) && (regtype == ' ')) || ((sreg != -1) && (regtype != ' ')));
14802                                 if ((sreg != -1) && get_vreg_to_inst (cfg, sreg)) {
14803                                         MonoInst *var = get_vreg_to_inst (cfg, sreg);
14804                                         MonoInst *use_ins = ins;
14805                                         MonoInst *load_ins;
14806                                         guint32 load_opcode;
14807
14808                                         if (var->opcode == OP_REGVAR) {
14809                                                 sregs [srcindex] = var->dreg;
14810                                                 //mono_inst_set_src_registers (ins, sregs);
14811                                                 live_range_end [sreg] = use_ins;
14812                                                 live_range_end_bb [sreg] = bb;
14813
14814                                                 if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14815                                                         MonoInst *tmp;
14816
14817                                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14818                                                         /* var->dreg is a hreg */
14819                                                         tmp->inst_c1 = sreg;
14820                                                         mono_bblock_insert_after_ins (bb, ins, tmp);
14821                                                 }
14822
14823                                                 continue;
14824                                         }
14825
14826                                         g_assert (var->opcode == OP_REGOFFSET);
14827                                                 
14828                                         load_opcode = mono_type_to_load_membase (cfg, var->inst_vtype);
14829
14830                                         g_assert (load_opcode != OP_LOADV_MEMBASE);
14831
14832                                         if (vreg_to_lvreg [sreg]) {
14833                                                 g_assert (vreg_to_lvreg [sreg] != -1);
14834
14835                                                 /* The variable is already loaded to an lvreg */
14836                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
14837                                                         printf ("\t\tUse lvreg R%d for R%d.\n", vreg_to_lvreg [sreg], sreg);
14838                                                 sregs [srcindex] = vreg_to_lvreg [sreg];
14839                                                 //mono_inst_set_src_registers (ins, sregs);
14840                                                 continue;
14841                                         }
14842
14843                                         /* Try to fuse the load into the instruction */
14844                                         if ((srcindex == 0) && (op_to_op_src1_membase (cfg, load_opcode, ins->opcode) != -1)) {
14845                                                 ins->opcode = op_to_op_src1_membase (cfg, load_opcode, ins->opcode);
14846                                                 sregs [0] = var->inst_basereg;
14847                                                 //mono_inst_set_src_registers (ins, sregs);
14848                                                 ins->inst_offset = var->inst_offset;
14849                                         } else if ((srcindex == 1) && (op_to_op_src2_membase (cfg, load_opcode, ins->opcode) != -1)) {
14850                                                 ins->opcode = op_to_op_src2_membase (cfg, load_opcode, ins->opcode);
14851                                                 sregs [1] = var->inst_basereg;
14852                                                 //mono_inst_set_src_registers (ins, sregs);
14853                                                 ins->inst_offset = var->inst_offset;
14854                                         } else {
14855                                                 if (MONO_IS_REAL_MOVE (ins)) {
14856                                                         ins->opcode = OP_NOP;
14857                                                         sreg = ins->dreg;
14858                                                 } else {
14859                                                         //printf ("%d ", srcindex); mono_print_ins (ins);
14860
14861                                                         sreg = alloc_dreg (cfg, stacktypes [regtype]);
14862
14863                                                         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) {
14864                                                                 if (var->dreg == prev_dreg) {
14865                                                                         /*
14866                                                                          * sreg refers to the value loaded by the load
14867                                                                          * emitted below, but we need to use ins->dreg
14868                                                                          * since it refers to the store emitted earlier.
14869                                                                          */
14870                                                                         sreg = ins->dreg;
14871                                                                 }
14872                                                                 g_assert (sreg != -1);
14873                                                                 vreg_to_lvreg [var->dreg] = sreg;
14874                                                                 g_assert (lvregs_len < 1024);
14875                                                                 lvregs [lvregs_len ++] = var->dreg;
14876                                                         }
14877                                                 }
14878
14879                                                 sregs [srcindex] = sreg;
14880                                                 //mono_inst_set_src_registers (ins, sregs);
14881
14882 #if SIZEOF_REGISTER != 8
14883                                                 if (regtype == 'l') {
14884                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, MONO_LVREG_MS (sreg), var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET);
14885                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14886                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, MONO_LVREG_LS (sreg), var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET);
14887                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14888                                                         use_ins = load_ins;
14889                                                 }
14890                                                 else
14891 #endif
14892                                                 {
14893 #if SIZEOF_REGISTER == 4
14894                                                         g_assert (load_opcode != OP_LOADI8_MEMBASE);
14895 #endif
14896                                                         NEW_LOAD_MEMBASE (cfg, load_ins, load_opcode, sreg, var->inst_basereg, var->inst_offset);
14897                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14898                                                         use_ins = load_ins;
14899                                                 }
14900                                         }
14901
14902                                         if (var->dreg < orig_next_vreg) {
14903                                                 live_range_end [var->dreg] = use_ins;
14904                                                 live_range_end_bb [var->dreg] = bb;
14905                                         }
14906
14907                                         if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14908                                                 MonoInst *tmp;
14909
14910                                                 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14911                                                 tmp->inst_c1 = var->dreg;
14912                                                 mono_bblock_insert_after_ins (bb, ins, tmp);
14913                                         }
14914                                 }
14915                         }
14916                         mono_inst_set_src_registers (ins, sregs);
14917
14918                         if (dest_has_lvreg) {
14919                                 g_assert (ins->dreg != -1);
14920                                 vreg_to_lvreg [prev_dreg] = ins->dreg;
14921                                 g_assert (lvregs_len < 1024);
14922                                 lvregs [lvregs_len ++] = prev_dreg;
14923                                 dest_has_lvreg = FALSE;
14924                         }
14925
14926                         if (store) {
14927                                 tmp_reg = ins->dreg;
14928                                 ins->dreg = ins->sreg2;
14929                                 ins->sreg2 = tmp_reg;
14930                         }
14931
14932                         if (MONO_IS_CALL (ins)) {
14933                                 /* Clear vreg_to_lvreg array */
14934                                 for (i = 0; i < lvregs_len; i++)
14935                                         vreg_to_lvreg [lvregs [i]] = 0;
14936                                 lvregs_len = 0;
14937                         } else if (ins->opcode == OP_NOP) {
14938                                 ins->dreg = -1;
14939                                 MONO_INST_NULLIFY_SREGS (ins);
14940                         }
14941
14942                         if (cfg->verbose_level > 2)
14943                                 mono_print_ins_index (1, ins);
14944                 }
14945
14946                 /* Extend the live range based on the liveness info */
14947                 if (cfg->compute_precise_live_ranges && bb->live_out_set && bb->code) {
14948                         for (i = 0; i < cfg->num_varinfo; i ++) {
14949                                 MonoMethodVar *vi = MONO_VARINFO (cfg, i);
14950
14951                                 if (vreg_is_volatile (cfg, vi->vreg))
14952                                         /* The liveness info is incomplete */
14953                                         continue;
14954
14955                                 if (mono_bitset_test_fast (bb->live_in_set, i) && !live_range_start [vi->vreg]) {
14956                                         /* Live from at least the first ins of this bb */
14957                                         live_range_start [vi->vreg] = bb->code;
14958                                         live_range_start_bb [vi->vreg] = bb;
14959                                 }
14960
14961                                 if (mono_bitset_test_fast (bb->live_out_set, i)) {
14962                                         /* Live at least until the last ins of this bb */
14963                                         live_range_end [vi->vreg] = bb->last_ins;
14964                                         live_range_end_bb [vi->vreg] = bb;
14965                                 }
14966                         }
14967                 }
14968         }
14969         
14970         /*
14971          * Emit LIVERANGE_START/LIVERANGE_END opcodes, the backend will implement them
14972          * by storing the current native offset into MonoMethodVar->live_range_start/end.
14973          */
14974         if (cfg->backend->have_liverange_ops && cfg->compute_precise_live_ranges && cfg->comp_done & MONO_COMP_LIVENESS) {
14975                 for (i = 0; i < cfg->num_varinfo; ++i) {
14976                         int vreg = MONO_VARINFO (cfg, i)->vreg;
14977                         MonoInst *ins;
14978
14979                         if (live_range_start [vreg]) {
14980                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_START);
14981                                 ins->inst_c0 = i;
14982                                 ins->inst_c1 = vreg;
14983                                 mono_bblock_insert_after_ins (live_range_start_bb [vreg], live_range_start [vreg], ins);
14984                         }
14985                         if (live_range_end [vreg]) {
14986                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_END);
14987                                 ins->inst_c0 = i;
14988                                 ins->inst_c1 = vreg;
14989                                 if (live_range_end [vreg] == live_range_end_bb [vreg]->last_ins)
14990                                         mono_add_ins_to_end (live_range_end_bb [vreg], ins);
14991                                 else
14992                                         mono_bblock_insert_after_ins (live_range_end_bb [vreg], live_range_end [vreg], ins);
14993                         }
14994                 }
14995         }
14996
14997         if (cfg->gsharedvt_locals_var_ins) {
14998                 /* Nullify if unused */
14999                 cfg->gsharedvt_locals_var_ins->opcode = OP_PCONST;
15000                 cfg->gsharedvt_locals_var_ins->inst_imm = 0;
15001         }
15002
15003         g_free (live_range_start);
15004         g_free (live_range_end);
15005         g_free (live_range_start_bb);
15006         g_free (live_range_end_bb);
15007 }
15008
15009 static void
15010 mono_decompose_typecheck (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins)
15011 {
15012         MonoInst *ret, *move, *source;
15013         MonoClass *klass = ins->klass;
15014         int context_used = mini_class_check_context_used (cfg, klass);
15015         int is_isinst = ins->opcode == OP_ISINST;
15016         g_assert (is_isinst || ins->opcode == OP_CASTCLASS);
15017         source = get_vreg_to_inst (cfg, ins->sreg1);
15018         if (!source || source == (MonoInst *) -1)
15019                 source = mono_compile_create_var_for_vreg (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL, ins->sreg1);
15020         g_assert (source && source != (MonoInst *) -1);
15021
15022         MonoBasicBlock *first_bb;
15023         NEW_BBLOCK (cfg, first_bb);
15024         cfg->cbb = first_bb;
15025
15026         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
15027                 if (is_isinst)
15028                         ret = emit_isinst_with_cache_nonshared (cfg, source, klass);
15029                 else
15030                         ret = emit_castclass_with_cache_nonshared (cfg, source, klass);
15031         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
15032                 MonoInst *iargs [1];
15033                 int costs;
15034
15035                 iargs [0] = source;
15036                 if (is_isinst) {
15037                         MonoMethod *wrapper = mono_marshal_get_isinst (klass);
15038                         costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), iargs, 0, 0, TRUE);
15039                 } else {
15040                         MonoMethod *wrapper = mono_marshal_get_castclass (klass);
15041                         save_cast_details (cfg, klass, source->dreg, TRUE);
15042                         costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), iargs, 0, 0, TRUE);
15043                         reset_cast_details (cfg);
15044                 }
15045                 g_assert (costs > 0);
15046                 ret = iargs [0];
15047         } else {
15048                 if (is_isinst)
15049                         ret = handle_isinst (cfg, klass, source, context_used);
15050                 else
15051                         ret = handle_castclass (cfg, klass, source, context_used);
15052         }
15053         EMIT_NEW_UNALU (cfg, move, OP_MOVE, ins->dreg, ret->dreg);
15054
15055         g_assert (cfg->cbb->code || first_bb->code);
15056         MonoInst *prev = ins->prev;
15057         mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
15058 }
15059
15060 void
15061 mono_decompose_typechecks (MonoCompile *cfg)
15062 {
15063         for (MonoBasicBlock *bb = cfg->bb_entry; bb; bb = bb->next_bb) {
15064                 MonoInst *ins;
15065                 MONO_BB_FOR_EACH_INS (bb, ins) {
15066                         switch (ins->opcode) {
15067                         case OP_ISINST:
15068                         case OP_CASTCLASS:
15069                                 mono_decompose_typecheck (cfg, bb, ins);
15070                                 break;
15071                         }
15072                 }
15073         }
15074 }
15075
15076
15077 /**
15078  * FIXME:
15079  * - use 'iadd' instead of 'int_add'
15080  * - handling ovf opcodes: decompose in method_to_ir.
15081  * - unify iregs/fregs
15082  *   -> partly done, the missing parts are:
15083  *   - a more complete unification would involve unifying the hregs as well, so
15084  *     code wouldn't need if (fp) all over the place. but that would mean the hregs
15085  *     would no longer map to the machine hregs, so the code generators would need to
15086  *     be modified. Also, on ia64 for example, niregs + nfregs > 256 -> bitmasks
15087  *     wouldn't work any more. Duplicating the code in mono_local_regalloc () into
15088  *     fp/non-fp branches speeds it up by about 15%.
15089  * - use sext/zext opcodes instead of shifts
15090  * - add OP_ICALL
15091  * - get rid of TEMPLOADs if possible and use vregs instead
15092  * - clean up usage of OP_P/OP_ opcodes
15093  * - cleanup usage of DUMMY_USE
15094  * - cleanup the setting of ins->type for MonoInst's which are pushed on the 
15095  *   stack
15096  * - set the stack type and allocate a dreg in the EMIT_NEW macros
15097  * - get rid of all the <foo>2 stuff when the new JIT is ready.
15098  * - make sure handle_stack_args () is called before the branch is emitted
15099  * - when the new IR is done, get rid of all unused stuff
15100  * - COMPARE/BEQ as separate instructions or unify them ?
15101  *   - keeping them separate allows specialized compare instructions like
15102  *     compare_imm, compare_membase
15103  *   - most back ends unify fp compare+branch, fp compare+ceq
15104  * - integrate mono_save_args into inline_method
15105  * - get rid of the empty bblocks created by MONO_EMIT_NEW_BRACH_BLOCK2
15106  * - handle long shift opts on 32 bit platforms somehow: they require 
15107  *   3 sregs (2 for arg1 and 1 for arg2)
15108  * - make byref a 'normal' type.
15109  * - use vregs for bb->out_stacks if possible, handle_global_vreg will make them a
15110  *   variable if needed.
15111  * - do not start a new IL level bblock when cfg->cbb is changed by a function call
15112  *   like inline_method.
15113  * - remove inlining restrictions
15114  * - fix LNEG and enable cfold of INEG
15115  * - generalize x86 optimizations like ldelema as a peephole optimization
15116  * - add store_mem_imm for amd64
15117  * - optimize the loading of the interruption flag in the managed->native wrappers
15118  * - avoid special handling of OP_NOP in passes
15119  * - move code inserting instructions into one function/macro.
15120  * - try a coalescing phase after liveness analysis
15121  * - add float -> vreg conversion + local optimizations on !x86
15122  * - figure out how to handle decomposed branches during optimizations, ie.
15123  *   compare+branch, op_jump_table+op_br etc.
15124  * - promote RuntimeXHandles to vregs
15125  * - vtype cleanups:
15126  *   - add a NEW_VARLOADA_VREG macro
15127  * - the vtype optimizations are blocked by the LDADDR opcodes generated for 
15128  *   accessing vtype fields.
15129  * - get rid of I8CONST on 64 bit platforms
15130  * - dealing with the increase in code size due to branches created during opcode
15131  *   decomposition:
15132  *   - use extended basic blocks
15133  *     - all parts of the JIT
15134  *     - handle_global_vregs () && local regalloc
15135  *   - avoid introducing global vregs during decomposition, like 'vtable' in isinst
15136  * - sources of increase in code size:
15137  *   - vtypes
15138  *   - long compares
15139  *   - isinst and castclass
15140  *   - lvregs not allocated to global registers even if used multiple times
15141  * - call cctors outside the JIT, to make -v output more readable and JIT timings more
15142  *   meaningful.
15143  * - check for fp stack leakage in other opcodes too. (-> 'exceptions' optimization)
15144  * - add all micro optimizations from the old JIT
15145  * - put tree optimizations into the deadce pass
15146  * - decompose op_start_handler/op_endfilter/op_endfinally earlier using an arch
15147  *   specific function.
15148  * - unify the float comparison opcodes with the other comparison opcodes, i.e.
15149  *   fcompare + branchCC.
15150  * - create a helper function for allocating a stack slot, taking into account 
15151  *   MONO_CFG_HAS_SPILLUP.
15152  * - merge r68207.
15153  * - merge the ia64 switch changes.
15154  * - optimize mono_regstate2_alloc_int/float.
15155  * - fix the pessimistic handling of variables accessed in exception handler blocks.
15156  * - need to write a tree optimization pass, but the creation of trees is difficult, i.e.
15157  *   parts of the tree could be separated by other instructions, killing the tree
15158  *   arguments, or stores killing loads etc. Also, should we fold loads into other
15159  *   instructions if the result of the load is used multiple times ?
15160  * - make the REM_IMM optimization in mini-x86.c arch-independent.
15161  * - LAST MERGE: 108395.
15162  * - when returning vtypes in registers, generate IR and append it to the end of the
15163  *   last bb instead of doing it in the epilog.
15164  * - change the store opcodes so they use sreg1 instead of dreg to store the base register.
15165  */
15166
15167 /*
15168
15169 NOTES
15170 -----
15171
15172 - When to decompose opcodes:
15173   - earlier: this makes some optimizations hard to implement, since the low level IR
15174   no longer contains the neccessary information. But it is easier to do.
15175   - later: harder to implement, enables more optimizations.
15176 - Branches inside bblocks:
15177   - created when decomposing complex opcodes. 
15178     - branches to another bblock: harmless, but not tracked by the branch 
15179       optimizations, so need to branch to a label at the start of the bblock.
15180     - branches to inside the same bblock: very problematic, trips up the local
15181       reg allocator. Can be fixed by spitting the current bblock, but that is a
15182       complex operation, since some local vregs can become global vregs etc.
15183 - Local/global vregs:
15184   - local vregs: temporary vregs used inside one bblock. Assigned to hregs by the
15185     local register allocator.
15186   - global vregs: used in more than one bblock. Have an associated MonoMethodVar
15187     structure, created by mono_create_var (). Assigned to hregs or the stack by
15188     the global register allocator.
15189 - When to do optimizations like alu->alu_imm:
15190   - earlier -> saves work later on since the IR will be smaller/simpler
15191   - later -> can work on more instructions
15192 - Handling of valuetypes:
15193   - When a vtype is pushed on the stack, a new temporary is created, an 
15194     instruction computing its address (LDADDR) is emitted and pushed on
15195     the stack. Need to optimize cases when the vtype is used immediately as in
15196     argument passing, stloc etc.
15197 - Instead of the to_end stuff in the old JIT, simply call the function handling
15198   the values on the stack before emitting the last instruction of the bb.
15199 */
15200
15201 #endif /* DISABLE_JIT */