[jit] Fix the saving of the 'cfg->ret_var_set' flag when inlining, it was set to...
[mono.git] / mono / mini / method-to-ir.c
1 /**
2  * \file
3  * Convert CIL to the JIT internal representation
4  *
5  * Author:
6  *   Paolo Molaro (lupus@ximian.com)
7  *   Dietmar Maurer (dietmar@ximian.com)
8  *
9  * (C) 2002 Ximian, Inc.
10  * Copyright 2003-2010 Novell, Inc (http://www.novell.com)
11  * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
12  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
13  */
14
15 #include <config.h>
16 #include <mono/utils/mono-compiler.h>
17 #include "mini.h"
18
19 #ifndef DISABLE_JIT
20
21 #include <signal.h>
22
23 #ifdef HAVE_UNISTD_H
24 #include <unistd.h>
25 #endif
26
27 #include <math.h>
28 #include <string.h>
29 #include <ctype.h>
30
31 #ifdef HAVE_SYS_TIME_H
32 #include <sys/time.h>
33 #endif
34
35 #ifdef HAVE_ALLOCA_H
36 #include <alloca.h>
37 #endif
38
39 #include <mono/utils/memcheck.h>
40 #include <mono/metadata/abi-details.h>
41 #include <mono/metadata/assembly.h>
42 #include <mono/metadata/attrdefs.h>
43 #include <mono/metadata/loader.h>
44 #include <mono/metadata/tabledefs.h>
45 #include <mono/metadata/class.h>
46 #include <mono/metadata/object.h>
47 #include <mono/metadata/exception.h>
48 #include <mono/metadata/opcodes.h>
49 #include <mono/metadata/mono-endian.h>
50 #include <mono/metadata/tokentype.h>
51 #include <mono/metadata/tabledefs.h>
52 #include <mono/metadata/marshal.h>
53 #include <mono/metadata/debug-helpers.h>
54 #include <mono/metadata/debug-internals.h>
55 #include <mono/metadata/gc-internals.h>
56 #include <mono/metadata/security-manager.h>
57 #include <mono/metadata/threads-types.h>
58 #include <mono/metadata/security-core-clr.h>
59 #include <mono/metadata/profiler-private.h>
60 #include <mono/metadata/profiler.h>
61 #include <mono/metadata/monitor.h>
62 #include <mono/utils/mono-memory-model.h>
63 #include <mono/utils/mono-error-internals.h>
64 #include <mono/metadata/mono-basic-block.h>
65 #include <mono/metadata/reflection-internals.h>
66 #include <mono/utils/mono-threads-coop.h>
67
68 #include "trace.h"
69
70 #include "ir-emit.h"
71
72 #include "jit-icalls.h"
73 #include "jit.h"
74 #include "debugger-agent.h"
75 #include "seq-points.h"
76 #include "aot-compiler.h"
77 #include "mini-llvm.h"
78
79 #define BRANCH_COST 10
80 #define INLINE_LENGTH_LIMIT 20
81
82 /* These have 'cfg' as an implicit argument */
83 #define INLINE_FAILURE(msg) do {                                                                        \
84         if ((cfg->method != cfg->current_method) && (cfg->current_method->wrapper_type == MONO_WRAPPER_NONE)) { \
85                 inline_failure (cfg, msg);                                                                              \
86                 goto exception_exit;                                                                                    \
87         } \
88         } while (0)
89 #define CHECK_CFG_EXCEPTION do {\
90                 if (cfg->exception_type != MONO_EXCEPTION_NONE) \
91                         goto exception_exit;                                            \
92         } while (0)
93 #define FIELD_ACCESS_FAILURE(method, field) do {                                        \
94                 field_access_failure ((cfg), (method), (field));                        \
95                 goto exception_exit;    \
96         } while (0)
97 #define GENERIC_SHARING_FAILURE(opcode) do {            \
98                 if (cfg->gshared) {                                                                     \
99                         gshared_failure (cfg, opcode, __FILE__, __LINE__);      \
100                         goto exception_exit;    \
101                 }                       \
102         } while (0)
103 #define GSHAREDVT_FAILURE(opcode) do {          \
104         if (cfg->gsharedvt) {                                                                                           \
105                 gsharedvt_failure (cfg, opcode, __FILE__, __LINE__);                    \
106                 goto exception_exit;                                                                                    \
107         }                                                                                                                                       \
108         } while (0)
109 #define OUT_OF_MEMORY_FAILURE do {      \
110                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);                \
111                 mono_error_set_out_of_memory (&cfg->error, "");                                 \
112                 goto exception_exit;    \
113         } while (0)
114 #define DISABLE_AOT(cfg) do { \
115                 if ((cfg)->verbose_level >= 2)                                            \
116                         printf ("AOT disabled: %s:%d\n", __FILE__, __LINE__);   \
117                 (cfg)->disable_aot = TRUE;                                                        \
118         } while (0)
119 #define LOAD_ERROR do { \
120                 break_on_unverified ();                                                         \
121                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD); \
122                 goto exception_exit;                                                                    \
123         } while (0)
124
125 #define TYPE_LOAD_ERROR(klass) do { \
126                 cfg->exception_ptr = klass; \
127                 LOAD_ERROR;                                     \
128         } while (0)
129
130 #define CHECK_CFG_ERROR do {\
131                 if (!mono_error_ok (&cfg->error)) { \
132                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);        \
133                         goto mono_error_exit; \
134                 } \
135         } while (0)
136
137 /* Determine whenever 'ins' represents a load of the 'this' argument */
138 #define MONO_CHECK_THIS(ins) (mono_method_signature (cfg->method)->hasthis && ((ins)->opcode == OP_MOVE) && ((ins)->sreg1 == cfg->args [0]->dreg))
139
140 static int ldind_to_load_membase (int opcode);
141 static int stind_to_store_membase (int opcode);
142
143 int mono_op_to_op_imm (int opcode);
144 int mono_op_to_op_imm_noemul (int opcode);
145
146 static int inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
147                                                   guchar *ip, guint real_offset, gboolean inline_always);
148 static MonoInst*
149 emit_llvmonly_virtual_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used, MonoInst **sp);
150
151 /* helper methods signatures */
152 static MonoMethodSignature *helper_sig_domain_get;
153 static MonoMethodSignature *helper_sig_rgctx_lazy_fetch_trampoline;
154 static MonoMethodSignature *helper_sig_llvmonly_imt_trampoline;
155 static MonoMethodSignature *helper_sig_jit_thread_attach;
156 static MonoMethodSignature *helper_sig_get_tls_tramp;
157 static MonoMethodSignature *helper_sig_set_tls_tramp;
158
159 /* type loading helpers */
160 static GENERATE_GET_CLASS_WITH_CACHE (runtime_helpers, "System.Runtime.CompilerServices", "RuntimeHelpers")
161 static GENERATE_TRY_GET_CLASS_WITH_CACHE (debuggable_attribute, "System.Diagnostics", "DebuggableAttribute")
162
163 /*
164  * Instruction metadata
165  */
166 #ifdef MINI_OP
167 #undef MINI_OP
168 #endif
169 #ifdef MINI_OP3
170 #undef MINI_OP3
171 #endif
172 #define MINI_OP(a,b,dest,src1,src2) dest, src1, src2, ' ',
173 #define MINI_OP3(a,b,dest,src1,src2,src3) dest, src1, src2, src3,
174 #define NONE ' '
175 #define IREG 'i'
176 #define FREG 'f'
177 #define VREG 'v'
178 #define XREG 'x'
179 #if SIZEOF_REGISTER == 8 && SIZEOF_REGISTER == SIZEOF_VOID_P
180 #define LREG IREG
181 #else
182 #define LREG 'l'
183 #endif
184 /* keep in sync with the enum in mini.h */
185 const char
186 ins_info[] = {
187 #include "mini-ops.h"
188 };
189 #undef MINI_OP
190 #undef MINI_OP3
191
192 #define MINI_OP(a,b,dest,src1,src2) ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0)),
193 #define MINI_OP3(a,b,dest,src1,src2,src3) ((src3) != NONE ? 3 : ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0))),
194 /* 
195  * This should contain the index of the last sreg + 1. This is not the same
196  * as the number of sregs for opcodes like IA64_CMP_EQ_IMM.
197  */
198 const gint8 ins_sreg_counts[] = {
199 #include "mini-ops.h"
200 };
201 #undef MINI_OP
202 #undef MINI_OP3
203
204 guint32
205 mono_alloc_ireg (MonoCompile *cfg)
206 {
207         return alloc_ireg (cfg);
208 }
209
210 guint32
211 mono_alloc_lreg (MonoCompile *cfg)
212 {
213         return alloc_lreg (cfg);
214 }
215
216 guint32
217 mono_alloc_freg (MonoCompile *cfg)
218 {
219         return alloc_freg (cfg);
220 }
221
222 guint32
223 mono_alloc_preg (MonoCompile *cfg)
224 {
225         return alloc_preg (cfg);
226 }
227
228 guint32
229 mono_alloc_dreg (MonoCompile *cfg, MonoStackType stack_type)
230 {
231         return alloc_dreg (cfg, stack_type);
232 }
233
234 /*
235  * mono_alloc_ireg_ref:
236  *
237  *   Allocate an IREG, and mark it as holding a GC ref.
238  */
239 guint32
240 mono_alloc_ireg_ref (MonoCompile *cfg)
241 {
242         return alloc_ireg_ref (cfg);
243 }
244
245 /*
246  * mono_alloc_ireg_mp:
247  *
248  *   Allocate an IREG, and mark it as holding a managed pointer.
249  */
250 guint32
251 mono_alloc_ireg_mp (MonoCompile *cfg)
252 {
253         return alloc_ireg_mp (cfg);
254 }
255
256 /*
257  * mono_alloc_ireg_copy:
258  *
259  *   Allocate an IREG with the same GC type as VREG.
260  */
261 guint32
262 mono_alloc_ireg_copy (MonoCompile *cfg, guint32 vreg)
263 {
264         if (vreg_is_ref (cfg, vreg))
265                 return alloc_ireg_ref (cfg);
266         else if (vreg_is_mp (cfg, vreg))
267                 return alloc_ireg_mp (cfg);
268         else
269                 return alloc_ireg (cfg);
270 }
271
272 guint
273 mono_type_to_regmove (MonoCompile *cfg, MonoType *type)
274 {
275         if (type->byref)
276                 return OP_MOVE;
277
278         type = mini_get_underlying_type (type);
279 handle_enum:
280         switch (type->type) {
281         case MONO_TYPE_I1:
282         case MONO_TYPE_U1:
283                 return OP_MOVE;
284         case MONO_TYPE_I2:
285         case MONO_TYPE_U2:
286                 return OP_MOVE;
287         case MONO_TYPE_I4:
288         case MONO_TYPE_U4:
289                 return OP_MOVE;
290         case MONO_TYPE_I:
291         case MONO_TYPE_U:
292         case MONO_TYPE_PTR:
293         case MONO_TYPE_FNPTR:
294                 return OP_MOVE;
295         case MONO_TYPE_CLASS:
296         case MONO_TYPE_STRING:
297         case MONO_TYPE_OBJECT:
298         case MONO_TYPE_SZARRAY:
299         case MONO_TYPE_ARRAY:    
300                 return OP_MOVE;
301         case MONO_TYPE_I8:
302         case MONO_TYPE_U8:
303 #if SIZEOF_REGISTER == 8
304                 return OP_MOVE;
305 #else
306                 return OP_LMOVE;
307 #endif
308         case MONO_TYPE_R4:
309                 return cfg->r4fp ? OP_RMOVE : OP_FMOVE;
310         case MONO_TYPE_R8:
311                 return OP_FMOVE;
312         case MONO_TYPE_VALUETYPE:
313                 if (type->data.klass->enumtype) {
314                         type = mono_class_enum_basetype (type->data.klass);
315                         goto handle_enum;
316                 }
317                 if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (type)))
318                         return OP_XMOVE;
319                 return OP_VMOVE;
320         case MONO_TYPE_TYPEDBYREF:
321                 return OP_VMOVE;
322         case MONO_TYPE_GENERICINST:
323                 if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (type)))
324                         return OP_XMOVE;
325                 type = &type->data.generic_class->container_class->byval_arg;
326                 goto handle_enum;
327         case MONO_TYPE_VAR:
328         case MONO_TYPE_MVAR:
329                 g_assert (cfg->gshared);
330                 if (mini_type_var_is_vt (type))
331                         return OP_VMOVE;
332                 else
333                         return mono_type_to_regmove (cfg, mini_get_underlying_type (type));
334         default:
335                 g_error ("unknown type 0x%02x in type_to_regstore", type->type);
336         }
337         return -1;
338 }
339
340 void
341 mono_print_bb (MonoBasicBlock *bb, const char *msg)
342 {
343         int i;
344         MonoInst *tree;
345         GString *str = g_string_new ("");
346
347         g_string_append_printf (str, "%s %d: [IN: ", msg, bb->block_num);
348         for (i = 0; i < bb->in_count; ++i)
349                 g_string_append_printf (str, " BB%d(%d)", bb->in_bb [i]->block_num, bb->in_bb [i]->dfn);
350         g_string_append_printf (str, ", OUT: ");
351         for (i = 0; i < bb->out_count; ++i)
352                 g_string_append_printf (str, " BB%d(%d)", bb->out_bb [i]->block_num, bb->out_bb [i]->dfn);
353         g_string_append_printf (str, " ]\n");
354
355         g_print ("%s", str->str);
356         g_string_free (str, TRUE);
357
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_trampoline = mono_create_icall_signature ("ptr ptr ptr");
368         helper_sig_jit_thread_attach = mono_create_icall_signature ("ptr ptr");
369         helper_sig_get_tls_tramp = mono_create_icall_signature ("ptr");
370         helper_sig_set_tls_tramp = mono_create_icall_signature ("void ptr");
371 }
372
373 static MONO_NEVER_INLINE void
374 break_on_unverified (void)
375 {
376         if (mini_get_debug_options ()->break_on_unverified)
377                 G_BREAKPOINT ();
378 }
379
380 static MONO_NEVER_INLINE void
381 field_access_failure (MonoCompile *cfg, MonoMethod *method, MonoClassField *field)
382 {
383         char *method_fname = mono_method_full_name (method, TRUE);
384         char *field_fname = mono_field_full_name (field);
385         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
386         mono_error_set_generic_error (&cfg->error, "System", "FieldAccessException", "Field `%s' is inaccessible from method `%s'\n", field_fname, method_fname);
387         g_free (method_fname);
388         g_free (field_fname);
389 }
390
391 static MONO_NEVER_INLINE void
392 inline_failure (MonoCompile *cfg, const char *msg)
393 {
394         if (cfg->verbose_level >= 2)
395                 printf ("inline failed: %s\n", msg);
396         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INLINE_FAILED);
397 }
398
399 static MONO_NEVER_INLINE void
400 gshared_failure (MonoCompile *cfg, int opcode, const char *file, int line)
401 {
402         if (cfg->verbose_level > 2)                                                                                     \
403                 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);
404         mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED);
405 }
406
407 static MONO_NEVER_INLINE void
408 gsharedvt_failure (MonoCompile *cfg, int opcode, const char *file, int line)
409 {
410         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);
411         if (cfg->verbose_level >= 2)
412                 printf ("%s\n", cfg->exception_message);
413         mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED);
414 }
415
416 /*
417  * When using gsharedvt, some instatiations might be verifiable, and some might be not. i.e. 
418  * foo<T> (int i) { ldarg.0; box T; }
419  */
420 #define UNVERIFIED do { \
421         if (cfg->gsharedvt) { \
422                 if (cfg->verbose_level > 2)                                                                     \
423                         printf ("gsharedvt method failed to verify, falling back to instantiation.\n"); \
424                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED); \
425                 goto exception_exit;                                                                                    \
426         }                                                                                                                                       \
427         break_on_unverified ();                                                                                         \
428         goto unverified;                                                                                                        \
429 } while (0)
430
431 #define GET_BBLOCK(cfg,tblock,ip) do {  \
432                 (tblock) = cfg->cil_offset_to_bb [(ip) - cfg->cil_start]; \
433                 if (!(tblock)) {        \
434                         if ((ip) >= end || (ip) < header->code) UNVERIFIED; \
435             NEW_BBLOCK (cfg, (tblock)); \
436                         (tblock)->cil_code = (ip);      \
437                         ADD_BBLOCK (cfg, (tblock));     \
438                 } \
439         } while (0)
440
441 #if defined(TARGET_X86) || defined(TARGET_AMD64)
442 #define EMIT_NEW_X86_LEA(cfg,dest,sr1,sr2,shift,imm) do { \
443                 MONO_INST_NEW (cfg, dest, OP_X86_LEA); \
444                 (dest)->dreg = alloc_ireg_mp ((cfg)); \
445                 (dest)->sreg1 = (sr1); \
446                 (dest)->sreg2 = (sr2); \
447                 (dest)->inst_imm = (imm); \
448                 (dest)->backend.shift_amount = (shift); \
449                 MONO_ADD_INS ((cfg)->cbb, (dest)); \
450         } while (0)
451 #endif
452
453 /* Emit conversions so both operands of a binary opcode are of the same type */
454 static void
455 add_widen_op (MonoCompile *cfg, MonoInst *ins, MonoInst **arg1_ref, MonoInst **arg2_ref)
456 {
457         MonoInst *arg1 = *arg1_ref;
458         MonoInst *arg2 = *arg2_ref;
459
460         if (cfg->r4fp &&
461                 ((arg1->type == STACK_R4 && arg2->type == STACK_R8) ||
462                  (arg1->type == STACK_R8 && arg2->type == STACK_R4))) {
463                 MonoInst *conv;
464
465                 /* Mixing r4/r8 is allowed by the spec */
466                 if (arg1->type == STACK_R4) {
467                         int dreg = alloc_freg (cfg);
468
469                         EMIT_NEW_UNALU (cfg, conv, OP_RCONV_TO_R8, dreg, arg1->dreg);
470                         conv->type = STACK_R8;
471                         ins->sreg1 = dreg;
472                         *arg1_ref = conv;
473                 }
474                 if (arg2->type == STACK_R4) {
475                         int dreg = alloc_freg (cfg);
476
477                         EMIT_NEW_UNALU (cfg, conv, OP_RCONV_TO_R8, dreg, arg2->dreg);
478                         conv->type = STACK_R8;
479                         ins->sreg2 = dreg;
480                         *arg2_ref = conv;
481                 }
482         }
483
484 #if SIZEOF_REGISTER == 8
485         /* FIXME: Need to add many more cases */
486         if ((arg1)->type == STACK_PTR && (arg2)->type == STACK_I4) {
487                 MonoInst *widen;
488
489                 int dr = alloc_preg (cfg);
490                 EMIT_NEW_UNALU (cfg, widen, OP_SEXT_I4, dr, (arg2)->dreg);
491                 (ins)->sreg2 = widen->dreg;
492         }
493 #endif
494 }
495
496 #define ADD_BINOP(op) do {      \
497                 MONO_INST_NEW (cfg, ins, (op)); \
498                 sp -= 2;        \
499                 ins->sreg1 = sp [0]->dreg;      \
500                 ins->sreg2 = sp [1]->dreg;      \
501                 type_from_op (cfg, ins, sp [0], sp [1]);        \
502                 CHECK_TYPE (ins);       \
503                 /* Have to insert a widening op */               \
504         add_widen_op (cfg, ins, &sp [0], &sp [1]);               \
505         ins->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type); \
506         MONO_ADD_INS ((cfg)->cbb, (ins)); \
507         *sp++ = mono_decompose_opcode ((cfg), (ins));   \
508         } while (0)
509
510 #define ADD_UNOP(op) do {       \
511                 MONO_INST_NEW (cfg, ins, (op)); \
512                 sp--;   \
513                 ins->sreg1 = sp [0]->dreg;      \
514                 type_from_op (cfg, ins, sp [0], NULL);  \
515                 CHECK_TYPE (ins);       \
516         (ins)->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type); \
517         MONO_ADD_INS ((cfg)->cbb, (ins)); \
518                 *sp++ = mono_decompose_opcode (cfg, ins);       \
519         } while (0)
520
521 #define ADD_BINCOND(next_block) do {    \
522                 MonoInst *cmp;  \
523                 sp -= 2; \
524                 MONO_INST_NEW(cfg, cmp, OP_COMPARE);    \
525                 cmp->sreg1 = sp [0]->dreg;      \
526                 cmp->sreg2 = sp [1]->dreg;      \
527                 type_from_op (cfg, cmp, sp [0], sp [1]);        \
528                 CHECK_TYPE (cmp);       \
529                 add_widen_op (cfg, cmp, &sp [0], &sp [1]);                                              \
530                 type_from_op (cfg, ins, sp [0], sp [1]);                                                        \
531                 ins->inst_many_bb = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);   \
532                 GET_BBLOCK (cfg, tblock, target);               \
533                 link_bblock (cfg, cfg->cbb, tblock);    \
534                 ins->inst_true_bb = tblock;     \
535                 if ((next_block)) {     \
536                         link_bblock (cfg, cfg->cbb, (next_block));      \
537                         ins->inst_false_bb = (next_block);      \
538                         start_new_bblock = 1;   \
539                 } else {        \
540                         GET_BBLOCK (cfg, tblock, ip);           \
541                         link_bblock (cfg, cfg->cbb, tblock);    \
542                         ins->inst_false_bb = tblock;    \
543                         start_new_bblock = 2;   \
544                 }       \
545                 if (sp != stack_start) {                                                                        \
546                     handle_stack_args (cfg, stack_start, sp - stack_start); \
547                         CHECK_UNVERIFIABLE (cfg); \
548                 } \
549         MONO_ADD_INS (cfg->cbb, cmp); \
550                 MONO_ADD_INS (cfg->cbb, ins);   \
551         } while (0)
552
553 /* *
554  * link_bblock: Links two basic blocks
555  *
556  * links two basic blocks in the control flow graph, the 'from'
557  * argument is the starting block and the 'to' argument is the block
558  * the control flow ends to after 'from'.
559  */
560 static void
561 link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
562 {
563         MonoBasicBlock **newa;
564         int i, found;
565
566 #if 0
567         if (from->cil_code) {
568                 if (to->cil_code)
569                         printf ("edge from IL%04x to IL_%04x\n", from->cil_code - cfg->cil_code, to->cil_code - cfg->cil_code);
570                 else
571                         printf ("edge from IL%04x to exit\n", from->cil_code - cfg->cil_code);
572         } else {
573                 if (to->cil_code)
574                         printf ("edge from entry to IL_%04x\n", to->cil_code - cfg->cil_code);
575                 else
576                         printf ("edge from entry to exit\n");
577         }
578 #endif
579
580         found = FALSE;
581         for (i = 0; i < from->out_count; ++i) {
582                 if (to == from->out_bb [i]) {
583                         found = TRUE;
584                         break;
585                 }
586         }
587         if (!found) {
588                 newa = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (from->out_count + 1));
589                 for (i = 0; i < from->out_count; ++i) {
590                         newa [i] = from->out_bb [i];
591                 }
592                 newa [i] = to;
593                 from->out_count++;
594                 from->out_bb = newa;
595         }
596
597         found = FALSE;
598         for (i = 0; i < to->in_count; ++i) {
599                 if (from == to->in_bb [i]) {
600                         found = TRUE;
601                         break;
602                 }
603         }
604         if (!found) {
605                 newa = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (to->in_count + 1));
606                 for (i = 0; i < to->in_count; ++i) {
607                         newa [i] = to->in_bb [i];
608                 }
609                 newa [i] = from;
610                 to->in_count++;
611                 to->in_bb = newa;
612         }
613 }
614
615 void
616 mono_link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
617 {
618         link_bblock (cfg, from, to);
619 }
620
621 /**
622  * mono_find_block_region:
623  *
624  *   We mark each basic block with a region ID. We use that to avoid BB
625  *   optimizations when blocks are in different regions.
626  *
627  * Returns:
628  *   A region token that encodes where this region is, and information
629  *   about the clause owner for this block.
630  *
631  *   The region encodes the try/catch/filter clause that owns this block
632  *   as well as the type.  -1 is a special value that represents a block
633  *   that is in none of try/catch/filter.
634  */
635 static int
636 mono_find_block_region (MonoCompile *cfg, int offset)
637 {
638         MonoMethodHeader *header = cfg->header;
639         MonoExceptionClause *clause;
640         int i;
641
642         for (i = 0; i < header->num_clauses; ++i) {
643                 clause = &header->clauses [i];
644                 if ((clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) && (offset >= clause->data.filter_offset) &&
645                     (offset < (clause->handler_offset)))
646                         return ((i + 1) << 8) | MONO_REGION_FILTER | clause->flags;
647                            
648                 if (MONO_OFFSET_IN_HANDLER (clause, offset)) {
649                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY)
650                                 return ((i + 1) << 8) | MONO_REGION_FINALLY | clause->flags;
651                         else if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
652                                 return ((i + 1) << 8) | MONO_REGION_FAULT | clause->flags;
653                         else
654                                 return ((i + 1) << 8) | MONO_REGION_CATCH | clause->flags;
655                 }
656         }
657         for (i = 0; i < header->num_clauses; ++i) {
658                 clause = &header->clauses [i];
659
660                 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
661                         return ((i + 1) << 8) | clause->flags;
662         }
663
664         return -1;
665 }
666
667 static gboolean
668 ip_in_finally_clause (MonoCompile *cfg, int offset)
669 {
670         MonoMethodHeader *header = cfg->header;
671         MonoExceptionClause *clause;
672         int i;
673
674         for (i = 0; i < header->num_clauses; ++i) {
675                 clause = &header->clauses [i];
676                 if (clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY && clause->flags != MONO_EXCEPTION_CLAUSE_FAULT)
677                         continue;
678
679                 if (MONO_OFFSET_IN_HANDLER (clause, offset))
680                         return TRUE;
681         }
682         return FALSE;
683 }
684
685 static GList*
686 mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *target, int type)
687 {
688         MonoMethodHeader *header = cfg->header;
689         MonoExceptionClause *clause;
690         int i;
691         GList *res = NULL;
692
693         for (i = 0; i < header->num_clauses; ++i) {
694                 clause = &header->clauses [i];
695                 if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) && 
696                     (!MONO_OFFSET_IN_CLAUSE (clause, (target - header->code)))) {
697                         if (clause->flags == type)
698                                 res = g_list_append (res, clause);
699                 }
700         }
701         return res;
702 }
703
704 static void
705 mono_create_spvar_for_region (MonoCompile *cfg, int region)
706 {
707         MonoInst *var;
708
709         var = (MonoInst *)g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
710         if (var)
711                 return;
712
713         var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
714         /* prevent it from being register allocated */
715         var->flags |= MONO_INST_VOLATILE;
716
717         g_hash_table_insert (cfg->spvars, GINT_TO_POINTER (region), var);
718 }
719
720 MonoInst *
721 mono_find_exvar_for_offset (MonoCompile *cfg, int offset)
722 {
723         return (MonoInst *)g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
724 }
725
726 static MonoInst*
727 mono_create_exvar_for_offset (MonoCompile *cfg, int offset)
728 {
729         MonoInst *var;
730
731         var = (MonoInst *)g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
732         if (var)
733                 return var;
734
735         var = mono_compile_create_var (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL);
736         /* prevent it from being register allocated */
737         var->flags |= MONO_INST_VOLATILE;
738
739         g_hash_table_insert (cfg->exvars, GINT_TO_POINTER (offset), var);
740
741         return var;
742 }
743
744 /*
745  * Returns the type used in the eval stack when @type is loaded.
746  * FIXME: return a MonoType/MonoClass for the byref and VALUETYPE cases.
747  */
748 void
749 type_to_eval_stack_type (MonoCompile *cfg, MonoType *type, MonoInst *inst)
750 {
751         MonoClass *klass;
752
753         type = mini_get_underlying_type (type);
754         inst->klass = klass = mono_class_from_mono_type (type);
755         if (type->byref) {
756                 inst->type = STACK_MP;
757                 return;
758         }
759
760 handle_enum:
761         switch (type->type) {
762         case MONO_TYPE_VOID:
763                 inst->type = STACK_INV;
764                 return;
765         case MONO_TYPE_I1:
766         case MONO_TYPE_U1:
767         case MONO_TYPE_I2:
768         case MONO_TYPE_U2:
769         case MONO_TYPE_I4:
770         case MONO_TYPE_U4:
771                 inst->type = STACK_I4;
772                 return;
773         case MONO_TYPE_I:
774         case MONO_TYPE_U:
775         case MONO_TYPE_PTR:
776         case MONO_TYPE_FNPTR:
777                 inst->type = STACK_PTR;
778                 return;
779         case MONO_TYPE_CLASS:
780         case MONO_TYPE_STRING:
781         case MONO_TYPE_OBJECT:
782         case MONO_TYPE_SZARRAY:
783         case MONO_TYPE_ARRAY:    
784                 inst->type = STACK_OBJ;
785                 return;
786         case MONO_TYPE_I8:
787         case MONO_TYPE_U8:
788                 inst->type = STACK_I8;
789                 return;
790         case MONO_TYPE_R4:
791                 inst->type = cfg->r4_stack_type;
792                 break;
793         case MONO_TYPE_R8:
794                 inst->type = STACK_R8;
795                 return;
796         case MONO_TYPE_VALUETYPE:
797                 if (type->data.klass->enumtype) {
798                         type = mono_class_enum_basetype (type->data.klass);
799                         goto handle_enum;
800                 } else {
801                         inst->klass = klass;
802                         inst->type = STACK_VTYPE;
803                         return;
804                 }
805         case MONO_TYPE_TYPEDBYREF:
806                 inst->klass = mono_defaults.typed_reference_class;
807                 inst->type = STACK_VTYPE;
808                 return;
809         case MONO_TYPE_GENERICINST:
810                 type = &type->data.generic_class->container_class->byval_arg;
811                 goto handle_enum;
812         case MONO_TYPE_VAR:
813         case MONO_TYPE_MVAR:
814                 g_assert (cfg->gshared);
815                 if (mini_is_gsharedvt_type (type)) {
816                         g_assert (cfg->gsharedvt);
817                         inst->type = STACK_VTYPE;
818                 } else {
819                         type_to_eval_stack_type (cfg, mini_get_underlying_type (type), inst);
820                 }
821                 return;
822         default:
823                 g_error ("unknown type 0x%02x in eval stack type", type->type);
824         }
825 }
826
827 /*
828  * The following tables are used to quickly validate the IL code in type_from_op ().
829  */
830 static const char
831 bin_num_table [STACK_MAX] [STACK_MAX] = {
832         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
833         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
834         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
835         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
836         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8,  STACK_INV, STACK_INV, STACK_INV, STACK_R8},
837         {STACK_INV, STACK_MP,  STACK_INV, STACK_MP,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV},
838         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
839         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
840         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8, STACK_INV, STACK_INV, STACK_INV, STACK_R4}
841 };
842
843 static const char 
844 neg_table [] = {
845         STACK_INV, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_INV, STACK_INV, STACK_INV, STACK_R4
846 };
847
848 /* reduce the size of this table */
849 static const char
850 bin_int_table [STACK_MAX] [STACK_MAX] = {
851         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
852         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
853         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
854         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
855         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
856         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
857         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
858         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
859 };
860
861 static const char
862 bin_comp_table [STACK_MAX] [STACK_MAX] = {
863 /*      Inv i  L  p  F  &  O  vt r4 */
864         {0},
865         {0, 1, 0, 1, 0, 0, 0, 0}, /* i, int32 */
866         {0, 0, 1, 0, 0, 0, 0, 0}, /* L, int64 */
867         {0, 1, 0, 1, 0, 2, 4, 0}, /* p, ptr */
868         {0, 0, 0, 0, 1, 0, 0, 0, 1}, /* F, R8 */
869         {0, 0, 0, 2, 0, 1, 0, 0}, /* &, managed pointer */
870         {0, 0, 0, 4, 0, 0, 3, 0}, /* O, reference */
871         {0, 0, 0, 0, 0, 0, 0, 0}, /* vt value type */
872         {0, 0, 0, 0, 1, 0, 0, 0, 1}, /* r, r4 */
873 };
874
875 /* reduce the size of this table */
876 static const char
877 shift_table [STACK_MAX] [STACK_MAX] = {
878         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
879         {STACK_INV, STACK_I4,  STACK_INV, STACK_I4,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
880         {STACK_INV, STACK_I8,  STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
881         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
882         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
883         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
884         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
885         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
886 };
887
888 /*
889  * Tables to map from the non-specific opcode to the matching
890  * type-specific opcode.
891  */
892 /* handles from CEE_ADD to CEE_SHR_UN (CEE_REM_UN for floats) */
893 static const guint16
894 binops_op_map [STACK_MAX] = {
895         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
896 };
897
898 /* handles from CEE_NEG to CEE_CONV_U8 */
899 static const guint16
900 unops_op_map [STACK_MAX] = {
901         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
902 };
903
904 /* handles from CEE_CONV_U2 to CEE_SUB_OVF_UN */
905 static const guint16
906 ovfops_op_map [STACK_MAX] = {
907         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
908 };
909
910 /* handles from CEE_CONV_OVF_I1_UN to CEE_CONV_OVF_U_UN */
911 static const guint16
912 ovf2ops_op_map [STACK_MAX] = {
913         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
914 };
915
916 /* handles from CEE_CONV_OVF_I1 to CEE_CONV_OVF_U8 */
917 static const guint16
918 ovf3ops_op_map [STACK_MAX] = {
919         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
920 };
921
922 /* handles from CEE_BEQ to CEE_BLT_UN */
923 static const guint16
924 beqops_op_map [STACK_MAX] = {
925         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
926 };
927
928 /* handles from CEE_CEQ to CEE_CLT_UN */
929 static const guint16
930 ceqops_op_map [STACK_MAX] = {
931         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
932 };
933
934 /*
935  * Sets ins->type (the type on the eval stack) according to the
936  * type of the opcode and the arguments to it.
937  * Invalid IL code is marked by setting ins->type to the invalid value STACK_INV.
938  *
939  * FIXME: this function sets ins->type unconditionally in some cases, but
940  * it should set it to invalid for some types (a conv.x on an object)
941  */
942 static void
943 type_from_op (MonoCompile *cfg, MonoInst *ins, MonoInst *src1, MonoInst *src2)
944 {
945         switch (ins->opcode) {
946         /* binops */
947         case CEE_ADD:
948         case CEE_SUB:
949         case CEE_MUL:
950         case CEE_DIV:
951         case CEE_REM:
952                 /* FIXME: check unverifiable args for STACK_MP */
953                 ins->type = bin_num_table [src1->type] [src2->type];
954                 ins->opcode += binops_op_map [ins->type];
955                 break;
956         case CEE_DIV_UN:
957         case CEE_REM_UN:
958         case CEE_AND:
959         case CEE_OR:
960         case CEE_XOR:
961                 ins->type = bin_int_table [src1->type] [src2->type];
962                 ins->opcode += binops_op_map [ins->type];
963                 break;
964         case CEE_SHL:
965         case CEE_SHR:
966         case CEE_SHR_UN:
967                 ins->type = shift_table [src1->type] [src2->type];
968                 ins->opcode += binops_op_map [ins->type];
969                 break;
970         case OP_COMPARE:
971         case OP_LCOMPARE:
972         case OP_ICOMPARE:
973                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
974                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
975                         ins->opcode = OP_LCOMPARE;
976                 else if (src1->type == STACK_R4)
977                         ins->opcode = OP_RCOMPARE;
978                 else if (src1->type == STACK_R8)
979                         ins->opcode = OP_FCOMPARE;
980                 else
981                         ins->opcode = OP_ICOMPARE;
982                 break;
983         case OP_ICOMPARE_IMM:
984                 ins->type = bin_comp_table [src1->type] [src1->type] ? STACK_I4 : STACK_INV;
985                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
986                         ins->opcode = OP_LCOMPARE_IMM;          
987                 break;
988         case CEE_BEQ:
989         case CEE_BGE:
990         case CEE_BGT:
991         case CEE_BLE:
992         case CEE_BLT:
993         case CEE_BNE_UN:
994         case CEE_BGE_UN:
995         case CEE_BGT_UN:
996         case CEE_BLE_UN:
997         case CEE_BLT_UN:
998                 ins->opcode += beqops_op_map [src1->type];
999                 break;
1000         case OP_CEQ:
1001                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
1002                 ins->opcode += ceqops_op_map [src1->type];
1003                 break;
1004         case OP_CGT:
1005         case OP_CGT_UN:
1006         case OP_CLT:
1007         case OP_CLT_UN:
1008                 ins->type = (bin_comp_table [src1->type] [src2->type] & 1) ? STACK_I4: STACK_INV;
1009                 ins->opcode += ceqops_op_map [src1->type];
1010                 break;
1011         /* unops */
1012         case CEE_NEG:
1013                 ins->type = neg_table [src1->type];
1014                 ins->opcode += unops_op_map [ins->type];
1015                 break;
1016         case CEE_NOT:
1017                 if (src1->type >= STACK_I4 && src1->type <= STACK_PTR)
1018                         ins->type = src1->type;
1019                 else
1020                         ins->type = STACK_INV;
1021                 ins->opcode += unops_op_map [ins->type];
1022                 break;
1023         case CEE_CONV_I1:
1024         case CEE_CONV_I2:
1025         case CEE_CONV_I4:
1026         case CEE_CONV_U4:
1027                 ins->type = STACK_I4;
1028                 ins->opcode += unops_op_map [src1->type];
1029                 break;
1030         case CEE_CONV_R_UN:
1031                 ins->type = STACK_R8;
1032                 switch (src1->type) {
1033                 case STACK_I4:
1034                 case STACK_PTR:
1035                         ins->opcode = OP_ICONV_TO_R_UN;
1036                         break;
1037                 case STACK_I8:
1038                         ins->opcode = OP_LCONV_TO_R_UN; 
1039                         break;
1040                 }
1041                 break;
1042         case CEE_CONV_OVF_I1:
1043         case CEE_CONV_OVF_U1:
1044         case CEE_CONV_OVF_I2:
1045         case CEE_CONV_OVF_U2:
1046         case CEE_CONV_OVF_I4:
1047         case CEE_CONV_OVF_U4:
1048                 ins->type = STACK_I4;
1049                 ins->opcode += ovf3ops_op_map [src1->type];
1050                 break;
1051         case CEE_CONV_OVF_I_UN:
1052         case CEE_CONV_OVF_U_UN:
1053                 ins->type = STACK_PTR;
1054                 ins->opcode += ovf2ops_op_map [src1->type];
1055                 break;
1056         case CEE_CONV_OVF_I1_UN:
1057         case CEE_CONV_OVF_I2_UN:
1058         case CEE_CONV_OVF_I4_UN:
1059         case CEE_CONV_OVF_U1_UN:
1060         case CEE_CONV_OVF_U2_UN:
1061         case CEE_CONV_OVF_U4_UN:
1062                 ins->type = STACK_I4;
1063                 ins->opcode += ovf2ops_op_map [src1->type];
1064                 break;
1065         case CEE_CONV_U:
1066                 ins->type = STACK_PTR;
1067                 switch (src1->type) {
1068                 case STACK_I4:
1069                         ins->opcode = OP_ICONV_TO_U;
1070                         break;
1071                 case STACK_PTR:
1072                 case STACK_MP:
1073 #if SIZEOF_VOID_P == 8
1074                         ins->opcode = OP_LCONV_TO_U;
1075 #else
1076                         ins->opcode = OP_MOVE;
1077 #endif
1078                         break;
1079                 case STACK_I8:
1080                         ins->opcode = OP_LCONV_TO_U;
1081                         break;
1082                 case STACK_R8:
1083                         ins->opcode = OP_FCONV_TO_U;
1084                         break;
1085                 }
1086                 break;
1087         case CEE_CONV_I8:
1088         case CEE_CONV_U8:
1089                 ins->type = STACK_I8;
1090                 ins->opcode += unops_op_map [src1->type];
1091                 break;
1092         case CEE_CONV_OVF_I8:
1093         case CEE_CONV_OVF_U8:
1094                 ins->type = STACK_I8;
1095                 ins->opcode += ovf3ops_op_map [src1->type];
1096                 break;
1097         case CEE_CONV_OVF_U8_UN:
1098         case CEE_CONV_OVF_I8_UN:
1099                 ins->type = STACK_I8;
1100                 ins->opcode += ovf2ops_op_map [src1->type];
1101                 break;
1102         case CEE_CONV_R4:
1103                 ins->type = cfg->r4_stack_type;
1104                 ins->opcode += unops_op_map [src1->type];
1105                 break;
1106         case CEE_CONV_R8:
1107                 ins->type = STACK_R8;
1108                 ins->opcode += unops_op_map [src1->type];
1109                 break;
1110         case OP_CKFINITE:
1111                 ins->type = STACK_R8;           
1112                 break;
1113         case CEE_CONV_U2:
1114         case CEE_CONV_U1:
1115                 ins->type = STACK_I4;
1116                 ins->opcode += ovfops_op_map [src1->type];
1117                 break;
1118         case CEE_CONV_I:
1119         case CEE_CONV_OVF_I:
1120         case CEE_CONV_OVF_U:
1121                 ins->type = STACK_PTR;
1122                 ins->opcode += ovfops_op_map [src1->type];
1123                 break;
1124         case CEE_ADD_OVF:
1125         case CEE_ADD_OVF_UN:
1126         case CEE_MUL_OVF:
1127         case CEE_MUL_OVF_UN:
1128         case CEE_SUB_OVF:
1129         case CEE_SUB_OVF_UN:
1130                 ins->type = bin_num_table [src1->type] [src2->type];
1131                 ins->opcode += ovfops_op_map [src1->type];
1132                 if (ins->type == STACK_R8)
1133                         ins->type = STACK_INV;
1134                 break;
1135         case OP_LOAD_MEMBASE:
1136                 ins->type = STACK_PTR;
1137                 break;
1138         case OP_LOADI1_MEMBASE:
1139         case OP_LOADU1_MEMBASE:
1140         case OP_LOADI2_MEMBASE:
1141         case OP_LOADU2_MEMBASE:
1142         case OP_LOADI4_MEMBASE:
1143         case OP_LOADU4_MEMBASE:
1144                 ins->type = STACK_PTR;
1145                 break;
1146         case OP_LOADI8_MEMBASE:
1147                 ins->type = STACK_I8;
1148                 break;
1149         case OP_LOADR4_MEMBASE:
1150                 ins->type = cfg->r4_stack_type;
1151                 break;
1152         case OP_LOADR8_MEMBASE:
1153                 ins->type = STACK_R8;
1154                 break;
1155         default:
1156                 g_error ("opcode 0x%04x not handled in type from op", ins->opcode);
1157                 break;
1158         }
1159
1160         if (ins->type == STACK_MP)
1161                 ins->klass = mono_defaults.object_class;
1162 }
1163
1164 static MonoClass*
1165 ldind_to_type (int op)
1166 {
1167         switch (op) {
1168         case CEE_LDIND_I1: return mono_defaults.sbyte_class;
1169         case CEE_LDIND_U1: return mono_defaults.byte_class;
1170         case CEE_LDIND_I2: return mono_defaults.int16_class;
1171         case CEE_LDIND_U2: return mono_defaults.uint16_class;
1172         case CEE_LDIND_I4: return mono_defaults.int32_class;
1173         case CEE_LDIND_U4: return mono_defaults.uint32_class;
1174         case CEE_LDIND_I8: return mono_defaults.int64_class;
1175         case CEE_LDIND_I: return mono_defaults.int_class;
1176         case CEE_LDIND_R4: return mono_defaults.single_class;
1177         case CEE_LDIND_R8: return mono_defaults.double_class;
1178         case CEE_LDIND_REF:return mono_defaults.object_class; //FIXME we should try to return a more specific type
1179         default: g_error ("Unknown ldind type %d", op);
1180         }
1181 }
1182
1183 #if 0
1184
1185 static const char
1186 param_table [STACK_MAX] [STACK_MAX] = {
1187         {0},
1188 };
1189
1190 static int
1191 check_values_to_signature (MonoInst *args, MonoType *this_ins, MonoMethodSignature *sig)
1192 {
1193         int i;
1194
1195         if (sig->hasthis) {
1196                 switch (args->type) {
1197                 case STACK_I4:
1198                 case STACK_I8:
1199                 case STACK_R8:
1200                 case STACK_VTYPE:
1201                 case STACK_INV:
1202                         return 0;
1203                 }
1204                 args++;
1205         }
1206         for (i = 0; i < sig->param_count; ++i) {
1207                 switch (args [i].type) {
1208                 case STACK_INV:
1209                         return 0;
1210                 case STACK_MP:
1211                         if (!sig->params [i]->byref)
1212                                 return 0;
1213                         continue;
1214                 case STACK_OBJ:
1215                         if (sig->params [i]->byref)
1216                                 return 0;
1217                         switch (sig->params [i]->type) {
1218                         case MONO_TYPE_CLASS:
1219                         case MONO_TYPE_STRING:
1220                         case MONO_TYPE_OBJECT:
1221                         case MONO_TYPE_SZARRAY:
1222                         case MONO_TYPE_ARRAY:
1223                                 break;
1224                         default:
1225                                 return 0;
1226                         }
1227                         continue;
1228                 case STACK_R8:
1229                         if (sig->params [i]->byref)
1230                                 return 0;
1231                         if (sig->params [i]->type != MONO_TYPE_R4 && sig->params [i]->type != MONO_TYPE_R8)
1232                                 return 0;
1233                         continue;
1234                 case STACK_PTR:
1235                 case STACK_I4:
1236                 case STACK_I8:
1237                 case STACK_VTYPE:
1238                         break;
1239                 }
1240                 /*if (!param_table [args [i].type] [sig->params [i]->type])
1241                         return 0;*/
1242         }
1243         return 1;
1244 }
1245 #endif
1246
1247 /*
1248  * When we need a pointer to the current domain many times in a method, we
1249  * call mono_domain_get() once and we store the result in a local variable.
1250  * This function returns the variable that represents the MonoDomain*.
1251  */
1252 inline static MonoInst *
1253 mono_get_domainvar (MonoCompile *cfg)
1254 {
1255         if (!cfg->domainvar)
1256                 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1257         return cfg->domainvar;
1258 }
1259
1260 /*
1261  * The got_var contains the address of the Global Offset Table when AOT 
1262  * compiling.
1263  */
1264 MonoInst *
1265 mono_get_got_var (MonoCompile *cfg)
1266 {
1267         if (!cfg->compile_aot || !cfg->backend->need_got_var || cfg->llvm_only)
1268                 return NULL;
1269         if (!cfg->got_var) {
1270                 cfg->got_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1271         }
1272         return cfg->got_var;
1273 }
1274
1275 static void
1276 mono_create_rgctx_var (MonoCompile *cfg)
1277 {
1278         if (!cfg->rgctx_var) {
1279                 cfg->rgctx_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1280                 /* force the var to be stack allocated */
1281                 cfg->rgctx_var->flags |= MONO_INST_VOLATILE;
1282         }
1283 }
1284
1285 static MonoInst *
1286 mono_get_vtable_var (MonoCompile *cfg)
1287 {
1288         g_assert (cfg->gshared);
1289
1290         mono_create_rgctx_var (cfg);
1291
1292         return cfg->rgctx_var;
1293 }
1294
1295 static MonoType*
1296 type_from_stack_type (MonoInst *ins) {
1297         switch (ins->type) {
1298         case STACK_I4: return &mono_defaults.int32_class->byval_arg;
1299         case STACK_I8: return &mono_defaults.int64_class->byval_arg;
1300         case STACK_PTR: return &mono_defaults.int_class->byval_arg;
1301         case STACK_R4: return &mono_defaults.single_class->byval_arg;
1302         case STACK_R8: return &mono_defaults.double_class->byval_arg;
1303         case STACK_MP:
1304                 return &ins->klass->this_arg;
1305         case STACK_OBJ: return &mono_defaults.object_class->byval_arg;
1306         case STACK_VTYPE: return &ins->klass->byval_arg;
1307         default:
1308                 g_error ("stack type %d to monotype not handled\n", ins->type);
1309         }
1310         return NULL;
1311 }
1312
1313 static G_GNUC_UNUSED int
1314 type_to_stack_type (MonoCompile *cfg, MonoType *t)
1315 {
1316         t = mono_type_get_underlying_type (t);
1317         switch (t->type) {
1318         case MONO_TYPE_I1:
1319         case MONO_TYPE_U1:
1320         case MONO_TYPE_I2:
1321         case MONO_TYPE_U2:
1322         case MONO_TYPE_I4:
1323         case MONO_TYPE_U4:
1324                 return STACK_I4;
1325         case MONO_TYPE_I:
1326         case MONO_TYPE_U:
1327         case MONO_TYPE_PTR:
1328         case MONO_TYPE_FNPTR:
1329                 return STACK_PTR;
1330         case MONO_TYPE_CLASS:
1331         case MONO_TYPE_STRING:
1332         case MONO_TYPE_OBJECT:
1333         case MONO_TYPE_SZARRAY:
1334         case MONO_TYPE_ARRAY:    
1335                 return STACK_OBJ;
1336         case MONO_TYPE_I8:
1337         case MONO_TYPE_U8:
1338                 return STACK_I8;
1339         case MONO_TYPE_R4:
1340                 return cfg->r4_stack_type;
1341         case MONO_TYPE_R8:
1342                 return STACK_R8;
1343         case MONO_TYPE_VALUETYPE:
1344         case MONO_TYPE_TYPEDBYREF:
1345                 return STACK_VTYPE;
1346         case MONO_TYPE_GENERICINST:
1347                 if (mono_type_generic_inst_is_valuetype (t))
1348                         return STACK_VTYPE;
1349                 else
1350                         return STACK_OBJ;
1351                 break;
1352         default:
1353                 g_assert_not_reached ();
1354         }
1355
1356         return -1;
1357 }
1358
1359 static MonoClass*
1360 array_access_to_klass (int opcode)
1361 {
1362         switch (opcode) {
1363         case CEE_LDELEM_U1:
1364                 return mono_defaults.byte_class;
1365         case CEE_LDELEM_U2:
1366                 return mono_defaults.uint16_class;
1367         case CEE_LDELEM_I:
1368         case CEE_STELEM_I:
1369                 return mono_defaults.int_class;
1370         case CEE_LDELEM_I1:
1371         case CEE_STELEM_I1:
1372                 return mono_defaults.sbyte_class;
1373         case CEE_LDELEM_I2:
1374         case CEE_STELEM_I2:
1375                 return mono_defaults.int16_class;
1376         case CEE_LDELEM_I4:
1377         case CEE_STELEM_I4:
1378                 return mono_defaults.int32_class;
1379         case CEE_LDELEM_U4:
1380                 return mono_defaults.uint32_class;
1381         case CEE_LDELEM_I8:
1382         case CEE_STELEM_I8:
1383                 return mono_defaults.int64_class;
1384         case CEE_LDELEM_R4:
1385         case CEE_STELEM_R4:
1386                 return mono_defaults.single_class;
1387         case CEE_LDELEM_R8:
1388         case CEE_STELEM_R8:
1389                 return mono_defaults.double_class;
1390         case CEE_LDELEM_REF:
1391         case CEE_STELEM_REF:
1392                 return mono_defaults.object_class;
1393         default:
1394                 g_assert_not_reached ();
1395         }
1396         return NULL;
1397 }
1398
1399 /*
1400  * We try to share variables when possible
1401  */
1402 static MonoInst *
1403 mono_compile_get_interface_var (MonoCompile *cfg, int slot, MonoInst *ins)
1404 {
1405         MonoInst *res;
1406         int pos, vnum;
1407
1408         /* inlining can result in deeper stacks */ 
1409         if (slot >= cfg->header->max_stack)
1410                 return mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1411
1412         pos = ins->type - 1 + slot * STACK_MAX;
1413
1414         switch (ins->type) {
1415         case STACK_I4:
1416         case STACK_I8:
1417         case STACK_R8:
1418         case STACK_PTR:
1419         case STACK_MP:
1420         case STACK_OBJ:
1421                 if ((vnum = cfg->intvars [pos]))
1422                         return cfg->varinfo [vnum];
1423                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1424                 cfg->intvars [pos] = res->inst_c0;
1425                 break;
1426         default:
1427                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1428         }
1429         return res;
1430 }
1431
1432 static void
1433 mono_save_token_info (MonoCompile *cfg, MonoImage *image, guint32 token, gpointer key)
1434 {
1435         /* 
1436          * Don't use this if a generic_context is set, since that means AOT can't
1437          * look up the method using just the image+token.
1438          * table == 0 means this is a reference made from a wrapper.
1439          */
1440         if (cfg->compile_aot && !cfg->generic_context && (mono_metadata_token_table (token) > 0)) {
1441                 MonoJumpInfoToken *jump_info_token = (MonoJumpInfoToken *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoToken));
1442                 jump_info_token->image = image;
1443                 jump_info_token->token = token;
1444                 g_hash_table_insert (cfg->token_info_hash, key, jump_info_token);
1445         }
1446 }
1447
1448 /*
1449  * This function is called to handle items that are left on the evaluation stack
1450  * at basic block boundaries. What happens is that we save the values to local variables
1451  * and we reload them later when first entering the target basic block (with the
1452  * handle_loaded_temps () function).
1453  * A single joint point will use the same variables (stored in the array bb->out_stack or
1454  * bb->in_stack, if the basic block is before or after the joint point).
1455  *
1456  * This function needs to be called _before_ emitting the last instruction of
1457  * the bb (i.e. before emitting a branch).
1458  * If the stack merge fails at a join point, cfg->unverifiable is set.
1459  */
1460 static void
1461 handle_stack_args (MonoCompile *cfg, MonoInst **sp, int count)
1462 {
1463         int i, bindex;
1464         MonoBasicBlock *bb = cfg->cbb;
1465         MonoBasicBlock *outb;
1466         MonoInst *inst, **locals;
1467         gboolean found;
1468
1469         if (!count)
1470                 return;
1471         if (cfg->verbose_level > 3)
1472                 printf ("%d item(s) on exit from B%d\n", count, bb->block_num);
1473         if (!bb->out_scount) {
1474                 bb->out_scount = count;
1475                 //printf ("bblock %d has out:", bb->block_num);
1476                 found = FALSE;
1477                 for (i = 0; i < bb->out_count; ++i) {
1478                         outb = bb->out_bb [i];
1479                         /* exception handlers are linked, but they should not be considered for stack args */
1480                         if (outb->flags & BB_EXCEPTION_HANDLER)
1481                                 continue;
1482                         //printf (" %d", outb->block_num);
1483                         if (outb->in_stack) {
1484                                 found = TRUE;
1485                                 bb->out_stack = outb->in_stack;
1486                                 break;
1487                         }
1488                 }
1489                 //printf ("\n");
1490                 if (!found) {
1491                         bb->out_stack = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * count);
1492                         for (i = 0; i < count; ++i) {
1493                                 /* 
1494                                  * try to reuse temps already allocated for this purpouse, if they occupy the same
1495                                  * stack slot and if they are of the same type.
1496                                  * This won't cause conflicts since if 'local' is used to 
1497                                  * store one of the values in the in_stack of a bblock, then
1498                                  * the same variable will be used for the same outgoing stack 
1499                                  * slot as well. 
1500                                  * This doesn't work when inlining methods, since the bblocks
1501                                  * in the inlined methods do not inherit their in_stack from
1502                                  * the bblock they are inlined to. See bug #58863 for an
1503                                  * example.
1504                                  */
1505                                 if (cfg->inlined_method)
1506                                         bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
1507                                 else
1508                                         bb->out_stack [i] = mono_compile_get_interface_var (cfg, i, sp [i]);
1509                         }
1510                 }
1511         }
1512
1513         for (i = 0; i < bb->out_count; ++i) {
1514                 outb = bb->out_bb [i];
1515                 /* exception handlers are linked, but they should not be considered for stack args */
1516                 if (outb->flags & BB_EXCEPTION_HANDLER)
1517                         continue;
1518                 if (outb->in_scount) {
1519                         if (outb->in_scount != bb->out_scount) {
1520                                 cfg->unverifiable = TRUE;
1521                                 return;
1522                         }
1523                         continue; /* check they are the same locals */
1524                 }
1525                 outb->in_scount = count;
1526                 outb->in_stack = bb->out_stack;
1527         }
1528
1529         locals = bb->out_stack;
1530         cfg->cbb = bb;
1531         for (i = 0; i < count; ++i) {
1532                 EMIT_NEW_TEMPSTORE (cfg, inst, locals [i]->inst_c0, sp [i]);
1533                 inst->cil_code = sp [i]->cil_code;
1534                 sp [i] = locals [i];
1535                 if (cfg->verbose_level > 3)
1536                         printf ("storing %d to temp %d\n", i, (int)locals [i]->inst_c0);
1537         }
1538
1539         /*
1540          * It is possible that the out bblocks already have in_stack assigned, and
1541          * the in_stacks differ. In this case, we will store to all the different 
1542          * in_stacks.
1543          */
1544
1545         found = TRUE;
1546         bindex = 0;
1547         while (found) {
1548                 /* Find a bblock which has a different in_stack */
1549                 found = FALSE;
1550                 while (bindex < bb->out_count) {
1551                         outb = bb->out_bb [bindex];
1552                         /* exception handlers are linked, but they should not be considered for stack args */
1553                         if (outb->flags & BB_EXCEPTION_HANDLER) {
1554                                 bindex++;
1555                                 continue;
1556                         }
1557                         if (outb->in_stack != locals) {
1558                                 for (i = 0; i < count; ++i) {
1559                                         EMIT_NEW_TEMPSTORE (cfg, inst, outb->in_stack [i]->inst_c0, sp [i]);
1560                                         inst->cil_code = sp [i]->cil_code;
1561                                         sp [i] = locals [i];
1562                                         if (cfg->verbose_level > 3)
1563                                                 printf ("storing %d to temp %d\n", i, (int)outb->in_stack [i]->inst_c0);
1564                                 }
1565                                 locals = outb->in_stack;
1566                                 found = TRUE;
1567                                 break;
1568                         }
1569                         bindex ++;
1570                 }
1571         }
1572 }
1573
1574 MonoInst*
1575 mini_emit_runtime_constant (MonoCompile *cfg, MonoJumpInfoType patch_type, gpointer data)
1576 {
1577         MonoInst *ins;
1578
1579         if (cfg->compile_aot) {
1580                 EMIT_NEW_AOTCONST (cfg, ins, patch_type, data);
1581         } else {
1582                 MonoJumpInfo ji;
1583                 gpointer target;
1584                 MonoError error;
1585
1586                 ji.type = patch_type;
1587                 ji.data.target = data;
1588                 target = mono_resolve_patch_target (NULL, cfg->domain, NULL, &ji, FALSE, &error);
1589                 mono_error_assert_ok (&error);
1590
1591                 EMIT_NEW_PCONST (cfg, ins, target);
1592         }
1593         return ins;
1594 }
1595
1596 static MonoInst*
1597 mono_create_fast_tls_getter (MonoCompile *cfg, MonoTlsKey key)
1598 {
1599         int tls_offset = mono_tls_get_tls_offset (key);
1600
1601         if (cfg->compile_aot)
1602                 return NULL;
1603
1604         if (tls_offset != -1 && mono_arch_have_fast_tls ()) {
1605                 MonoInst *ins;
1606                 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
1607                 ins->dreg = mono_alloc_preg (cfg);
1608                 ins->inst_offset = tls_offset;
1609                 return ins;
1610         }
1611         return NULL;
1612 }
1613
1614 static MonoInst*
1615 mono_create_fast_tls_setter (MonoCompile *cfg, MonoInst* value, MonoTlsKey key)
1616 {
1617         int tls_offset = mono_tls_get_tls_offset (key);
1618
1619         if (cfg->compile_aot)
1620                 return NULL;
1621
1622         if (tls_offset != -1 && mono_arch_have_fast_tls ()) {
1623                 MonoInst *ins;
1624                 MONO_INST_NEW (cfg, ins, OP_TLS_SET);
1625                 ins->sreg1 = value->dreg;
1626                 ins->inst_offset = tls_offset;
1627                 return ins;
1628         }
1629         return NULL;
1630 }
1631
1632
1633 MonoInst*
1634 mono_create_tls_get (MonoCompile *cfg, MonoTlsKey key)
1635 {
1636         MonoInst *fast_tls = NULL;
1637
1638         if (!mini_get_debug_options ()->use_fallback_tls)
1639                 fast_tls = mono_create_fast_tls_getter (cfg, key);
1640
1641         if (fast_tls) {
1642                 MONO_ADD_INS (cfg->cbb, fast_tls);
1643                 return fast_tls;
1644         }
1645
1646         if (cfg->compile_aot) {
1647                 MonoInst *addr;
1648                 /*
1649                  * tls getters are critical pieces of code and we don't want to resolve them
1650                  * through the standard plt/tramp mechanism since we might expose ourselves
1651                  * to crashes and infinite recursions.
1652                  */
1653                 EMIT_NEW_AOTCONST (cfg, addr, MONO_PATCH_INFO_GET_TLS_TRAMP, (void*)key);
1654                 return mini_emit_calli (cfg, helper_sig_get_tls_tramp, NULL, addr, NULL, NULL);
1655         } else {
1656                 gpointer getter = mono_tls_get_tls_getter (key, FALSE);
1657                 return mono_emit_jit_icall (cfg, getter, NULL);
1658         }
1659 }
1660
1661 static MonoInst*
1662 mono_create_tls_set (MonoCompile *cfg, MonoInst *value, MonoTlsKey key)
1663 {
1664         MonoInst *fast_tls = NULL;
1665
1666         if (!mini_get_debug_options ()->use_fallback_tls)
1667                 fast_tls = mono_create_fast_tls_setter (cfg, value, key);
1668
1669         if (fast_tls) {
1670                 MONO_ADD_INS (cfg->cbb, fast_tls);
1671                 return fast_tls;
1672         }
1673
1674         if (cfg->compile_aot) {
1675                 MonoInst *addr;
1676                 EMIT_NEW_AOTCONST (cfg, addr, MONO_PATCH_INFO_SET_TLS_TRAMP, (void*)key);
1677                 return mini_emit_calli (cfg, helper_sig_set_tls_tramp, &value, addr, NULL, NULL);
1678         } else {
1679                 gpointer setter = mono_tls_get_tls_setter (key, FALSE);
1680                 return mono_emit_jit_icall (cfg, setter, &value);
1681         }
1682 }
1683
1684 /*
1685  * emit_push_lmf:
1686  *
1687  *   Emit IR to push the current LMF onto the LMF stack.
1688  */
1689 static void
1690 emit_push_lmf (MonoCompile *cfg)
1691 {
1692         /*
1693          * Emit IR to push the LMF:
1694          * lmf_addr = <lmf_addr from tls>
1695          * lmf->lmf_addr = lmf_addr
1696          * lmf->prev_lmf = *lmf_addr
1697          * *lmf_addr = lmf
1698          */
1699         MonoInst *ins, *lmf_ins;
1700
1701         if (!cfg->lmf_ir)
1702                 return;
1703
1704         int lmf_reg, prev_lmf_reg;
1705         /*
1706          * Store lmf_addr in a variable, so it can be allocated to a global register.
1707          */
1708         if (!cfg->lmf_addr_var)
1709                 cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1710
1711 #ifdef HOST_WIN32
1712         ins = mono_create_tls_get (cfg, TLS_KEY_JIT_TLS);
1713         g_assert (ins);
1714         int jit_tls_dreg = ins->dreg;
1715
1716         lmf_reg = alloc_preg (cfg);
1717         EMIT_NEW_BIALU_IMM (cfg, lmf_ins, OP_PADD_IMM, lmf_reg, jit_tls_dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, lmf));
1718 #else
1719         lmf_ins = mono_create_tls_get (cfg, TLS_KEY_LMF_ADDR);
1720         g_assert (lmf_ins);
1721 #endif
1722         lmf_ins->dreg = cfg->lmf_addr_var->dreg;
1723
1724         EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
1725         lmf_reg = ins->dreg;
1726
1727         prev_lmf_reg = alloc_preg (cfg);
1728         /* Save previous_lmf */
1729         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, cfg->lmf_addr_var->dreg, 0);
1730         EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), prev_lmf_reg);
1731         /* Set new lmf */
1732         EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, cfg->lmf_addr_var->dreg, 0, lmf_reg);
1733 }
1734
1735 /*
1736  * emit_pop_lmf:
1737  *
1738  *   Emit IR to pop the current LMF from the LMF stack.
1739  */
1740 static void
1741 emit_pop_lmf (MonoCompile *cfg)
1742 {
1743         int lmf_reg, lmf_addr_reg;
1744         MonoInst *ins;
1745
1746         if (!cfg->lmf_ir)
1747                 return;
1748
1749         EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
1750         lmf_reg = ins->dreg;
1751
1752         int prev_lmf_reg;
1753         /*
1754          * Emit IR to pop the LMF:
1755          * *(lmf->lmf_addr) = lmf->prev_lmf
1756          */
1757         /* This could be called before emit_push_lmf () */
1758         if (!cfg->lmf_addr_var)
1759                 cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1760         lmf_addr_reg = cfg->lmf_addr_var->dreg;
1761
1762         prev_lmf_reg = alloc_preg (cfg);
1763         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
1764         EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_addr_reg, 0, prev_lmf_reg);
1765 }
1766
1767 static int
1768 ret_type_to_call_opcode (MonoCompile *cfg, MonoType *type, int calli, int virt)
1769 {
1770 handle_enum:
1771         type = mini_get_underlying_type (type);
1772         switch (type->type) {
1773         case MONO_TYPE_VOID:
1774                 return calli? OP_VOIDCALL_REG: virt? OP_VOIDCALL_MEMBASE: OP_VOIDCALL;
1775         case MONO_TYPE_I1:
1776         case MONO_TYPE_U1:
1777         case MONO_TYPE_I2:
1778         case MONO_TYPE_U2:
1779         case MONO_TYPE_I4:
1780         case MONO_TYPE_U4:
1781                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
1782         case MONO_TYPE_I:
1783         case MONO_TYPE_U:
1784         case MONO_TYPE_PTR:
1785         case MONO_TYPE_FNPTR:
1786                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
1787         case MONO_TYPE_CLASS:
1788         case MONO_TYPE_STRING:
1789         case MONO_TYPE_OBJECT:
1790         case MONO_TYPE_SZARRAY:
1791         case MONO_TYPE_ARRAY:    
1792                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
1793         case MONO_TYPE_I8:
1794         case MONO_TYPE_U8:
1795                 return calli? OP_LCALL_REG: virt? OP_LCALL_MEMBASE: OP_LCALL;
1796         case MONO_TYPE_R4:
1797                 if (cfg->r4fp)
1798                         return calli? OP_RCALL_REG: virt? OP_RCALL_MEMBASE: OP_RCALL;
1799                 else
1800                         return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
1801         case MONO_TYPE_R8:
1802                 return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
1803         case MONO_TYPE_VALUETYPE:
1804                 if (type->data.klass->enumtype) {
1805                         type = mono_class_enum_basetype (type->data.klass);
1806                         goto handle_enum;
1807                 } else
1808                         return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
1809         case MONO_TYPE_TYPEDBYREF:
1810                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
1811         case MONO_TYPE_GENERICINST:
1812                 type = &type->data.generic_class->container_class->byval_arg;
1813                 goto handle_enum;
1814         case MONO_TYPE_VAR:
1815         case MONO_TYPE_MVAR:
1816                 /* gsharedvt */
1817                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
1818         default:
1819                 g_error ("unknown type 0x%02x in ret_type_to_call_opcode", type->type);
1820         }
1821         return -1;
1822 }
1823
1824 //XXX this ignores if t is byref
1825 #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)))))
1826
1827 /*
1828  * target_type_is_incompatible:
1829  * @cfg: MonoCompile context
1830  *
1831  * Check that the item @arg on the evaluation stack can be stored
1832  * in the target type (can be a local, or field, etc).
1833  * The cfg arg can be used to check if we need verification or just
1834  * validity checks.
1835  *
1836  * Returns: non-0 value if arg can't be stored on a target.
1837  */
1838 static int
1839 target_type_is_incompatible (MonoCompile *cfg, MonoType *target, MonoInst *arg)
1840 {
1841         MonoType *simple_type;
1842         MonoClass *klass;
1843
1844         if (target->byref) {
1845                 /* FIXME: check that the pointed to types match */
1846                 if (arg->type == STACK_MP) {
1847                         /* This is needed to handle gshared types + ldaddr. We lower the types so we can handle enums and other typedef-like types. */
1848                         MonoClass *target_class_lowered = mono_class_from_mono_type (mini_get_underlying_type (&mono_class_from_mono_type (target)->byval_arg));
1849                         MonoClass *source_class_lowered = mono_class_from_mono_type (mini_get_underlying_type (&arg->klass->byval_arg));
1850
1851                         /* if the target is native int& or same type */
1852                         if (target->type == MONO_TYPE_I || target_class_lowered == source_class_lowered)
1853                                 return 0;
1854
1855                         /* Both are primitive type byrefs and the source points to a larger type that the destination */
1856                         if (MONO_TYPE_IS_PRIMITIVE_SCALAR (&target_class_lowered->byval_arg) && MONO_TYPE_IS_PRIMITIVE_SCALAR (&source_class_lowered->byval_arg) &&
1857                                 mono_class_instance_size (target_class_lowered) <= mono_class_instance_size (source_class_lowered))
1858                                 return 0;
1859                         return 1;
1860                 }
1861                 if (arg->type == STACK_PTR)
1862                         return 0;
1863                 return 1;
1864         }
1865
1866         simple_type = mini_get_underlying_type (target);
1867         switch (simple_type->type) {
1868         case MONO_TYPE_VOID:
1869                 return 1;
1870         case MONO_TYPE_I1:
1871         case MONO_TYPE_U1:
1872         case MONO_TYPE_I2:
1873         case MONO_TYPE_U2:
1874         case MONO_TYPE_I4:
1875         case MONO_TYPE_U4:
1876                 if (arg->type != STACK_I4 && arg->type != STACK_PTR)
1877                         return 1;
1878                 return 0;
1879         case MONO_TYPE_PTR:
1880                 /* STACK_MP is needed when setting pinned locals */
1881                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
1882                         return 1;
1883                 return 0;
1884         case MONO_TYPE_I:
1885         case MONO_TYPE_U:
1886         case MONO_TYPE_FNPTR:
1887                 /* 
1888                  * Some opcodes like ldloca returns 'transient pointers' which can be stored in
1889                  * in native int. (#688008).
1890                  */
1891                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
1892                         return 1;
1893                 return 0;
1894         case MONO_TYPE_CLASS:
1895         case MONO_TYPE_STRING:
1896         case MONO_TYPE_OBJECT:
1897         case MONO_TYPE_SZARRAY:
1898         case MONO_TYPE_ARRAY:    
1899                 if (arg->type != STACK_OBJ)
1900                         return 1;
1901                 /* FIXME: check type compatibility */
1902                 return 0;
1903         case MONO_TYPE_I8:
1904         case MONO_TYPE_U8:
1905                 if (arg->type != STACK_I8)
1906                         return 1;
1907                 return 0;
1908         case MONO_TYPE_R4:
1909                 if (arg->type != cfg->r4_stack_type)
1910                         return 1;
1911                 return 0;
1912         case MONO_TYPE_R8:
1913                 if (arg->type != STACK_R8)
1914                         return 1;
1915                 return 0;
1916         case MONO_TYPE_VALUETYPE:
1917                 if (arg->type != STACK_VTYPE)
1918                         return 1;
1919                 klass = mono_class_from_mono_type (simple_type);
1920                 if (klass != arg->klass)
1921                         return 1;
1922                 return 0;
1923         case MONO_TYPE_TYPEDBYREF:
1924                 if (arg->type != STACK_VTYPE)
1925                         return 1;
1926                 klass = mono_class_from_mono_type (simple_type);
1927                 if (klass != arg->klass)
1928                         return 1;
1929                 return 0;
1930         case MONO_TYPE_GENERICINST:
1931                 if (mono_type_generic_inst_is_valuetype (simple_type)) {
1932                         MonoClass *target_class;
1933                         if (arg->type != STACK_VTYPE)
1934                                 return 1;
1935                         klass = mono_class_from_mono_type (simple_type);
1936                         target_class = mono_class_from_mono_type (target);
1937                         /* The second cases is needed when doing partial sharing */
1938                         if (klass != arg->klass && target_class != arg->klass && target_class != mono_class_from_mono_type (mini_get_underlying_type (&arg->klass->byval_arg)))
1939                                 return 1;
1940                         return 0;
1941                 } else {
1942                         if (arg->type != STACK_OBJ)
1943                                 return 1;
1944                         /* FIXME: check type compatibility */
1945                         return 0;
1946                 }
1947         case MONO_TYPE_VAR:
1948         case MONO_TYPE_MVAR:
1949                 g_assert (cfg->gshared);
1950                 if (mini_type_var_is_vt (simple_type)) {
1951                         if (arg->type != STACK_VTYPE)
1952                                 return 1;
1953                 } else {
1954                         if (arg->type != STACK_OBJ)
1955                                 return 1;
1956                 }
1957                 return 0;
1958         default:
1959                 g_error ("unknown type 0x%02x in target_type_is_incompatible", simple_type->type);
1960         }
1961         return 1;
1962 }
1963
1964 /*
1965  * Prepare arguments for passing to a function call.
1966  * Return a non-zero value if the arguments can't be passed to the given
1967  * signature.
1968  * The type checks are not yet complete and some conversions may need
1969  * casts on 32 or 64 bit architectures.
1970  *
1971  * FIXME: implement this using target_type_is_incompatible ()
1972  */
1973 static int
1974 check_call_signature (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args)
1975 {
1976         MonoType *simple_type;
1977         int i;
1978
1979         if (sig->hasthis) {
1980                 if (args [0]->type != STACK_OBJ && args [0]->type != STACK_MP && args [0]->type != STACK_PTR)
1981                         return 1;
1982                 args++;
1983         }
1984         for (i = 0; i < sig->param_count; ++i) {
1985                 if (sig->params [i]->byref) {
1986                         if (args [i]->type != STACK_MP && args [i]->type != STACK_PTR)
1987                                 return 1;
1988                         continue;
1989                 }
1990                 simple_type = mini_get_underlying_type (sig->params [i]);
1991 handle_enum:
1992                 switch (simple_type->type) {
1993                 case MONO_TYPE_VOID:
1994                         return 1;
1995                         continue;
1996                 case MONO_TYPE_I1:
1997                 case MONO_TYPE_U1:
1998                 case MONO_TYPE_I2:
1999                 case MONO_TYPE_U2:
2000                 case MONO_TYPE_I4:
2001                 case MONO_TYPE_U4:
2002                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR)
2003                                 return 1;
2004                         continue;
2005                 case MONO_TYPE_I:
2006                 case MONO_TYPE_U:
2007                 case MONO_TYPE_PTR:
2008                 case MONO_TYPE_FNPTR:
2009                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR && args [i]->type != STACK_MP && args [i]->type != STACK_OBJ)
2010                                 return 1;
2011                         continue;
2012                 case MONO_TYPE_CLASS:
2013                 case MONO_TYPE_STRING:
2014                 case MONO_TYPE_OBJECT:
2015                 case MONO_TYPE_SZARRAY:
2016                 case MONO_TYPE_ARRAY:    
2017                         if (args [i]->type != STACK_OBJ)
2018                                 return 1;
2019                         continue;
2020                 case MONO_TYPE_I8:
2021                 case MONO_TYPE_U8:
2022                         if (args [i]->type != STACK_I8)
2023                                 return 1;
2024                         continue;
2025                 case MONO_TYPE_R4:
2026                         if (args [i]->type != cfg->r4_stack_type)
2027                                 return 1;
2028                         continue;
2029                 case MONO_TYPE_R8:
2030                         if (args [i]->type != STACK_R8)
2031                                 return 1;
2032                         continue;
2033                 case MONO_TYPE_VALUETYPE:
2034                         if (simple_type->data.klass->enumtype) {
2035                                 simple_type = mono_class_enum_basetype (simple_type->data.klass);
2036                                 goto handle_enum;
2037                         }
2038                         if (args [i]->type != STACK_VTYPE)
2039                                 return 1;
2040                         continue;
2041                 case MONO_TYPE_TYPEDBYREF:
2042                         if (args [i]->type != STACK_VTYPE)
2043                                 return 1;
2044                         continue;
2045                 case MONO_TYPE_GENERICINST:
2046                         simple_type = &simple_type->data.generic_class->container_class->byval_arg;
2047                         goto handle_enum;
2048                 case MONO_TYPE_VAR:
2049                 case MONO_TYPE_MVAR:
2050                         /* gsharedvt */
2051                         if (args [i]->type != STACK_VTYPE)
2052                                 return 1;
2053                         continue;
2054                 default:
2055                         g_error ("unknown type 0x%02x in check_call_signature",
2056                                  simple_type->type);
2057                 }
2058         }
2059         return 0;
2060 }
2061
2062 static int
2063 callvirt_to_call (int opcode)
2064 {
2065         switch (opcode) {
2066         case OP_CALL_MEMBASE:
2067                 return OP_CALL;
2068         case OP_VOIDCALL_MEMBASE:
2069                 return OP_VOIDCALL;
2070         case OP_FCALL_MEMBASE:
2071                 return OP_FCALL;
2072         case OP_RCALL_MEMBASE:
2073                 return OP_RCALL;
2074         case OP_VCALL_MEMBASE:
2075                 return OP_VCALL;
2076         case OP_LCALL_MEMBASE:
2077                 return OP_LCALL;
2078         default:
2079                 g_assert_not_reached ();
2080         }
2081
2082         return -1;
2083 }
2084
2085 static int
2086 callvirt_to_call_reg (int opcode)
2087 {
2088         switch (opcode) {
2089         case OP_CALL_MEMBASE:
2090                 return OP_CALL_REG;
2091         case OP_VOIDCALL_MEMBASE:
2092                 return OP_VOIDCALL_REG;
2093         case OP_FCALL_MEMBASE:
2094                 return OP_FCALL_REG;
2095         case OP_RCALL_MEMBASE:
2096                 return OP_RCALL_REG;
2097         case OP_VCALL_MEMBASE:
2098                 return OP_VCALL_REG;
2099         case OP_LCALL_MEMBASE:
2100                 return OP_LCALL_REG;
2101         default:
2102                 g_assert_not_reached ();
2103         }
2104
2105         return -1;
2106 }
2107
2108 /* Either METHOD or IMT_ARG needs to be set */
2109 static void
2110 emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoMethod *method, MonoInst *imt_arg)
2111 {
2112         int method_reg;
2113
2114         if (COMPILE_LLVM (cfg)) {
2115                 if (imt_arg) {
2116                         method_reg = alloc_preg (cfg);
2117                         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2118                 } else {
2119                         MonoInst *ins = mini_emit_runtime_constant (cfg, MONO_PATCH_INFO_METHODCONST, method);
2120                         method_reg = ins->dreg;
2121                 }
2122
2123 #ifdef ENABLE_LLVM
2124                 call->imt_arg_reg = method_reg;
2125 #endif
2126                 mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2127                 return;
2128         }
2129
2130         if (imt_arg) {
2131                 method_reg = alloc_preg (cfg);
2132                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2133         } else {
2134                 MonoInst *ins = mini_emit_runtime_constant (cfg, MONO_PATCH_INFO_METHODCONST, method);
2135                 method_reg = ins->dreg;
2136         }
2137
2138         mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2139 }
2140
2141 static MonoJumpInfo *
2142 mono_patch_info_new (MonoMemPool *mp, int ip, MonoJumpInfoType type, gconstpointer target)
2143 {
2144         MonoJumpInfo *ji = (MonoJumpInfo *)mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
2145
2146         ji->ip.i = ip;
2147         ji->type = type;
2148         ji->data.target = target;
2149
2150         return ji;
2151 }
2152
2153 int
2154 mini_class_check_context_used (MonoCompile *cfg, MonoClass *klass)
2155 {
2156         if (cfg->gshared)
2157                 return mono_class_check_context_used (klass);
2158         else
2159                 return 0;
2160 }
2161
2162 static int
2163 mini_method_check_context_used (MonoCompile *cfg, MonoMethod *method)
2164 {
2165         if (cfg->gshared)
2166                 return mono_method_check_context_used (method);
2167         else
2168                 return 0;
2169 }
2170
2171 /*
2172  * check_method_sharing:
2173  *
2174  *   Check whenever the vtable or an mrgctx needs to be passed when calling CMETHOD.
2175  */
2176 static void
2177 check_method_sharing (MonoCompile *cfg, MonoMethod *cmethod, gboolean *out_pass_vtable, gboolean *out_pass_mrgctx)
2178 {
2179         gboolean pass_vtable = FALSE;
2180         gboolean pass_mrgctx = FALSE;
2181
2182         if (((cmethod->flags & METHOD_ATTRIBUTE_STATIC) || cmethod->klass->valuetype) &&
2183                 (mono_class_is_ginst (cmethod->klass) || mono_class_is_gtd (cmethod->klass))) {
2184                 gboolean sharable = FALSE;
2185
2186                 if (mono_method_is_generic_sharable_full (cmethod, TRUE, TRUE, TRUE))
2187                         sharable = TRUE;
2188
2189                 /*
2190                  * Pass vtable iff target method might
2191                  * be shared, which means that sharing
2192                  * is enabled for its class and its
2193                  * context is sharable (and it's not a
2194                  * generic method).
2195                  */
2196                 if (sharable && !(mini_method_get_context (cmethod) && mini_method_get_context (cmethod)->method_inst))
2197                         pass_vtable = TRUE;
2198         }
2199
2200         if (mini_method_get_context (cmethod) &&
2201                 mini_method_get_context (cmethod)->method_inst) {
2202                 g_assert (!pass_vtable);
2203
2204                 if (mono_method_is_generic_sharable_full (cmethod, TRUE, TRUE, TRUE)) {
2205                         pass_mrgctx = TRUE;
2206                 } else {
2207                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (mono_method_signature (cmethod)))
2208                                 pass_mrgctx = TRUE;
2209                 }
2210         }
2211
2212         if (out_pass_vtable)
2213                 *out_pass_vtable = pass_vtable;
2214         if (out_pass_mrgctx)
2215                 *out_pass_mrgctx = pass_mrgctx;
2216 }
2217
2218 inline static MonoCallInst *
2219 mono_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig, 
2220                                          MonoInst **args, int calli, int virtual_, int tail, int rgctx, int unbox_trampoline, MonoMethod *target)
2221 {
2222         MonoType *sig_ret;
2223         MonoCallInst *call;
2224 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2225         int i;
2226 #endif
2227
2228         if (cfg->llvm_only)
2229                 tail = FALSE;
2230
2231         if (tail) {
2232                 mini_profiler_emit_tail_call (cfg, target);
2233
2234                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
2235         } else
2236                 MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (cfg, sig->ret, calli, virtual_));
2237
2238         call->args = args;
2239         call->signature = sig;
2240         call->rgctx_reg = rgctx;
2241         sig_ret = mini_get_underlying_type (sig->ret);
2242
2243         type_to_eval_stack_type ((cfg), sig_ret, &call->inst);
2244
2245         if (tail) {
2246                 if (mini_type_is_vtype (sig_ret)) {
2247                         call->vret_var = cfg->vret_addr;
2248                         //g_assert_not_reached ();
2249                 }
2250         } else if (mini_type_is_vtype (sig_ret)) {
2251                 MonoInst *temp = mono_compile_create_var (cfg, sig_ret, OP_LOCAL);
2252                 MonoInst *loada;
2253
2254                 temp->backend.is_pinvoke = sig->pinvoke;
2255
2256                 /*
2257                  * We use a new opcode OP_OUTARG_VTRETADDR instead of LDADDR for emitting the
2258                  * address of return value to increase optimization opportunities.
2259                  * Before vtype decomposition, the dreg of the call ins itself represents the
2260                  * fact the call modifies the return value. After decomposition, the call will
2261                  * be transformed into one of the OP_VOIDCALL opcodes, and the VTRETADDR opcode
2262                  * will be transformed into an LDADDR.
2263                  */
2264                 MONO_INST_NEW (cfg, loada, OP_OUTARG_VTRETADDR);
2265                 loada->dreg = alloc_preg (cfg);
2266                 loada->inst_p0 = temp;
2267                 /* We reference the call too since call->dreg could change during optimization */
2268                 loada->inst_p1 = call;
2269                 MONO_ADD_INS (cfg->cbb, loada);
2270
2271                 call->inst.dreg = temp->dreg;
2272
2273                 call->vret_var = loada;
2274         } else if (!MONO_TYPE_IS_VOID (sig_ret))
2275                 call->inst.dreg = alloc_dreg (cfg, (MonoStackType)call->inst.type);
2276
2277 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2278         if (COMPILE_SOFT_FLOAT (cfg)) {
2279                 /* 
2280                  * If the call has a float argument, we would need to do an r8->r4 conversion using 
2281                  * an icall, but that cannot be done during the call sequence since it would clobber
2282                  * the call registers + the stack. So we do it before emitting the call.
2283                  */
2284                 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2285                         MonoType *t;
2286                         MonoInst *in = call->args [i];
2287
2288                         if (i >= sig->hasthis)
2289                                 t = sig->params [i - sig->hasthis];
2290                         else
2291                                 t = &mono_defaults.int_class->byval_arg;
2292                         t = mono_type_get_underlying_type (t);
2293
2294                         if (!t->byref && t->type == MONO_TYPE_R4) {
2295                                 MonoInst *iargs [1];
2296                                 MonoInst *conv;
2297
2298                                 iargs [0] = in;
2299                                 conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
2300
2301                                 /* The result will be in an int vreg */
2302                                 call->args [i] = conv;
2303                         }
2304                 }
2305         }
2306 #endif
2307
2308         call->need_unbox_trampoline = unbox_trampoline;
2309
2310 #ifdef ENABLE_LLVM
2311         if (COMPILE_LLVM (cfg))
2312                 mono_llvm_emit_call (cfg, call);
2313         else
2314                 mono_arch_emit_call (cfg, call);
2315 #else
2316         mono_arch_emit_call (cfg, call);
2317 #endif
2318
2319         cfg->param_area = MAX (cfg->param_area, call->stack_usage);
2320         cfg->flags |= MONO_CFG_HAS_CALLS;
2321         
2322         return call;
2323 }
2324
2325 static void
2326 set_rgctx_arg (MonoCompile *cfg, MonoCallInst *call, int rgctx_reg, MonoInst *rgctx_arg)
2327 {
2328         mono_call_inst_add_outarg_reg (cfg, call, rgctx_reg, MONO_ARCH_RGCTX_REG, FALSE);
2329         cfg->uses_rgctx_reg = TRUE;
2330         call->rgctx_reg = TRUE;
2331 #ifdef ENABLE_LLVM
2332         call->rgctx_arg_reg = rgctx_reg;
2333 #endif
2334 }       
2335
2336 MonoInst*
2337 mini_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr, MonoInst *imt_arg, MonoInst *rgctx_arg)
2338 {
2339         MonoCallInst *call;
2340         MonoInst *ins;
2341         int rgctx_reg = -1;
2342         gboolean check_sp = FALSE;
2343
2344         if (cfg->check_pinvoke_callconv && cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
2345                 WrapperInfo *info = mono_marshal_get_wrapper_info (cfg->method);
2346
2347                 if (info && info->subtype == WRAPPER_SUBTYPE_PINVOKE)
2348                         check_sp = TRUE;
2349         }
2350
2351         if (rgctx_arg) {
2352                 rgctx_reg = mono_alloc_preg (cfg);
2353                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2354         }
2355
2356         if (check_sp) {
2357                 if (!cfg->stack_inbalance_var)
2358                         cfg->stack_inbalance_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2359
2360                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2361                 ins->dreg = cfg->stack_inbalance_var->dreg;
2362                 MONO_ADD_INS (cfg->cbb, ins);
2363         }
2364
2365         call = mono_emit_call_args (cfg, sig, args, TRUE, FALSE, FALSE, rgctx_arg ? TRUE : FALSE, FALSE, NULL);
2366
2367         call->inst.sreg1 = addr->dreg;
2368
2369         if (imt_arg)
2370                 emit_imt_argument (cfg, call, NULL, imt_arg);
2371
2372         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2373
2374         if (check_sp) {
2375                 int sp_reg;
2376
2377                 sp_reg = mono_alloc_preg (cfg);
2378
2379                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2380                 ins->dreg = sp_reg;
2381                 MONO_ADD_INS (cfg->cbb, ins);
2382
2383                 /* Restore the stack so we don't crash when throwing the exception */
2384                 MONO_INST_NEW (cfg, ins, OP_SET_SP);
2385                 ins->sreg1 = cfg->stack_inbalance_var->dreg;
2386                 MONO_ADD_INS (cfg->cbb, ins);
2387
2388                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, cfg->stack_inbalance_var->dreg, sp_reg);
2389                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ExecutionEngineException");
2390         }
2391
2392         if (rgctx_arg)
2393                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2394
2395         return (MonoInst*)call;
2396 }
2397
2398 static MonoInst*
2399 emit_get_rgctx_method (MonoCompile *cfg, int context_used, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type);
2400
2401 static MonoInst*
2402 mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSignature *sig, gboolean tail,
2403                                                         MonoInst **args, MonoInst *this_ins, MonoInst *imt_arg, MonoInst *rgctx_arg)
2404 {
2405 #ifndef DISABLE_REMOTING
2406         gboolean might_be_remote = FALSE;
2407 #endif
2408         gboolean virtual_ = this_ins != NULL;
2409         gboolean enable_for_aot = TRUE;
2410         int context_used;
2411         MonoCallInst *call;
2412         MonoInst *call_target = NULL;
2413         int rgctx_reg = 0;
2414         gboolean need_unbox_trampoline;
2415
2416         if (!sig)
2417                 sig = mono_method_signature (method);
2418
2419         if (cfg->llvm_only && (mono_class_is_interface (method->klass)))
2420                 g_assert_not_reached ();
2421
2422         if (rgctx_arg) {
2423                 rgctx_reg = mono_alloc_preg (cfg);
2424                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2425         }
2426
2427         if (method->string_ctor) {
2428                 /* Create the real signature */
2429                 /* FIXME: Cache these */
2430                 MonoMethodSignature *ctor_sig = mono_metadata_signature_dup_mempool (cfg->mempool, sig);
2431                 ctor_sig->ret = &mono_defaults.string_class->byval_arg;
2432
2433                 sig = ctor_sig;
2434         }
2435
2436         context_used = mini_method_check_context_used (cfg, method);
2437
2438 #ifndef DISABLE_REMOTING
2439         might_be_remote = this_ins && sig->hasthis &&
2440                 (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) &&
2441                 !(method->flags & METHOD_ATTRIBUTE_VIRTUAL) && (!MONO_CHECK_THIS (this_ins) || context_used);
2442
2443         if (might_be_remote && context_used) {
2444                 MonoInst *addr;
2445
2446                 g_assert (cfg->gshared);
2447
2448                 addr = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK);
2449
2450                 return mini_emit_calli (cfg, sig, args, addr, NULL, NULL);
2451         }
2452 #endif
2453
2454         if (cfg->llvm_only && !call_target && virtual_ && (method->flags & METHOD_ATTRIBUTE_VIRTUAL))
2455                 return emit_llvmonly_virtual_call (cfg, method, sig, 0, args);
2456
2457         need_unbox_trampoline = method->klass == mono_defaults.object_class || mono_class_is_interface (method->klass);
2458
2459         call = mono_emit_call_args (cfg, sig, args, FALSE, virtual_, tail, rgctx_arg ? TRUE : FALSE, need_unbox_trampoline, method);
2460
2461 #ifndef DISABLE_REMOTING
2462         if (might_be_remote)
2463                 call->method = mono_marshal_get_remoting_invoke_with_check (method);
2464         else
2465 #endif
2466                 call->method = method;
2467         call->inst.flags |= MONO_INST_HAS_METHOD;
2468         call->inst.inst_left = this_ins;
2469         call->tail_call = tail;
2470
2471         if (virtual_) {
2472                 int vtable_reg, slot_reg, this_reg;
2473                 int offset;
2474
2475                 this_reg = this_ins->dreg;
2476
2477                 if (!cfg->llvm_only && (method->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (method->name, "Invoke")) {
2478                         MonoInst *dummy_use;
2479
2480                         MONO_EMIT_NULL_CHECK (cfg, this_reg);
2481
2482                         /* Make a call to delegate->invoke_impl */
2483                         call->inst.inst_basereg = this_reg;
2484                         call->inst.inst_offset = MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl);
2485                         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2486
2487                         /* We must emit a dummy use here because the delegate trampoline will
2488                         replace the 'this' argument with the delegate target making this activation
2489                         no longer a root for the delegate.
2490                         This is an issue for delegates that target collectible code such as dynamic
2491                         methods of GC'able assemblies.
2492
2493                         For a test case look into #667921.
2494
2495                         FIXME: a dummy use is not the best way to do it as the local register allocator
2496                         will put it on a caller save register and spil it around the call. 
2497                         Ideally, we would either put it on a callee save register or only do the store part.  
2498                          */
2499                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, args [0]);
2500
2501                         return (MonoInst*)call;
2502                 }
2503
2504                 if ((!cfg->compile_aot || enable_for_aot) && 
2505                         (!(method->flags & METHOD_ATTRIBUTE_VIRTUAL) || 
2506                          (MONO_METHOD_IS_FINAL (method) &&
2507                           method->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)) &&
2508                         !(mono_class_is_marshalbyref (method->klass) && context_used)) {
2509                         /* 
2510                          * the method is not virtual, we just need to ensure this is not null
2511                          * and then we can call the method directly.
2512                          */
2513 #ifndef DISABLE_REMOTING
2514                         if (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) {
2515                                 /* 
2516                                  * The check above ensures method is not gshared, this is needed since
2517                                  * gshared methods can't have wrappers.
2518                                  */
2519                                 method = call->method = mono_marshal_get_remoting_invoke_with_check (method);
2520                         }
2521 #endif
2522
2523                         if (!method->string_ctor)
2524                                 MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2525
2526                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2527                 } else if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && MONO_METHOD_IS_FINAL (method)) {
2528                         /*
2529                          * the method is virtual, but we can statically dispatch since either
2530                          * it's class or the method itself are sealed.
2531                          * But first we need to ensure it's not a null reference.
2532                          */
2533                         MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2534
2535                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2536                 } else if (call_target) {
2537                         vtable_reg = alloc_preg (cfg);
2538                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
2539
2540                         call->inst.opcode = callvirt_to_call_reg (call->inst.opcode);
2541                         call->inst.sreg1 = call_target->dreg;
2542                         call->inst.flags &= !MONO_INST_HAS_METHOD;
2543                 } else {
2544                         vtable_reg = alloc_preg (cfg);
2545                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
2546                         if (mono_class_is_interface (method->klass)) {
2547                                 guint32 imt_slot = mono_method_get_imt_slot (method);
2548                                 emit_imt_argument (cfg, call, call->method, imt_arg);
2549                                 slot_reg = vtable_reg;
2550                                 offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
2551                         } else {
2552                                 slot_reg = vtable_reg;
2553                                 offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) +
2554                                         ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
2555                                 if (imt_arg) {
2556                                         g_assert (mono_method_signature (method)->generic_param_count);
2557                                         emit_imt_argument (cfg, call, call->method, imt_arg);
2558                                 }
2559                         }
2560
2561                         call->inst.sreg1 = slot_reg;
2562                         call->inst.inst_offset = offset;
2563                         call->is_virtual = TRUE;
2564                 }
2565         }
2566
2567         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2568
2569         if (rgctx_arg)
2570                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2571
2572         return (MonoInst*)call;
2573 }
2574
2575 MonoInst*
2576 mono_emit_method_call (MonoCompile *cfg, MonoMethod *method, MonoInst **args, MonoInst *this_ins)
2577 {
2578         return mono_emit_method_call_full (cfg, method, mono_method_signature (method), FALSE, args, this_ins, NULL, NULL);
2579 }
2580
2581 MonoInst*
2582 mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig,
2583                                            MonoInst **args)
2584 {
2585         MonoCallInst *call;
2586
2587         g_assert (sig);
2588
2589         call = mono_emit_call_args (cfg, sig, args, FALSE, FALSE, FALSE, FALSE, FALSE, NULL);
2590         call->fptr = func;
2591
2592         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2593
2594         return (MonoInst*)call;
2595 }
2596
2597 MonoInst*
2598 mono_emit_jit_icall (MonoCompile *cfg, gconstpointer func, MonoInst **args)
2599 {
2600         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (func);
2601
2602         g_assert (info);
2603
2604         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
2605 }
2606
2607 /*
2608  * mono_emit_abs_call:
2609  *
2610  *   Emit a call to the runtime function described by PATCH_TYPE and DATA.
2611  */
2612 inline static MonoInst*
2613 mono_emit_abs_call (MonoCompile *cfg, MonoJumpInfoType patch_type, gconstpointer data, 
2614                                         MonoMethodSignature *sig, MonoInst **args)
2615 {
2616         MonoJumpInfo *ji = mono_patch_info_new (cfg->mempool, 0, patch_type, data);
2617         MonoInst *ins;
2618
2619         /* 
2620          * We pass ji as the call address, the PATCH_INFO_ABS resolving code will
2621          * handle it.
2622          */
2623         if (cfg->abs_patches == NULL)
2624                 cfg->abs_patches = g_hash_table_new (NULL, NULL);
2625         g_hash_table_insert (cfg->abs_patches, ji, ji);
2626         ins = mono_emit_native_call (cfg, ji, sig, args);
2627         ((MonoCallInst*)ins)->fptr_is_patch = TRUE;
2628         return ins;
2629 }
2630
2631 static MonoMethodSignature*
2632 sig_to_rgctx_sig (MonoMethodSignature *sig)
2633 {
2634         // FIXME: memory allocation
2635         MonoMethodSignature *res;
2636         int i;
2637
2638         res = (MonoMethodSignature *)g_malloc (MONO_SIZEOF_METHOD_SIGNATURE + (sig->param_count + 1) * sizeof (MonoType*));
2639         memcpy (res, sig, MONO_SIZEOF_METHOD_SIGNATURE);
2640         res->param_count = sig->param_count + 1;
2641         for (i = 0; i < sig->param_count; ++i)
2642                 res->params [i] = sig->params [i];
2643         res->params [sig->param_count] = &mono_defaults.int_class->this_arg;
2644         return res;
2645 }
2646
2647 /* Make an indirect call to FSIG passing an additional argument */
2648 static MonoInst*
2649 emit_extra_arg_calli (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **orig_args, int arg_reg, MonoInst *call_target)
2650 {
2651         MonoMethodSignature *csig;
2652         MonoInst *args_buf [16];
2653         MonoInst **args;
2654         int i, pindex, tmp_reg;
2655
2656         /* Make a call with an rgctx/extra arg */
2657         if (fsig->param_count + 2 < 16)
2658                 args = args_buf;
2659         else
2660                 args = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (fsig->param_count + 2));
2661         pindex = 0;
2662         if (fsig->hasthis)
2663                 args [pindex ++] = orig_args [0];
2664         for (i = 0; i < fsig->param_count; ++i)
2665                 args [pindex ++] = orig_args [fsig->hasthis + i];
2666         tmp_reg = alloc_preg (cfg);
2667         EMIT_NEW_UNALU (cfg, args [pindex], OP_MOVE, tmp_reg, arg_reg);
2668         csig = sig_to_rgctx_sig (fsig);
2669         return mini_emit_calli (cfg, csig, args, call_target, NULL, NULL);
2670 }
2671
2672 /* Emit an indirect call to the function descriptor ADDR */
2673 static MonoInst*
2674 emit_llvmonly_calli (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, MonoInst *addr)
2675 {
2676         int addr_reg, arg_reg;
2677         MonoInst *call_target;
2678
2679         g_assert (cfg->llvm_only);
2680
2681         /*
2682          * addr points to a <addr, arg> pair, load both of them, and
2683          * make a call to addr, passing arg as an extra arg.
2684          */
2685         addr_reg = alloc_preg (cfg);
2686         EMIT_NEW_LOAD_MEMBASE (cfg, call_target, OP_LOAD_MEMBASE, addr_reg, addr->dreg, 0);
2687         arg_reg = alloc_preg (cfg);
2688         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, arg_reg, addr->dreg, sizeof (gpointer));
2689
2690         return emit_extra_arg_calli (cfg, fsig, args, arg_reg, call_target);
2691 }
2692
2693 static gboolean
2694 direct_icalls_enabled (MonoCompile *cfg)
2695 {
2696         return FALSE;
2697
2698         /* LLVM on amd64 can't handle calls to non-32 bit addresses */
2699 #ifdef TARGET_AMD64
2700         if (cfg->compile_llvm && !cfg->llvm_only)
2701                 return FALSE;
2702 #endif
2703         if (cfg->gen_sdb_seq_points || cfg->disable_direct_icalls)
2704                 return FALSE;
2705         return TRUE;
2706 }
2707
2708 MonoInst*
2709 mono_emit_jit_icall_by_info (MonoCompile *cfg, int il_offset, MonoJitICallInfo *info, MonoInst **args)
2710 {
2711         /*
2712          * Call the jit icall without a wrapper if possible.
2713          * The wrapper is needed for the following reasons:
2714          * - to handle exceptions thrown using mono_raise_exceptions () from the
2715          *   icall function. The EH code needs the lmf frame pushed by the
2716          *   wrapper to be able to unwind back to managed code.
2717          * - to be able to do stack walks for asynchronously suspended
2718          *   threads when debugging.
2719          */
2720         if (info->no_raise && direct_icalls_enabled (cfg)) {
2721                 char *name;
2722                 int costs;
2723
2724                 if (!info->wrapper_method) {
2725                         name = g_strdup_printf ("__icall_wrapper_%s", info->name);
2726                         info->wrapper_method = mono_marshal_get_icall_wrapper (info->sig, name, info->func, TRUE);
2727                         g_free (name);
2728                         mono_memory_barrier ();
2729                 }
2730
2731                 /*
2732                  * Inline the wrapper method, which is basically a call to the C icall, and
2733                  * an exception check.
2734                  */
2735                 costs = inline_method (cfg, info->wrapper_method, NULL,
2736                                                            args, NULL, il_offset, TRUE);
2737                 g_assert (costs > 0);
2738                 g_assert (!MONO_TYPE_IS_VOID (info->sig->ret));
2739
2740                 return args [0];
2741         } else {
2742                 return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
2743         }
2744 }
2745  
2746 static MonoInst*
2747 mono_emit_widen_call_res (MonoCompile *cfg, MonoInst *ins, MonoMethodSignature *fsig)
2748 {
2749         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
2750                 if ((fsig->pinvoke || LLVM_ENABLED) && !fsig->ret->byref) {
2751                         int widen_op = -1;
2752
2753                         /* 
2754                          * Native code might return non register sized integers 
2755                          * without initializing the upper bits.
2756                          */
2757                         switch (mono_type_to_load_membase (cfg, fsig->ret)) {
2758                         case OP_LOADI1_MEMBASE:
2759                                 widen_op = OP_ICONV_TO_I1;
2760                                 break;
2761                         case OP_LOADU1_MEMBASE:
2762                                 widen_op = OP_ICONV_TO_U1;
2763                                 break;
2764                         case OP_LOADI2_MEMBASE:
2765                                 widen_op = OP_ICONV_TO_I2;
2766                                 break;
2767                         case OP_LOADU2_MEMBASE:
2768                                 widen_op = OP_ICONV_TO_U2;
2769                                 break;
2770                         default:
2771                                 break;
2772                         }
2773
2774                         if (widen_op != -1) {
2775                                 int dreg = alloc_preg (cfg);
2776                                 MonoInst *widen;
2777
2778                                 EMIT_NEW_UNALU (cfg, widen, widen_op, dreg, ins->dreg);
2779                                 widen->type = ins->type;
2780                                 ins = widen;
2781                         }
2782                 }
2783         }
2784
2785         return ins;
2786 }
2787
2788
2789 static void
2790 emit_method_access_failure (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee)
2791 {
2792         MonoInst *args [16];
2793
2794         args [0] = emit_get_rgctx_method (cfg, mono_method_check_context_used (caller), caller, MONO_RGCTX_INFO_METHOD);
2795         args [1] = emit_get_rgctx_method (cfg, mono_method_check_context_used (callee), callee, MONO_RGCTX_INFO_METHOD);
2796
2797         mono_emit_jit_icall (cfg, mono_throw_method_access, args);
2798 }
2799
2800 MonoMethod*
2801 mini_get_memcpy_method (void)
2802 {
2803         static MonoMethod *memcpy_method = NULL;
2804         if (!memcpy_method) {
2805                 memcpy_method = mono_class_get_method_from_name (mono_defaults.string_class, "memcpy", 3);
2806                 if (!memcpy_method)
2807                         g_error ("Old corlib found. Install a new one");
2808         }
2809         return memcpy_method;
2810 }
2811
2812 void
2813 mini_emit_write_barrier (MonoCompile *cfg, MonoInst *ptr, MonoInst *value)
2814 {
2815         int card_table_shift_bits;
2816         gpointer card_table_mask;
2817         guint8 *card_table;
2818         MonoInst *dummy_use;
2819         int nursery_shift_bits;
2820         size_t nursery_size;
2821
2822         if (!cfg->gen_write_barriers)
2823                 return;
2824
2825         //method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER && !MONO_INS_IS_PCONST_NULL (sp [1])
2826
2827         card_table = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
2828
2829         mono_gc_get_nursery (&nursery_shift_bits, &nursery_size);
2830
2831         if (cfg->backend->have_card_table_wb && !cfg->compile_aot && card_table && nursery_shift_bits > 0 && !COMPILE_LLVM (cfg)) {
2832                 MonoInst *wbarrier;
2833
2834                 MONO_INST_NEW (cfg, wbarrier, OP_CARD_TABLE_WBARRIER);
2835                 wbarrier->sreg1 = ptr->dreg;
2836                 wbarrier->sreg2 = value->dreg;
2837                 MONO_ADD_INS (cfg->cbb, wbarrier);
2838         } else if (card_table) {
2839                 int offset_reg = alloc_preg (cfg);
2840                 int card_reg;
2841                 MonoInst *ins;
2842
2843                 /*
2844                  * We emit a fast light weight write barrier. This always marks cards as in the concurrent
2845                  * collector case, so, for the serial collector, it might slightly slow down nursery
2846                  * collections. We also expect that the host system and the target system have the same card
2847                  * table configuration, which is the case if they have the same pointer size.
2848                  */
2849
2850                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, offset_reg, ptr->dreg, card_table_shift_bits);
2851                 if (card_table_mask)
2852                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, offset_reg, offset_reg, card_table_mask);
2853
2854                 /*We can't use PADD_IMM since the cardtable might end up in high addresses and amd64 doesn't support
2855                  * IMM's larger than 32bits.
2856                  */
2857                 ins = mini_emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR, NULL);
2858                 card_reg = ins->dreg;
2859
2860                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, offset_reg, offset_reg, card_reg);
2861                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, offset_reg, 0, 1);
2862         } else {
2863                 MonoMethod *write_barrier = mono_gc_get_write_barrier ();
2864                 mono_emit_method_call (cfg, write_barrier, &ptr, NULL);
2865         }
2866
2867         EMIT_NEW_DUMMY_USE (cfg, dummy_use, value);
2868 }
2869
2870 MonoMethod*
2871 mini_get_memset_method (void)
2872 {
2873         static MonoMethod *memset_method = NULL;
2874         if (!memset_method) {
2875                 memset_method = mono_class_get_method_from_name (mono_defaults.string_class, "memset", 3);
2876                 if (!memset_method)
2877                         g_error ("Old corlib found. Install a new one");
2878         }
2879         return memset_method;
2880 }
2881
2882 void
2883 mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass)
2884 {
2885         MonoInst *iargs [3];
2886         int n;
2887         guint32 align;
2888         MonoMethod *memset_method;
2889         MonoInst *size_ins = NULL;
2890         MonoInst *bzero_ins = NULL;
2891         static MonoMethod *bzero_method;
2892
2893         /* FIXME: Optimize this for the case when dest is an LDADDR */
2894         mono_class_init (klass);
2895         if (mini_is_gsharedvt_klass (klass)) {
2896                 size_ins = mini_emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
2897                 bzero_ins = mini_emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_BZERO);
2898                 if (!bzero_method)
2899                         bzero_method = mono_class_get_method_from_name (mono_defaults.string_class, "bzero_aligned_1", 2);
2900                 g_assert (bzero_method);
2901                 iargs [0] = dest;
2902                 iargs [1] = size_ins;
2903                 mini_emit_calli (cfg, mono_method_signature (bzero_method), iargs, bzero_ins, NULL, NULL);
2904                 return;
2905         }
2906
2907         klass = mono_class_from_mono_type (mini_get_underlying_type (&klass->byval_arg));
2908
2909         n = mono_class_value_size (klass, &align);
2910
2911         if (n <= sizeof (gpointer) * 8) {
2912                 mini_emit_memset (cfg, dest->dreg, 0, n, 0, align);
2913         }
2914         else {
2915                 memset_method = mini_get_memset_method ();
2916                 iargs [0] = dest;
2917                 EMIT_NEW_ICONST (cfg, iargs [1], 0);
2918                 EMIT_NEW_ICONST (cfg, iargs [2], n);
2919                 mono_emit_method_call (cfg, memset_method, iargs, NULL);
2920         }
2921 }
2922
2923 /*
2924  * emit_get_rgctx:
2925  *
2926  *   Emit IR to return either the this pointer for instance method,
2927  * or the mrgctx for static methods.
2928  */
2929 static MonoInst*
2930 emit_get_rgctx (MonoCompile *cfg, MonoMethod *method, int context_used)
2931 {
2932         MonoInst *this_ins = NULL;
2933
2934         g_assert (cfg->gshared);
2935
2936         if (!(method->flags & METHOD_ATTRIBUTE_STATIC) &&
2937                         !(context_used & MONO_GENERIC_CONTEXT_USED_METHOD) &&
2938                 !method->klass->valuetype)
2939                 EMIT_NEW_VARLOAD (cfg, this_ins, cfg->this_arg, &mono_defaults.object_class->byval_arg);
2940
2941         if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD) {
2942                 MonoInst *mrgctx_loc, *mrgctx_var;
2943
2944                 g_assert (!this_ins);
2945                 g_assert (method->is_inflated && mono_method_get_context (method)->method_inst);
2946
2947                 mrgctx_loc = mono_get_vtable_var (cfg);
2948                 EMIT_NEW_TEMPLOAD (cfg, mrgctx_var, mrgctx_loc->inst_c0);
2949
2950                 return mrgctx_var;
2951         } else if (MONO_CLASS_IS_INTERFACE (cfg->method->klass)) {
2952                 MonoInst *mrgctx_loc, *mrgctx_var;
2953
2954                 /* Default interface methods need an mrgctx since the vtabke at runtime points at an implementing class */
2955                 mrgctx_loc = mono_get_vtable_var (cfg);
2956                 EMIT_NEW_TEMPLOAD (cfg, mrgctx_var, mrgctx_loc->inst_c0);
2957
2958                 g_assert (mono_method_needs_static_rgctx_invoke (cfg->method, TRUE));
2959
2960                 return mrgctx_var;
2961         } else if (method->flags & METHOD_ATTRIBUTE_STATIC || method->klass->valuetype) {
2962                 MonoInst *vtable_loc, *vtable_var;
2963
2964                 g_assert (!this_ins);
2965
2966                 vtable_loc = mono_get_vtable_var (cfg);
2967                 EMIT_NEW_TEMPLOAD (cfg, vtable_var, vtable_loc->inst_c0);
2968
2969                 if (method->is_inflated && mono_method_get_context (method)->method_inst) {
2970                         MonoInst *mrgctx_var = vtable_var;
2971                         int vtable_reg;
2972
2973                         vtable_reg = alloc_preg (cfg);
2974                         EMIT_NEW_LOAD_MEMBASE (cfg, vtable_var, OP_LOAD_MEMBASE, vtable_reg, mrgctx_var->dreg, MONO_STRUCT_OFFSET (MonoMethodRuntimeGenericContext, class_vtable));
2975                         vtable_var->type = STACK_PTR;
2976                 }
2977
2978                 return vtable_var;
2979         } else {
2980                 MonoInst *ins;
2981                 int vtable_reg;
2982         
2983                 vtable_reg = alloc_preg (cfg);
2984                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, vtable_reg, this_ins->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
2985                 return ins;
2986         }
2987 }
2988
2989 static MonoJumpInfoRgctxEntry *
2990 mono_patch_info_rgctx_entry_new (MonoMemPool *mp, MonoMethod *method, gboolean in_mrgctx, MonoJumpInfoType patch_type, gconstpointer patch_data, MonoRgctxInfoType info_type)
2991 {
2992         MonoJumpInfoRgctxEntry *res = (MonoJumpInfoRgctxEntry *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoRgctxEntry));
2993         res->method = method;
2994         res->in_mrgctx = in_mrgctx;
2995         res->data = (MonoJumpInfo *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo));
2996         res->data->type = patch_type;
2997         res->data->data.target = patch_data;
2998         res->info_type = info_type;
2999
3000         return res;
3001 }
3002
3003 static inline MonoInst*
3004 emit_rgctx_fetch_inline (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
3005 {
3006         MonoInst *args [16];
3007         MonoInst *call;
3008
3009         // FIXME: No fastpath since the slot is not a compile time constant
3010         args [0] = rgctx;
3011         EMIT_NEW_AOTCONST (cfg, args [1], MONO_PATCH_INFO_RGCTX_SLOT_INDEX, entry);
3012         if (entry->in_mrgctx)
3013                 call = mono_emit_jit_icall (cfg, mono_fill_method_rgctx, args);
3014         else
3015                 call = mono_emit_jit_icall (cfg, mono_fill_class_rgctx, args);
3016         return call;
3017 #if 0
3018         /*
3019          * FIXME: This can be called during decompose, which is a problem since it creates
3020          * new bblocks.
3021          * Also, the fastpath doesn't work since the slot number is dynamically allocated.
3022          */
3023         int i, slot, depth, index, rgctx_reg, val_reg, res_reg;
3024         gboolean mrgctx;
3025         MonoBasicBlock *is_null_bb, *end_bb;
3026         MonoInst *res, *ins, *call;
3027         MonoInst *args[16];
3028
3029         slot = mini_get_rgctx_entry_slot (entry);
3030
3031         mrgctx = MONO_RGCTX_SLOT_IS_MRGCTX (slot);
3032         index = MONO_RGCTX_SLOT_INDEX (slot);
3033         if (mrgctx)
3034                 index += MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
3035         for (depth = 0; ; ++depth) {
3036                 int size = mono_class_rgctx_get_array_size (depth, mrgctx);
3037
3038                 if (index < size - 1)
3039                         break;
3040                 index -= size - 1;
3041         }
3042
3043         NEW_BBLOCK (cfg, end_bb);
3044         NEW_BBLOCK (cfg, is_null_bb);
3045
3046         if (mrgctx) {
3047                 rgctx_reg = rgctx->dreg;
3048         } else {
3049                 rgctx_reg = alloc_preg (cfg);
3050
3051                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, rgctx_reg, rgctx->dreg, MONO_STRUCT_OFFSET (MonoVTable, runtime_generic_context));
3052                 // FIXME: Avoid this check by allocating the table when the vtable is created etc.
3053                 NEW_BBLOCK (cfg, is_null_bb);
3054
3055                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rgctx_reg, 0);
3056                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3057         }
3058
3059         for (i = 0; i < depth; ++i) {
3060                 int array_reg = alloc_preg (cfg);
3061
3062                 /* load ptr to next array */
3063                 if (mrgctx && i == 0)
3064                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, rgctx_reg, MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT);
3065                 else
3066                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, rgctx_reg, 0);
3067                 rgctx_reg = array_reg;
3068                 /* is the ptr null? */
3069                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rgctx_reg, 0);
3070                 /* if yes, jump to actual trampoline */
3071                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3072         }
3073
3074         /* fetch slot */
3075         val_reg = alloc_preg (cfg);
3076         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, val_reg, rgctx_reg, (index + 1) * sizeof (gpointer));
3077         /* is the slot null? */
3078         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, val_reg, 0);
3079         /* if yes, jump to actual trampoline */
3080         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3081
3082         /* Fastpath */
3083         res_reg = alloc_preg (cfg);
3084         MONO_INST_NEW (cfg, ins, OP_MOVE);
3085         ins->dreg = res_reg;
3086         ins->sreg1 = val_reg;
3087         MONO_ADD_INS (cfg->cbb, ins);
3088         res = ins;
3089         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3090
3091         /* Slowpath */
3092         MONO_START_BB (cfg, is_null_bb);
3093         args [0] = rgctx;
3094         EMIT_NEW_ICONST (cfg, args [1], index);
3095         if (mrgctx)
3096                 call = mono_emit_jit_icall (cfg, mono_fill_method_rgctx, args);
3097         else
3098                 call = mono_emit_jit_icall (cfg, mono_fill_class_rgctx, args);
3099         MONO_INST_NEW (cfg, ins, OP_MOVE);
3100         ins->dreg = res_reg;
3101         ins->sreg1 = call->dreg;
3102         MONO_ADD_INS (cfg->cbb, ins);
3103         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3104
3105         MONO_START_BB (cfg, end_bb);
3106
3107         return res;
3108 #endif
3109 }
3110
3111 /*
3112  * emit_rgctx_fetch:
3113  *
3114  *   Emit IR to load the value of the rgctx entry ENTRY from the rgctx
3115  * given by RGCTX.
3116  */
3117 static inline MonoInst*
3118 emit_rgctx_fetch (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
3119 {
3120         if (cfg->llvm_only)
3121                 return emit_rgctx_fetch_inline (cfg, rgctx, entry);
3122         else
3123                 return mono_emit_abs_call (cfg, MONO_PATCH_INFO_RGCTX_FETCH, entry, helper_sig_rgctx_lazy_fetch_trampoline, &rgctx);
3124 }
3125
3126 MonoInst*
3127 mini_emit_get_rgctx_klass (MonoCompile *cfg, int context_used,
3128                                           MonoClass *klass, MonoRgctxInfoType rgctx_type)
3129 {
3130         MonoJumpInfoRgctxEntry *entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_CLASS, klass, rgctx_type);
3131         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
3132
3133         return emit_rgctx_fetch (cfg, rgctx, entry);
3134 }
3135
3136 static MonoInst*
3137 emit_get_rgctx_sig (MonoCompile *cfg, int context_used,
3138                                         MonoMethodSignature *sig, MonoRgctxInfoType rgctx_type)
3139 {
3140         MonoJumpInfoRgctxEntry *entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_SIGNATURE, sig, rgctx_type);
3141         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
3142
3143         return emit_rgctx_fetch (cfg, rgctx, entry);
3144 }
3145
3146 static MonoInst*
3147 emit_get_rgctx_gsharedvt_call (MonoCompile *cfg, int context_used,
3148                                                            MonoMethodSignature *sig, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3149 {
3150         MonoJumpInfoGSharedVtCall *call_info;
3151         MonoJumpInfoRgctxEntry *entry;
3152         MonoInst *rgctx;
3153
3154         call_info = (MonoJumpInfoGSharedVtCall *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoGSharedVtCall));
3155         call_info->sig = sig;
3156         call_info->method = cmethod;
3157
3158         entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_GSHAREDVT_CALL, call_info, rgctx_type);
3159         rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
3160
3161         return emit_rgctx_fetch (cfg, rgctx, entry);
3162 }
3163
3164 /*
3165  * emit_get_rgctx_virt_method:
3166  *
3167  *   Return data for method VIRT_METHOD for a receiver of type KLASS.
3168  */
3169 static MonoInst*
3170 emit_get_rgctx_virt_method (MonoCompile *cfg, int context_used,
3171                                                         MonoClass *klass, MonoMethod *virt_method, MonoRgctxInfoType rgctx_type)
3172 {
3173         MonoJumpInfoVirtMethod *info;
3174         MonoJumpInfoRgctxEntry *entry;
3175         MonoInst *rgctx;
3176
3177         info = (MonoJumpInfoVirtMethod *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoVirtMethod));
3178         info->klass = klass;
3179         info->method = virt_method;
3180
3181         entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_VIRT_METHOD, info, rgctx_type);
3182         rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
3183
3184         return emit_rgctx_fetch (cfg, rgctx, entry);
3185 }
3186
3187 static MonoInst*
3188 emit_get_rgctx_gsharedvt_method (MonoCompile *cfg, int context_used,
3189                                                                  MonoMethod *cmethod, MonoGSharedVtMethodInfo *info)
3190 {
3191         MonoJumpInfoRgctxEntry *entry;
3192         MonoInst *rgctx;
3193
3194         entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_GSHAREDVT_METHOD, info, MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO);
3195         rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
3196
3197         return emit_rgctx_fetch (cfg, rgctx, entry);
3198 }
3199
3200 /*
3201  * emit_get_rgctx_method:
3202  *
3203  *   Emit IR to load the property RGCTX_TYPE of CMETHOD. If context_used is 0, emit
3204  * normal constants, else emit a load from the rgctx.
3205  */
3206 static MonoInst*
3207 emit_get_rgctx_method (MonoCompile *cfg, int context_used,
3208                                            MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3209 {
3210         if (!context_used) {
3211                 MonoInst *ins;
3212
3213                 switch (rgctx_type) {
3214                 case MONO_RGCTX_INFO_METHOD:
3215                         EMIT_NEW_METHODCONST (cfg, ins, cmethod);
3216                         return ins;
3217                 case MONO_RGCTX_INFO_METHOD_RGCTX:
3218                         EMIT_NEW_METHOD_RGCTX_CONST (cfg, ins, cmethod);
3219                         return ins;
3220                 default:
3221                         g_assert_not_reached ();
3222                 }
3223         } else {
3224                 MonoJumpInfoRgctxEntry *entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_METHODCONST, cmethod, rgctx_type);
3225                 MonoInst *rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
3226
3227                 return emit_rgctx_fetch (cfg, rgctx, entry);
3228         }
3229 }
3230
3231 static MonoInst*
3232 emit_get_rgctx_field (MonoCompile *cfg, int context_used,
3233                                           MonoClassField *field, MonoRgctxInfoType rgctx_type)
3234 {
3235         MonoJumpInfoRgctxEntry *entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_FIELD, field, rgctx_type);
3236         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
3237
3238         return emit_rgctx_fetch (cfg, rgctx, entry);
3239 }
3240
3241 static int
3242 get_gsharedvt_info_slot (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3243 {
3244         MonoGSharedVtMethodInfo *info = cfg->gsharedvt_info;
3245         MonoRuntimeGenericContextInfoTemplate *template_;
3246         int i, idx;
3247
3248         g_assert (info);
3249
3250         for (i = 0; i < info->num_entries; ++i) {
3251                 MonoRuntimeGenericContextInfoTemplate *otemplate = &info->entries [i];
3252
3253                 if (otemplate->info_type == rgctx_type && otemplate->data == data && rgctx_type != MONO_RGCTX_INFO_LOCAL_OFFSET)
3254                         return i;
3255         }
3256
3257         if (info->num_entries == info->count_entries) {
3258                 MonoRuntimeGenericContextInfoTemplate *new_entries;
3259                 int new_count_entries = info->count_entries ? info->count_entries * 2 : 16;
3260
3261                 new_entries = (MonoRuntimeGenericContextInfoTemplate *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * new_count_entries);
3262
3263                 memcpy (new_entries, info->entries, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
3264                 info->entries = new_entries;
3265                 info->count_entries = new_count_entries;
3266         }
3267
3268         idx = info->num_entries;
3269         template_ = &info->entries [idx];
3270         template_->info_type = rgctx_type;
3271         template_->data = data;
3272
3273         info->num_entries ++;
3274
3275         return idx;
3276 }
3277
3278 /*
3279  * emit_get_gsharedvt_info:
3280  *
3281  *   This is similar to emit_get_rgctx_.., but loads the data from the gsharedvt info var instead of calling an rgctx fetch trampoline.
3282  */
3283 static MonoInst*
3284 emit_get_gsharedvt_info (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3285 {
3286         MonoInst *ins;
3287         int idx, dreg;
3288
3289         idx = get_gsharedvt_info_slot (cfg, data, rgctx_type);
3290         /* Load info->entries [idx] */
3291         dreg = alloc_preg (cfg);
3292         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, cfg->gsharedvt_info_var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
3293
3294         return ins;
3295 }
3296
3297 MonoInst*
3298 mini_emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type)
3299 {
3300         return emit_get_gsharedvt_info (cfg, &klass->byval_arg, rgctx_type);
3301 }
3302
3303 /*
3304  * On return the caller must check @klass for load errors.
3305  */
3306 static void
3307 emit_class_init (MonoCompile *cfg, MonoClass *klass)
3308 {
3309         MonoInst *vtable_arg;
3310         int context_used;
3311
3312         context_used = mini_class_check_context_used (cfg, klass);
3313
3314         if (context_used) {
3315                 vtable_arg = mini_emit_get_rgctx_klass (cfg, context_used,
3316                                                                                    klass, MONO_RGCTX_INFO_VTABLE);
3317         } else {
3318                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
3319
3320                 if (!vtable)
3321                         return;
3322                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
3323         }
3324
3325         if (!COMPILE_LLVM (cfg) && cfg->backend->have_op_generic_class_init) {
3326                 MonoInst *ins;
3327
3328                 /*
3329                  * Using an opcode instead of emitting IR here allows the hiding of the call inside the opcode,
3330                  * so this doesn't have to clobber any regs and it doesn't break basic blocks.
3331                  */
3332                 MONO_INST_NEW (cfg, ins, OP_GENERIC_CLASS_INIT);
3333                 ins->sreg1 = vtable_arg->dreg;
3334                 MONO_ADD_INS (cfg->cbb, ins);
3335         } else {
3336                 int inited_reg;
3337                 MonoBasicBlock *inited_bb;
3338                 MonoInst *args [16];
3339
3340                 inited_reg = alloc_ireg (cfg);
3341
3342                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, inited_reg, vtable_arg->dreg, MONO_STRUCT_OFFSET (MonoVTable, initialized));
3343
3344                 NEW_BBLOCK (cfg, inited_bb);
3345
3346                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, inited_reg, 0);
3347                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, inited_bb);
3348
3349                 args [0] = vtable_arg;
3350                 mono_emit_jit_icall (cfg, mono_generic_class_init, args);
3351
3352                 MONO_START_BB (cfg, inited_bb);
3353         }
3354 }
3355
3356 static void
3357 emit_seq_point (MonoCompile *cfg, MonoMethod *method, guint8* ip, gboolean intr_loc, gboolean nonempty_stack)
3358 {
3359         MonoInst *ins;
3360
3361         if (cfg->gen_seq_points && cfg->method == method) {
3362                 NEW_SEQ_POINT (cfg, ins, ip - cfg->header->code, intr_loc);
3363                 if (nonempty_stack)
3364                         ins->flags |= MONO_INST_NONEMPTY_STACK;
3365                 MONO_ADD_INS (cfg->cbb, ins);
3366         }
3367 }
3368
3369 void
3370 mini_save_cast_details (MonoCompile *cfg, MonoClass *klass, int obj_reg, gboolean null_check)
3371 {
3372         if (mini_get_debug_options ()->better_cast_details) {
3373                 int vtable_reg = alloc_preg (cfg);
3374                 int klass_reg = alloc_preg (cfg);
3375                 MonoBasicBlock *is_null_bb = NULL;
3376                 MonoInst *tls_get;
3377                 int to_klass_reg, context_used;
3378
3379                 if (null_check) {
3380                         NEW_BBLOCK (cfg, is_null_bb);
3381
3382                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
3383                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3384                 }
3385
3386                 tls_get = mono_create_tls_get (cfg, TLS_KEY_JIT_TLS);
3387                 if (!tls_get) {
3388                         fprintf (stderr, "error: --debug=casts not supported on this platform.\n.");
3389                         exit (1);
3390                 }
3391
3392                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3393                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3394
3395                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), klass_reg);
3396
3397                 context_used = mini_class_check_context_used (cfg, klass);
3398                 if (context_used) {
3399                         MonoInst *class_ins;
3400
3401                         class_ins = mini_emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3402                         to_klass_reg = class_ins->dreg;
3403                 } else {
3404                         to_klass_reg = alloc_preg (cfg);
3405                         MONO_EMIT_NEW_CLASSCONST (cfg, to_klass_reg, klass);
3406                 }
3407                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_to), to_klass_reg);
3408
3409                 if (null_check)
3410                         MONO_START_BB (cfg, is_null_bb);
3411         }
3412 }
3413
3414 void
3415 mini_reset_cast_details (MonoCompile *cfg)
3416 {
3417         /* Reset the variables holding the cast details */
3418         if (mini_get_debug_options ()->better_cast_details) {
3419                 MonoInst *tls_get = mono_create_tls_get (cfg, TLS_KEY_JIT_TLS);
3420                 /* It is enough to reset the from field */
3421                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), 0);
3422         }
3423 }
3424
3425 /*
3426  * On return the caller must check @array_class for load errors
3427  */
3428 static void
3429 mini_emit_check_array_type (MonoCompile *cfg, MonoInst *obj, MonoClass *array_class)
3430 {
3431         int vtable_reg = alloc_preg (cfg);
3432         int context_used;
3433
3434         context_used = mini_class_check_context_used (cfg, array_class);
3435
3436         mini_save_cast_details (cfg, array_class, obj->dreg, FALSE);
3437
3438         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3439
3440         if (cfg->opt & MONO_OPT_SHARED) {
3441                 int class_reg = alloc_preg (cfg);
3442                 MonoInst *ins;
3443
3444                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, class_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3445                 ins = mini_emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, array_class);
3446                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, class_reg, ins->dreg);
3447         } else if (context_used) {
3448                 MonoInst *vtable_ins;
3449
3450                 vtable_ins = mini_emit_get_rgctx_klass (cfg, context_used, array_class, MONO_RGCTX_INFO_VTABLE);
3451                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vtable_ins->dreg);
3452         } else {
3453                 if (cfg->compile_aot) {
3454                         int vt_reg;
3455                         MonoVTable *vtable;
3456
3457                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3458                                 return;
3459                         vt_reg = alloc_preg (cfg);
3460                         MONO_EMIT_NEW_VTABLECONST (cfg, vt_reg, vtable);
3461                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vt_reg);
3462                 } else {
3463                         MonoVTable *vtable;
3464                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3465                                 return;
3466                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vtable);
3467                 }
3468         }
3469         
3470         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ArrayTypeMismatchException");
3471
3472         mini_reset_cast_details (cfg);
3473 }
3474
3475 /**
3476  * Handles unbox of a Nullable<T>. If context_used is non zero, then shared 
3477  * generic code is generated.
3478  */
3479 static MonoInst*
3480 handle_unbox_nullable (MonoCompile* cfg, MonoInst* val, MonoClass* klass, int context_used)
3481 {
3482         MonoMethod* method = mono_class_get_method_from_name (klass, "Unbox", 1);
3483
3484         if (context_used) {
3485                 MonoInst *rgctx, *addr;
3486
3487                 /* FIXME: What if the class is shared?  We might not
3488                    have to get the address of the method from the
3489                    RGCTX. */
3490                 addr = emit_get_rgctx_method (cfg, context_used, method,
3491                                                                           MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
3492                 if (cfg->llvm_only) {
3493                         cfg->signatures = g_slist_prepend_mempool (cfg->mempool, cfg->signatures, mono_method_signature (method));
3494                         return emit_llvmonly_calli (cfg, mono_method_signature (method), &val, addr);
3495                 } else {
3496                         rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
3497
3498                         return mini_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
3499                 }
3500         } else {
3501                 gboolean pass_vtable, pass_mrgctx;
3502                 MonoInst *rgctx_arg = NULL;
3503
3504                 check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
3505                 g_assert (!pass_mrgctx);
3506
3507                 if (pass_vtable) {
3508                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
3509
3510                         g_assert (vtable);
3511                         EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
3512                 }
3513
3514                 return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
3515         }
3516 }
3517
3518 static MonoInst*
3519 handle_unbox (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, int context_used)
3520 {
3521         MonoInst *add;
3522         int obj_reg;
3523         int vtable_reg = alloc_dreg (cfg ,STACK_PTR);
3524         int klass_reg = alloc_dreg (cfg ,STACK_PTR);
3525         int eclass_reg = alloc_dreg (cfg ,STACK_PTR);
3526         int rank_reg = alloc_dreg (cfg ,STACK_I4);
3527
3528         obj_reg = sp [0]->dreg;
3529         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3530         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
3531
3532         /* FIXME: generics */
3533         g_assert (klass->rank == 0);
3534                         
3535         // Check rank == 0
3536         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, 0);
3537         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
3538
3539         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3540         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, element_class));
3541
3542         if (context_used) {
3543                 MonoInst *element_class;
3544
3545                 /* This assertion is from the unboxcast insn */
3546                 g_assert (klass->rank == 0);
3547
3548                 element_class = mini_emit_get_rgctx_klass (cfg, context_used,
3549                                 klass, MONO_RGCTX_INFO_ELEMENT_KLASS);
3550
3551                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, eclass_reg, element_class->dreg);
3552                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
3553         } else {
3554                 mini_save_cast_details (cfg, klass->element_class, obj_reg, FALSE);
3555                 mini_emit_class_check (cfg, eclass_reg, klass->element_class);
3556                 mini_reset_cast_details (cfg);
3557         }
3558
3559         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), obj_reg, sizeof (MonoObject));
3560         MONO_ADD_INS (cfg->cbb, add);
3561         add->type = STACK_MP;
3562         add->klass = klass;
3563
3564         return add;
3565 }
3566
3567 static MonoInst*
3568 handle_unbox_gsharedvt (MonoCompile *cfg, MonoClass *klass, MonoInst *obj)
3569 {
3570         MonoInst *addr, *klass_inst, *is_ref, *args[16];
3571         MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
3572         MonoInst *ins;
3573         int dreg, addr_reg;
3574
3575         klass_inst = mini_emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_KLASS);
3576
3577         /* obj */
3578         args [0] = obj;
3579
3580         /* klass */
3581         args [1] = klass_inst;
3582
3583         /* CASTCLASS */
3584         obj = mono_emit_jit_icall (cfg, mono_object_castclass_unbox, args);
3585
3586         NEW_BBLOCK (cfg, is_ref_bb);
3587         NEW_BBLOCK (cfg, is_nullable_bb);
3588         NEW_BBLOCK (cfg, end_bb);
3589         is_ref = mini_emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
3590         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
3591         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
3592
3593         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
3594         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
3595
3596         /* This will contain either the address of the unboxed vtype, or an address of the temporary where the ref is stored */
3597         addr_reg = alloc_dreg (cfg, STACK_MP);
3598
3599         /* Non-ref case */
3600         /* UNBOX */
3601         NEW_BIALU_IMM (cfg, addr, OP_ADD_IMM, addr_reg, obj->dreg, sizeof (MonoObject));
3602         MONO_ADD_INS (cfg->cbb, addr);
3603
3604         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3605
3606         /* Ref case */
3607         MONO_START_BB (cfg, is_ref_bb);
3608
3609         /* Save the ref to a temporary */
3610         dreg = alloc_ireg (cfg);
3611         EMIT_NEW_VARLOADA_VREG (cfg, addr, dreg, &klass->byval_arg);
3612         addr->dreg = addr_reg;
3613         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, obj->dreg);
3614         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3615
3616         /* Nullable case */
3617         MONO_START_BB (cfg, is_nullable_bb);
3618
3619         {
3620                 MonoInst *addr = mini_emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX);
3621                 MonoInst *unbox_call;
3622                 MonoMethodSignature *unbox_sig;
3623
3624                 unbox_sig = (MonoMethodSignature *)mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
3625                 unbox_sig->ret = &klass->byval_arg;
3626                 unbox_sig->param_count = 1;
3627                 unbox_sig->params [0] = &mono_defaults.object_class->byval_arg;
3628
3629                 if (cfg->llvm_only)
3630                         unbox_call = emit_llvmonly_calli (cfg, unbox_sig, &obj, addr);
3631                 else
3632                         unbox_call = mini_emit_calli (cfg, unbox_sig, &obj, addr, NULL, NULL);
3633
3634                 EMIT_NEW_VARLOADA_VREG (cfg, addr, unbox_call->dreg, &klass->byval_arg);
3635                 addr->dreg = addr_reg;
3636         }
3637
3638         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3639
3640         /* End */
3641         MONO_START_BB (cfg, end_bb);
3642
3643         /* LDOBJ */
3644         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr_reg, 0);
3645
3646         return ins;
3647 }
3648
3649 /*
3650  * Returns NULL and set the cfg exception on error.
3651  */
3652 static MonoInst*
3653 handle_alloc (MonoCompile *cfg, MonoClass *klass, gboolean for_box, int context_used)
3654 {
3655         MonoInst *iargs [2];
3656         void *alloc_ftn;
3657
3658         if (context_used) {
3659                 MonoInst *data;
3660                 MonoRgctxInfoType rgctx_info;
3661                 MonoInst *iargs [2];
3662                 gboolean known_instance_size = !mini_is_gsharedvt_klass (klass);
3663
3664                 MonoMethod *managed_alloc = mono_gc_get_managed_allocator (klass, for_box, known_instance_size);
3665
3666                 if (cfg->opt & MONO_OPT_SHARED)
3667                         rgctx_info = MONO_RGCTX_INFO_KLASS;
3668                 else
3669                         rgctx_info = MONO_RGCTX_INFO_VTABLE;
3670                 data = mini_emit_get_rgctx_klass (cfg, context_used, klass, rgctx_info);
3671
3672                 if (cfg->opt & MONO_OPT_SHARED) {
3673                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
3674                         iargs [1] = data;
3675                         alloc_ftn = ves_icall_object_new;
3676                 } else {
3677                         iargs [0] = data;
3678                         alloc_ftn = ves_icall_object_new_specific;
3679                 }
3680
3681                 if (managed_alloc && !(cfg->opt & MONO_OPT_SHARED)) {
3682                         if (known_instance_size) {
3683                                 int size = mono_class_instance_size (klass);
3684                                 if (size < sizeof (MonoObject))
3685                                         g_error ("Invalid size %d for class %s", size, mono_type_get_full_name (klass));
3686
3687                                 EMIT_NEW_ICONST (cfg, iargs [1], size);
3688                         }
3689                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
3690                 }
3691
3692                 return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
3693         }
3694
3695         if (cfg->opt & MONO_OPT_SHARED) {
3696                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
3697                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
3698
3699                 alloc_ftn = ves_icall_object_new;
3700         } else if (cfg->compile_aot && cfg->cbb->out_of_line && klass->type_token && klass->image == mono_defaults.corlib && !mono_class_is_ginst (klass)) {
3701                 /* This happens often in argument checking code, eg. throw new FooException... */
3702                 /* Avoid relocations and save some space by calling a helper function specialized to mscorlib */
3703                 EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (klass->type_token));
3704                 alloc_ftn = mono_helper_newobj_mscorlib;
3705         } else {
3706                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
3707                 MonoMethod *managed_alloc = NULL;
3708
3709                 if (!vtable) {
3710                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
3711                         cfg->exception_ptr = klass;
3712                         return NULL;
3713                 }
3714
3715                 managed_alloc = mono_gc_get_managed_allocator (klass, for_box, TRUE);
3716
3717                 if (managed_alloc) {
3718                         int size = mono_class_instance_size (klass);
3719                         if (size < sizeof (MonoObject))
3720                                 g_error ("Invalid size %d for class %s", size, mono_type_get_full_name (klass));
3721
3722                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
3723                         EMIT_NEW_ICONST (cfg, iargs [1], size);
3724                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
3725                 }
3726                 alloc_ftn = ves_icall_object_new_specific;
3727                 EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
3728         }
3729
3730         return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
3731 }
3732         
3733 /*
3734  * Returns NULL and set the cfg exception on error.
3735  */     
3736 static MonoInst*
3737 handle_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_used)
3738 {
3739         MonoInst *alloc, *ins;
3740
3741         if (mono_class_is_nullable (klass)) {
3742                 MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
3743
3744                 if (context_used) {
3745                         if (cfg->llvm_only && cfg->gsharedvt) {
3746                                 MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
3747                                                                                                                 MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
3748                                 return emit_llvmonly_calli (cfg, mono_method_signature (method), &val, addr);
3749                         } else {
3750                                 /* FIXME: What if the class is shared?  We might not
3751                                    have to get the method address from the RGCTX. */
3752                                 MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
3753                                                                                                                 MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
3754                                 MonoInst *rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
3755
3756                                 return mini_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
3757                         }
3758                 } else {
3759                         gboolean pass_vtable, pass_mrgctx;
3760                         MonoInst *rgctx_arg = NULL;
3761
3762                         check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
3763                         g_assert (!pass_mrgctx);
3764
3765                         if (pass_vtable) {
3766                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
3767
3768                                 g_assert (vtable);
3769                                 EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
3770                         }
3771
3772                         return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
3773                 }
3774         }
3775
3776         if (mini_is_gsharedvt_klass (klass)) {
3777                 MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
3778                 MonoInst *res, *is_ref, *src_var, *addr;
3779                 int dreg;
3780
3781                 dreg = alloc_ireg (cfg);
3782
3783                 NEW_BBLOCK (cfg, is_ref_bb);
3784                 NEW_BBLOCK (cfg, is_nullable_bb);
3785                 NEW_BBLOCK (cfg, end_bb);
3786                 is_ref = mini_emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
3787                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
3788                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
3789
3790                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
3791                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
3792
3793                 /* Non-ref case */
3794                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
3795                 if (!alloc)
3796                         return NULL;
3797                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
3798                 ins->opcode = OP_STOREV_MEMBASE;
3799
3800                 EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, alloc->dreg);
3801                 res->type = STACK_OBJ;
3802                 res->klass = klass;
3803                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3804                 
3805                 /* Ref case */
3806                 MONO_START_BB (cfg, is_ref_bb);
3807
3808                 /* val is a vtype, so has to load the value manually */
3809                 src_var = get_vreg_to_inst (cfg, val->dreg);
3810                 if (!src_var)
3811                         src_var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, val->dreg);
3812                 EMIT_NEW_VARLOADA (cfg, addr, src_var, src_var->inst_vtype);
3813                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, addr->dreg, 0);
3814                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3815
3816                 /* Nullable case */
3817                 MONO_START_BB (cfg, is_nullable_bb);
3818
3819                 {
3820                         MonoInst *addr = mini_emit_get_gsharedvt_info_klass (cfg, klass,
3821                                                                                                         MONO_RGCTX_INFO_NULLABLE_CLASS_BOX);
3822                         MonoInst *box_call;
3823                         MonoMethodSignature *box_sig;
3824
3825                         /*
3826                          * klass is Nullable<T>, need to call Nullable<T>.Box () using a gsharedvt signature, but we cannot
3827                          * construct that method at JIT time, so have to do things by hand.
3828                          */
3829                         box_sig = (MonoMethodSignature *)mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
3830                         box_sig->ret = &mono_defaults.object_class->byval_arg;
3831                         box_sig->param_count = 1;
3832                         box_sig->params [0] = &klass->byval_arg;
3833
3834                         if (cfg->llvm_only)
3835                                 box_call = emit_llvmonly_calli (cfg, box_sig, &val, addr);
3836                         else
3837                                 box_call = mini_emit_calli (cfg, box_sig, &val, addr, NULL, NULL);
3838                         EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, box_call->dreg);
3839                         res->type = STACK_OBJ;
3840                         res->klass = klass;
3841                 }
3842
3843                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3844
3845                 MONO_START_BB (cfg, end_bb);
3846
3847                 return res;
3848         } else {
3849                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
3850                 if (!alloc)
3851                         return NULL;
3852
3853                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
3854                 return alloc;
3855         }
3856 }
3857
3858 static GHashTable* direct_icall_type_hash;
3859
3860 static gboolean
3861 icall_is_direct_callable (MonoCompile *cfg, MonoMethod *cmethod)
3862 {
3863         /* LLVM on amd64 can't handle calls to non-32 bit addresses */
3864         if (!direct_icalls_enabled (cfg))
3865                 return FALSE;
3866
3867         /*
3868          * An icall is directly callable if it doesn't directly or indirectly call mono_raise_exception ().
3869          * Whitelist a few icalls for now.
3870          */
3871         if (!direct_icall_type_hash) {
3872                 GHashTable *h = g_hash_table_new (g_str_hash, g_str_equal);
3873
3874                 g_hash_table_insert (h, (char*)"Decimal", GUINT_TO_POINTER (1));
3875                 g_hash_table_insert (h, (char*)"Number", GUINT_TO_POINTER (1));
3876                 g_hash_table_insert (h, (char*)"Buffer", GUINT_TO_POINTER (1));
3877                 g_hash_table_insert (h, (char*)"Monitor", GUINT_TO_POINTER (1));
3878                 mono_memory_barrier ();
3879                 direct_icall_type_hash = h;
3880         }
3881
3882         if (cmethod->klass == mono_defaults.math_class)
3883                 return TRUE;
3884         /* No locking needed */
3885         if (cmethod->klass->image == mono_defaults.corlib && g_hash_table_lookup (direct_icall_type_hash, cmethod->klass->name))
3886                 return TRUE;
3887         return FALSE;
3888 }
3889
3890 static gboolean
3891 method_needs_stack_walk (MonoCompile *cfg, MonoMethod *cmethod)
3892 {
3893         if (cmethod->klass == mono_defaults.systemtype_class) {
3894                 if (!strcmp (cmethod->name, "GetType"))
3895                         return TRUE;
3896         }
3897         return FALSE;
3898 }
3899
3900 static G_GNUC_UNUSED MonoInst*
3901 handle_enum_has_flag (MonoCompile *cfg, MonoClass *klass, MonoInst *enum_this, MonoInst *enum_flag)
3902 {
3903         MonoType *enum_type = mono_type_get_underlying_type (&klass->byval_arg);
3904         guint32 load_opc = mono_type_to_load_membase (cfg, enum_type);
3905         gboolean is_i4;
3906
3907         switch (enum_type->type) {
3908         case MONO_TYPE_I8:
3909         case MONO_TYPE_U8:
3910 #if SIZEOF_REGISTER == 8
3911         case MONO_TYPE_I:
3912         case MONO_TYPE_U:
3913 #endif
3914                 is_i4 = FALSE;
3915                 break;
3916         default:
3917                 is_i4 = TRUE;
3918                 break;
3919         }
3920
3921         {
3922                 MonoInst *load, *and_, *cmp, *ceq;
3923                 int enum_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
3924                 int and_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
3925                 int dest_reg = alloc_ireg (cfg);
3926
3927                 EMIT_NEW_LOAD_MEMBASE (cfg, load, load_opc, enum_reg, enum_this->dreg, 0);
3928                 EMIT_NEW_BIALU (cfg, and_, is_i4 ? OP_IAND : OP_LAND, and_reg, enum_reg, enum_flag->dreg);
3929                 EMIT_NEW_BIALU (cfg, cmp, is_i4 ? OP_ICOMPARE : OP_LCOMPARE, -1, and_reg, enum_flag->dreg);
3930                 EMIT_NEW_UNALU (cfg, ceq, is_i4 ? OP_ICEQ : OP_LCEQ, dest_reg, -1);
3931
3932                 ceq->type = STACK_I4;
3933
3934                 if (!is_i4) {
3935                         load = mono_decompose_opcode (cfg, load);
3936                         and_ = mono_decompose_opcode (cfg, and_);
3937                         cmp = mono_decompose_opcode (cfg, cmp);
3938                         ceq = mono_decompose_opcode (cfg, ceq);
3939                 }
3940
3941                 return ceq;
3942         }
3943 }
3944
3945 /*
3946  * Returns NULL and set the cfg exception on error.
3947  */
3948 static G_GNUC_UNUSED MonoInst*
3949 handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, MonoMethod *method, int context_used, gboolean virtual_)
3950 {
3951         MonoInst *ptr;
3952         int dreg;
3953         gpointer trampoline;
3954         MonoInst *obj, *method_ins, *tramp_ins;
3955         MonoDomain *domain;
3956         guint8 **code_slot;
3957
3958         if (virtual_ && !cfg->llvm_only) {
3959                 MonoMethod *invoke = mono_get_delegate_invoke (klass);
3960                 g_assert (invoke);
3961
3962                 if (!mono_get_delegate_virtual_invoke_impl (mono_method_signature (invoke), context_used ? NULL : method))
3963                         return NULL;
3964         }
3965
3966         obj = handle_alloc (cfg, klass, FALSE, mono_class_check_context_used (klass));
3967         if (!obj)
3968                 return NULL;
3969
3970         /* Inline the contents of mono_delegate_ctor */
3971
3972         /* Set target field */
3973         /* Optimize away setting of NULL target */
3974         if (!MONO_INS_IS_PCONST_NULL (target)) {
3975                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, target->dreg, 0);
3976                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "NullReferenceException");
3977                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target), target->dreg);
3978                 if (cfg->gen_write_barriers) {
3979                         dreg = alloc_preg (cfg);
3980                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target));
3981                         mini_emit_write_barrier (cfg, ptr, target);
3982                 }
3983         }
3984
3985         /* Set method field */
3986         method_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
3987         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method), method_ins->dreg);
3988
3989         /* 
3990          * To avoid looking up the compiled code belonging to the target method
3991          * in mono_delegate_trampoline (), we allocate a per-domain memory slot to
3992          * store it, and we fill it after the method has been compiled.
3993          */
3994         if (!method->dynamic && !(cfg->opt & MONO_OPT_SHARED)) {
3995                 MonoInst *code_slot_ins;
3996
3997                 if (context_used) {
3998                         code_slot_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD_DELEGATE_CODE);
3999                 } else {
4000                         domain = mono_domain_get ();
4001                         mono_domain_lock (domain);
4002                         if (!domain_jit_info (domain)->method_code_hash)
4003                                 domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
4004                         code_slot = (guint8 **)g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, method);
4005                         if (!code_slot) {
4006                                 code_slot = (guint8 **)mono_domain_alloc0 (domain, sizeof (gpointer));
4007                                 g_hash_table_insert (domain_jit_info (domain)->method_code_hash, method, code_slot);
4008                         }
4009                         mono_domain_unlock (domain);
4010
4011                         code_slot_ins = mini_emit_runtime_constant (cfg, MONO_PATCH_INFO_METHOD_CODE_SLOT, method);
4012                 }
4013                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_code), code_slot_ins->dreg);                
4014         }
4015
4016         if (cfg->llvm_only) {
4017                 MonoInst *args [16];
4018
4019                 if (virtual_) {
4020                         args [0] = obj;
4021                         args [1] = target;
4022                         args [2] = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
4023                         mono_emit_jit_icall (cfg, mono_llvmonly_init_delegate_virtual, args);
4024                 } else {
4025                         args [0] = obj;
4026                         mono_emit_jit_icall (cfg, mono_llvmonly_init_delegate, args);
4027                 }
4028
4029                 return obj;
4030         }
4031
4032         if (cfg->compile_aot) {
4033                 MonoDelegateClassMethodPair *del_tramp;
4034
4035                 del_tramp = (MonoDelegateClassMethodPair *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoDelegateClassMethodPair));
4036                 del_tramp->klass = klass;
4037                 del_tramp->method = context_used ? NULL : method;
4038                 del_tramp->is_virtual = virtual_;
4039                 EMIT_NEW_AOTCONST (cfg, tramp_ins, MONO_PATCH_INFO_DELEGATE_TRAMPOLINE, del_tramp);
4040         } else {
4041                 if (virtual_)
4042                         trampoline = mono_create_delegate_virtual_trampoline (cfg->domain, klass, context_used ? NULL : method);
4043                 else
4044                         trampoline = mono_create_delegate_trampoline_info (cfg->domain, klass, context_used ? NULL : method);
4045                 EMIT_NEW_PCONST (cfg, tramp_ins, trampoline);
4046         }
4047
4048         /* Set invoke_impl field */
4049         if (virtual_) {
4050                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), tramp_ins->dreg);
4051         } else {
4052                 dreg = alloc_preg (cfg);
4053                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, invoke_impl));
4054                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), dreg);
4055
4056                 dreg = alloc_preg (cfg);
4057                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, method_ptr));
4058                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr), dreg);
4059         }
4060
4061         dreg = alloc_preg (cfg);
4062         MONO_EMIT_NEW_ICONST (cfg, dreg, virtual_ ? 1 : 0);
4063         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_is_virtual), dreg);
4064
4065         /* All the checks which are in mono_delegate_ctor () are done by the delegate trampoline */
4066
4067         return obj;
4068 }
4069
4070 static MonoInst*
4071 handle_array_new (MonoCompile *cfg, int rank, MonoInst **sp, unsigned char *ip)
4072 {
4073         MonoJitICallInfo *info;
4074
4075         /* Need to register the icall so it gets an icall wrapper */
4076         info = mono_get_array_new_va_icall (rank);
4077
4078         cfg->flags |= MONO_CFG_HAS_VARARGS;
4079
4080         /* mono_array_new_va () needs a vararg calling convention */
4081         cfg->exception_message = g_strdup ("array-new");
4082         cfg->disable_llvm = TRUE;
4083
4084         /* FIXME: This uses info->sig, but it should use the signature of the wrapper */
4085         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, sp);
4086 }
4087
4088 /*
4089  * handle_constrained_gsharedvt_call:
4090  *
4091  *   Handle constrained calls where the receiver is a gsharedvt type.
4092  * Return the instruction representing the call. Set the cfg exception on failure.
4093  */
4094 static MonoInst*
4095 handle_constrained_gsharedvt_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp, MonoClass *constrained_class,
4096                                                                    gboolean *ref_emit_widen)
4097 {
4098         MonoInst *ins = NULL;
4099         gboolean emit_widen = *ref_emit_widen;
4100
4101         /*
4102          * Constrained calls need to behave differently at runtime dependending on whenever the receiver is instantiated as ref type or as a vtype.
4103          * 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
4104          * pack the arguments into an array, and do the rest of the work in in an icall.
4105          */
4106         if (((cmethod->klass == mono_defaults.object_class) || mono_class_is_interface (cmethod->klass) || (!cmethod->klass->valuetype && cmethod->klass->image != mono_defaults.corlib)) &&
4107                 (MONO_TYPE_IS_VOID (fsig->ret) || MONO_TYPE_IS_PRIMITIVE (fsig->ret) || MONO_TYPE_IS_REFERENCE (fsig->ret) || MONO_TYPE_ISSTRUCT (fsig->ret) || mono_class_is_enum (mono_class_from_mono_type (fsig->ret)) || mini_is_gsharedvt_type (fsig->ret)) &&
4108                 (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]))))) {
4109                 MonoInst *args [16];
4110
4111                 /*
4112                  * This case handles calls to
4113                  * - object:ToString()/Equals()/GetHashCode(),
4114                  * - System.IComparable<T>:CompareTo()
4115                  * - System.IEquatable<T>:Equals ()
4116                  * plus some simple interface calls enough to support AsyncTaskMethodBuilder.
4117                  */
4118
4119                 args [0] = sp [0];
4120                 if (mono_method_check_context_used (cmethod))
4121                         args [1] = emit_get_rgctx_method (cfg, mono_method_check_context_used (cmethod), cmethod, MONO_RGCTX_INFO_METHOD);
4122                 else
4123                         EMIT_NEW_METHODCONST (cfg, args [1], cmethod);
4124                 args [2] = mini_emit_get_rgctx_klass (cfg, mono_class_check_context_used (constrained_class), constrained_class, MONO_RGCTX_INFO_KLASS);
4125
4126                 /* !fsig->hasthis is for the wrapper for the Object.GetType () icall */
4127                 if (fsig->hasthis && fsig->param_count) {
4128                         /* Pass the arguments using a localloc-ed array using the format expected by runtime_invoke () */
4129                         MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
4130                         ins->dreg = alloc_preg (cfg);
4131                         ins->inst_imm = fsig->param_count * sizeof (mgreg_t);
4132                         MONO_ADD_INS (cfg->cbb, ins);
4133                         args [4] = ins;
4134
4135                         if (mini_is_gsharedvt_type (fsig->params [0])) {
4136                                 int addr_reg, deref_arg_reg;
4137
4138                                 ins = mini_emit_get_gsharedvt_info_klass (cfg, mono_class_from_mono_type (fsig->params [0]), MONO_RGCTX_INFO_CLASS_BOX_TYPE);
4139                                 deref_arg_reg = alloc_preg (cfg);
4140                                 /* deref_arg = BOX_TYPE != MONO_GSHAREDVT_BOX_TYPE_VTYPE */
4141                                 EMIT_NEW_BIALU_IMM (cfg, args [3], OP_ISUB_IMM, deref_arg_reg, ins->dreg, 1);
4142
4143                                 EMIT_NEW_VARLOADA_VREG (cfg, ins, sp [1]->dreg, fsig->params [0]);
4144                                 addr_reg = ins->dreg;
4145                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, addr_reg);
4146                         } else {
4147                                 EMIT_NEW_ICONST (cfg, args [3], 0);
4148                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, sp [1]->dreg);
4149                         }
4150                 } else {
4151                         EMIT_NEW_ICONST (cfg, args [3], 0);
4152                         EMIT_NEW_ICONST (cfg, args [4], 0);
4153                 }
4154                 ins = mono_emit_jit_icall (cfg, mono_gsharedvt_constrained_call, args);
4155                 emit_widen = FALSE;
4156
4157                 if (mini_is_gsharedvt_type (fsig->ret)) {
4158                         ins = handle_unbox_gsharedvt (cfg, mono_class_from_mono_type (fsig->ret), ins);
4159                 } else if (MONO_TYPE_IS_PRIMITIVE (fsig->ret) || MONO_TYPE_ISSTRUCT (fsig->ret) || mono_class_is_enum (mono_class_from_mono_type (fsig->ret))) {
4160                         MonoInst *add;
4161
4162                         /* Unbox */
4163                         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), ins->dreg, sizeof (MonoObject));
4164                         MONO_ADD_INS (cfg->cbb, add);
4165                         /* Load value */
4166                         NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, add->dreg, 0);
4167                         MONO_ADD_INS (cfg->cbb, ins);
4168                         /* ins represents the call result */
4169                 }
4170         } else {
4171                 GSHAREDVT_FAILURE (CEE_CALLVIRT);
4172         }
4173
4174         *ref_emit_widen = emit_widen;
4175
4176         return ins;
4177
4178  exception_exit:
4179         return NULL;
4180 }
4181
4182 static void
4183 mono_emit_load_got_addr (MonoCompile *cfg)
4184 {
4185         MonoInst *getaddr, *dummy_use;
4186
4187         if (!cfg->got_var || cfg->got_var_allocated)
4188                 return;
4189
4190         MONO_INST_NEW (cfg, getaddr, OP_LOAD_GOTADDR);
4191         getaddr->cil_code = cfg->header->code;
4192         getaddr->dreg = cfg->got_var->dreg;
4193
4194         /* Add it to the start of the first bblock */
4195         if (cfg->bb_entry->code) {
4196                 getaddr->next = cfg->bb_entry->code;
4197                 cfg->bb_entry->code = getaddr;
4198         }
4199         else
4200                 MONO_ADD_INS (cfg->bb_entry, getaddr);
4201
4202         cfg->got_var_allocated = TRUE;
4203
4204         /* 
4205          * Add a dummy use to keep the got_var alive, since real uses might
4206          * only be generated by the back ends.
4207          * Add it to end_bblock, so the variable's lifetime covers the whole
4208          * method.
4209          * It would be better to make the usage of the got var explicit in all
4210          * cases when the backend needs it (i.e. calls, throw etc.), so this
4211          * wouldn't be needed.
4212          */
4213         NEW_DUMMY_USE (cfg, dummy_use, cfg->got_var);
4214         MONO_ADD_INS (cfg->bb_exit, dummy_use);
4215 }
4216
4217 static int inline_limit;
4218 static gboolean inline_limit_inited;
4219
4220 static gboolean
4221 mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
4222 {
4223         MonoMethodHeaderSummary header;
4224         MonoVTable *vtable;
4225 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
4226         MonoMethodSignature *sig = mono_method_signature (method);
4227         int i;
4228 #endif
4229
4230         if (cfg->disable_inline)
4231                 return FALSE;
4232         if (cfg->gsharedvt)
4233                 return FALSE;
4234
4235         if (cfg->inline_depth > 10)
4236                 return FALSE;
4237
4238         if (!mono_method_get_header_summary (method, &header))
4239                 return FALSE;
4240
4241         /*runtime, icall and pinvoke are checked by summary call*/
4242         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
4243             (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
4244             (mono_class_is_marshalbyref (method->klass)) ||
4245             header.has_clauses)
4246                 return FALSE;
4247
4248         /* also consider num_locals? */
4249         /* Do the size check early to avoid creating vtables */
4250         if (!inline_limit_inited) {
4251                 char *inlinelimit;
4252                 if ((inlinelimit = g_getenv ("MONO_INLINELIMIT"))) {
4253                         inline_limit = atoi (inlinelimit);
4254                         g_free (inlinelimit);
4255                 } else
4256                         inline_limit = INLINE_LENGTH_LIMIT;
4257                 inline_limit_inited = TRUE;
4258         }
4259         if (header.code_size >= inline_limit && !(method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))
4260                 return FALSE;
4261
4262         /*
4263          * if we can initialize the class of the method right away, we do,
4264          * otherwise we don't allow inlining if the class needs initialization,
4265          * since it would mean inserting a call to mono_runtime_class_init()
4266          * inside the inlined code
4267          */
4268         if (cfg->gshared && method->klass->has_cctor && mini_class_check_context_used (cfg, method->klass))
4269                 return FALSE;
4270
4271         if (!(cfg->opt & MONO_OPT_SHARED)) {
4272                 /* The AggressiveInlining hint is a good excuse to force that cctor to run. */
4273                 if (method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING) {
4274                         if (method->klass->has_cctor) {
4275                                 vtable = mono_class_vtable (cfg->domain, method->klass);
4276                                 if (!vtable)
4277                                         return FALSE;
4278                                 if (!cfg->compile_aot) {
4279                                         MonoError error;
4280                                         if (!mono_runtime_class_init_full (vtable, &error)) {
4281                                                 mono_error_cleanup (&error);
4282                                                 return FALSE;
4283                                         }
4284                                 }
4285                         }
4286                 } else if (mono_class_is_before_field_init (method->klass)) {
4287                         if (cfg->run_cctors && method->klass->has_cctor) {
4288                                 /*FIXME it would easier and lazier to just use mono_class_try_get_vtable */
4289                                 if (!method->klass->runtime_info)
4290                                         /* No vtable created yet */
4291                                         return FALSE;
4292                                 vtable = mono_class_vtable (cfg->domain, method->klass);
4293                                 if (!vtable)
4294                                         return FALSE;
4295                                 /* This makes so that inline cannot trigger */
4296                                 /* .cctors: too many apps depend on them */
4297                                 /* running with a specific order... */
4298                                 if (! vtable->initialized)
4299                                         return FALSE;
4300                                 MonoError error;
4301                                 if (!mono_runtime_class_init_full (vtable, &error)) {
4302                                         mono_error_cleanup (&error);
4303                                         return FALSE;
4304                                 }
4305                         }
4306                 } else if (mono_class_needs_cctor_run (method->klass, NULL)) {
4307                         if (!method->klass->runtime_info)
4308                                 /* No vtable created yet */
4309                                 return FALSE;
4310                         vtable = mono_class_vtable (cfg->domain, method->klass);
4311                         if (!vtable)
4312                                 return FALSE;
4313                         if (!vtable->initialized)
4314                                 return FALSE;
4315                 }
4316         } else {
4317                 /* 
4318                  * If we're compiling for shared code
4319                  * the cctor will need to be run at aot method load time, for example,
4320                  * or at the end of the compilation of the inlining method.
4321                  */
4322                 if (mono_class_needs_cctor_run (method->klass, NULL) && !mono_class_is_before_field_init (method->klass))
4323                         return FALSE;
4324         }
4325
4326 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
4327         if (mono_arch_is_soft_float ()) {
4328                 /* FIXME: */
4329                 if (sig->ret && sig->ret->type == MONO_TYPE_R4)
4330                         return FALSE;
4331                 for (i = 0; i < sig->param_count; ++i)
4332                         if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_R4)
4333                                 return FALSE;
4334         }
4335 #endif
4336
4337         if (g_list_find (cfg->dont_inline, method))
4338                 return FALSE;
4339
4340         if (mono_profiler_get_call_instrumentation_flags (method))
4341                 return FALSE;
4342
4343         return TRUE;
4344 }
4345
4346 static gboolean
4347 mini_field_access_needs_cctor_run (MonoCompile *cfg, MonoMethod *method, MonoClass *klass, MonoVTable *vtable)
4348 {
4349         if (!cfg->compile_aot) {
4350                 g_assert (vtable);
4351                 if (vtable->initialized)
4352                         return FALSE;
4353         }
4354
4355         if (mono_class_is_before_field_init (klass)) {
4356                 if (cfg->method == method)
4357                         return FALSE;
4358         }
4359
4360         if (!mono_class_needs_cctor_run (klass, method))
4361                 return FALSE;
4362
4363         if (! (method->flags & METHOD_ATTRIBUTE_STATIC) && (klass == method->klass))
4364                 /* The initialization is already done before the method is called */
4365                 return FALSE;
4366
4367         return TRUE;
4368 }
4369
4370 MonoInst*
4371 mini_emit_ldelema_1_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index, gboolean bcheck)
4372 {
4373         MonoInst *ins;
4374         guint32 size;
4375         int mult_reg, add_reg, array_reg, index_reg, index2_reg;
4376         int context_used;
4377
4378         if (mini_is_gsharedvt_variable_klass (klass)) {
4379                 size = -1;
4380         } else {
4381                 mono_class_init (klass);
4382                 size = mono_class_array_element_size (klass);
4383         }
4384
4385         mult_reg = alloc_preg (cfg);
4386         array_reg = arr->dreg;
4387         index_reg = index->dreg;
4388
4389 #if SIZEOF_REGISTER == 8
4390         /* The array reg is 64 bits but the index reg is only 32 */
4391         if (COMPILE_LLVM (cfg)) {
4392                 /*
4393                  * abcrem can't handle the OP_SEXT_I4, so add this after abcrem,
4394                  * during OP_BOUNDS_CHECK decomposition, and in the implementation
4395                  * of OP_X86_LEA for llvm.
4396                  */
4397                 index2_reg = index_reg;
4398         } else {
4399                 index2_reg = alloc_preg (cfg);
4400                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index2_reg, index_reg);
4401         }
4402 #else
4403         if (index->type == STACK_I8) {
4404                 index2_reg = alloc_preg (cfg);
4405                 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I4, index2_reg, index_reg);
4406         } else {
4407                 index2_reg = index_reg;
4408         }
4409 #endif
4410
4411         if (bcheck)
4412                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index2_reg);
4413
4414 #if defined(TARGET_X86) || defined(TARGET_AMD64)
4415         if (size == 1 || size == 2 || size == 4 || size == 8) {
4416                 static const int fast_log2 [] = { 1, 0, 1, -1, 2, -1, -1, -1, 3 };
4417
4418                 EMIT_NEW_X86_LEA (cfg, ins, array_reg, index2_reg, fast_log2 [size], MONO_STRUCT_OFFSET (MonoArray, vector));
4419                 ins->klass = mono_class_get_element_class (klass);
4420                 ins->type = STACK_MP;
4421
4422                 return ins;
4423         }
4424 #endif          
4425
4426         add_reg = alloc_ireg_mp (cfg);
4427
4428         if (size == -1) {
4429                 MonoInst *rgctx_ins;
4430
4431                 /* gsharedvt */
4432                 g_assert (cfg->gshared);
4433                 context_used = mini_class_check_context_used (cfg, klass);
4434                 g_assert (context_used);
4435                 rgctx_ins = mini_emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE);
4436                 MONO_EMIT_NEW_BIALU (cfg, OP_IMUL, mult_reg, index2_reg, rgctx_ins->dreg);
4437         } else {
4438                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MUL_IMM, mult_reg, index2_reg, size);
4439         }
4440         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, array_reg, mult_reg);
4441         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
4442         ins->klass = mono_class_get_element_class (klass);
4443         ins->type = STACK_MP;
4444         MONO_ADD_INS (cfg->cbb, ins);
4445
4446         return ins;
4447 }
4448
4449 static MonoInst*
4450 mini_emit_ldelema_2_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index_ins1, MonoInst *index_ins2)
4451 {
4452         int bounds_reg = alloc_preg (cfg);
4453         int add_reg = alloc_ireg_mp (cfg);
4454         int mult_reg = alloc_preg (cfg);
4455         int mult2_reg = alloc_preg (cfg);
4456         int low1_reg = alloc_preg (cfg);
4457         int low2_reg = alloc_preg (cfg);
4458         int high1_reg = alloc_preg (cfg);
4459         int high2_reg = alloc_preg (cfg);
4460         int realidx1_reg = alloc_preg (cfg);
4461         int realidx2_reg = alloc_preg (cfg);
4462         int sum_reg = alloc_preg (cfg);
4463         int index1, index2, tmpreg;
4464         MonoInst *ins;
4465         guint32 size;
4466
4467         mono_class_init (klass);
4468         size = mono_class_array_element_size (klass);
4469
4470         index1 = index_ins1->dreg;
4471         index2 = index_ins2->dreg;
4472
4473 #if SIZEOF_REGISTER == 8
4474         /* The array reg is 64 bits but the index reg is only 32 */
4475         if (COMPILE_LLVM (cfg)) {
4476                 /* Not needed */
4477         } else {
4478                 tmpreg = alloc_preg (cfg);
4479                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index1);
4480                 index1 = tmpreg;
4481                 tmpreg = alloc_preg (cfg);
4482                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index2);
4483                 index2 = tmpreg;
4484         }
4485 #else
4486         // FIXME: Do we need to do something here for i8 indexes, like in ldelema_1_ins ?
4487         tmpreg = -1;
4488 #endif
4489
4490         /* range checking */
4491         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, 
4492                                        arr->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
4493
4494         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low1_reg, 
4495                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
4496         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx1_reg, index1, low1_reg);
4497         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high1_reg, 
4498                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
4499         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high1_reg, realidx1_reg);
4500         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
4501
4502         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low2_reg, 
4503                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
4504         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx2_reg, index2, low2_reg);
4505         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high2_reg, 
4506                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, length));
4507         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high2_reg, realidx2_reg);
4508         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
4509
4510         MONO_EMIT_NEW_BIALU (cfg, OP_PMUL, mult_reg, high2_reg, realidx1_reg);
4511         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, mult_reg, realidx2_reg);
4512         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PMUL_IMM, mult2_reg, sum_reg, size);
4513         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult2_reg, arr->dreg);
4514         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
4515
4516         ins->type = STACK_MP;
4517         ins->klass = klass;
4518         MONO_ADD_INS (cfg->cbb, ins);
4519
4520         return ins;
4521 }
4522
4523 static MonoInst*
4524 mini_emit_ldelema_ins (MonoCompile *cfg, MonoMethod *cmethod, MonoInst **sp, unsigned char *ip, gboolean is_set)
4525 {
4526         int rank;
4527         MonoInst *addr;
4528         MonoMethod *addr_method;
4529         int element_size;
4530         MonoClass *eclass = cmethod->klass->element_class;
4531
4532         rank = mono_method_signature (cmethod)->param_count - (is_set? 1: 0);
4533
4534         if (rank == 1)
4535                 return mini_emit_ldelema_1_ins (cfg, eclass, sp [0], sp [1], TRUE);
4536
4537         /* emit_ldelema_2 depends on OP_LMUL */
4538         if (!cfg->backend->emulate_mul_div && rank == 2 && (cfg->opt & MONO_OPT_INTRINS) && !mini_is_gsharedvt_variable_klass (eclass)) {
4539                 return mini_emit_ldelema_2_ins (cfg, eclass, sp [0], sp [1], sp [2]);
4540         }
4541
4542         if (mini_is_gsharedvt_variable_klass (eclass))
4543                 element_size = 0;
4544         else
4545                 element_size = mono_class_array_element_size (eclass);
4546         addr_method = mono_marshal_get_array_address (rank, element_size);
4547         addr = mono_emit_method_call (cfg, addr_method, sp, NULL);
4548
4549         return addr;
4550 }
4551
4552 /* optimize the simple GetGenericValueImpl/SetGenericValueImpl generic icalls */
4553 static MonoInst*
4554 emit_array_generic_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
4555 {
4556         MonoInst *addr, *store, *load;
4557         MonoClass *eklass = mono_class_from_mono_type (fsig->params [2]);
4558
4559         /* the bounds check is already done by the callers */
4560         addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
4561         if (is_set) {
4562                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, args [2]->dreg, 0);
4563                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, addr->dreg, 0, load->dreg);
4564                 if (mini_type_is_reference (&eklass->byval_arg))
4565                         mini_emit_write_barrier (cfg, addr, load);
4566         } else {
4567                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, addr->dreg, 0);
4568                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, args [2]->dreg, 0, load->dreg);
4569         }
4570         return store;
4571 }
4572
4573
4574 static gboolean
4575 generic_class_is_reference_type (MonoCompile *cfg, MonoClass *klass)
4576 {
4577         return mini_type_is_reference (&klass->byval_arg);
4578 }
4579
4580 static MonoInst*
4581 emit_array_store (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, gboolean safety_checks)
4582 {
4583         if (safety_checks && generic_class_is_reference_type (cfg, klass) &&
4584                 !(MONO_INS_IS_PCONST_NULL (sp [2]))) {
4585                 MonoClass *obj_array = mono_array_class_get_cached (mono_defaults.object_class, 1);
4586                 MonoMethod *helper = mono_marshal_get_virtual_stelemref (obj_array);
4587                 MonoInst *iargs [3];
4588
4589                 if (!helper->slot)
4590                         mono_class_setup_vtable (obj_array);
4591                 g_assert (helper->slot);
4592
4593                 if (sp [0]->type != STACK_OBJ)
4594                         return NULL;
4595                 if (sp [2]->type != STACK_OBJ)
4596                         return NULL;
4597
4598                 iargs [2] = sp [2];
4599                 iargs [1] = sp [1];
4600                 iargs [0] = sp [0];
4601
4602                 return mono_emit_method_call (cfg, helper, iargs, sp [0]);
4603         } else {
4604                 MonoInst *ins;
4605
4606                 if (mini_is_gsharedvt_variable_klass (klass)) {
4607                         MonoInst *addr;
4608
4609                         // FIXME-VT: OP_ICONST optimization
4610                         addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
4611                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
4612                         ins->opcode = OP_STOREV_MEMBASE;
4613                 } else if (sp [1]->opcode == OP_ICONST) {
4614                         int array_reg = sp [0]->dreg;
4615                         int index_reg = sp [1]->dreg;
4616                         int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
4617
4618                         if (SIZEOF_REGISTER == 8 && COMPILE_LLVM (cfg))
4619                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, index_reg, index_reg);
4620
4621                         if (safety_checks)
4622                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
4623                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset, sp [2]->dreg);
4624                 } else {
4625                         MonoInst *addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], safety_checks);
4626                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
4627                         if (generic_class_is_reference_type (cfg, klass))
4628                                 mini_emit_write_barrier (cfg, addr, sp [2]);
4629                 }
4630                 return ins;
4631         }
4632 }
4633
4634 static MonoInst*
4635 emit_array_unsafe_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
4636 {
4637         MonoClass *eklass;
4638         
4639         if (is_set)
4640                 eklass = mono_class_from_mono_type (fsig->params [2]);
4641         else
4642                 eklass = mono_class_from_mono_type (fsig->ret);
4643
4644         if (is_set) {
4645                 return emit_array_store (cfg, eklass, args, FALSE);
4646         } else {
4647                 MonoInst *ins, *addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
4648                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &eklass->byval_arg, addr->dreg, 0);
4649                 return ins;
4650         }
4651 }
4652
4653 static gboolean
4654 is_unsafe_mov_compatible (MonoCompile *cfg, MonoClass *param_klass, MonoClass *return_klass)
4655 {
4656         uint32_t align;
4657         int param_size, return_size;
4658
4659         param_klass = mono_class_from_mono_type (mini_get_underlying_type (&param_klass->byval_arg));
4660         return_klass = mono_class_from_mono_type (mini_get_underlying_type (&return_klass->byval_arg));
4661
4662         if (cfg->verbose_level > 3)
4663                 printf ("[UNSAFE-MOV-INTRISIC] %s <- %s\n", return_klass->name, param_klass->name);
4664
4665         //Don't allow mixing reference types with value types
4666         if (param_klass->valuetype != return_klass->valuetype) {
4667                 if (cfg->verbose_level > 3)
4668                         printf ("[UNSAFE-MOV-INTRISIC]\tone of the args is a valuetype and the other is not\n");
4669                 return FALSE;
4670         }
4671
4672         if (!param_klass->valuetype) {
4673                 if (cfg->verbose_level > 3)
4674                         printf ("[UNSAFE-MOV-INTRISIC]\targs are reference types\n");
4675                 return TRUE;
4676         }
4677
4678         //That are blitable
4679         if (param_klass->has_references || return_klass->has_references)
4680                 return FALSE;
4681
4682         /* Avoid mixing structs and primitive types/enums, they need to be handled differently in the JIT */
4683         if ((MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && !MONO_TYPE_ISSTRUCT (&return_klass->byval_arg)) ||
4684                 (!MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && MONO_TYPE_ISSTRUCT (&return_klass->byval_arg))) {
4685                         if (cfg->verbose_level > 3)
4686                                 printf ("[UNSAFE-MOV-INTRISIC]\tmixing structs and scalars\n");
4687                 return FALSE;
4688         }
4689
4690         if (param_klass->byval_arg.type == MONO_TYPE_R4 || param_klass->byval_arg.type == MONO_TYPE_R8 ||
4691                 return_klass->byval_arg.type == MONO_TYPE_R4 || return_klass->byval_arg.type == MONO_TYPE_R8) {
4692                 if (cfg->verbose_level > 3)
4693                         printf ("[UNSAFE-MOV-INTRISIC]\tfloat or double are not supported\n");
4694                 return FALSE;
4695         }
4696
4697         param_size = mono_class_value_size (param_klass, &align);
4698         return_size = mono_class_value_size (return_klass, &align);
4699
4700         //We can do it if sizes match
4701         if (param_size == return_size) {
4702                 if (cfg->verbose_level > 3)
4703                         printf ("[UNSAFE-MOV-INTRISIC]\tsame size\n");
4704                 return TRUE;
4705         }
4706
4707         //No simple way to handle struct if sizes don't match
4708         if (MONO_TYPE_ISSTRUCT (&param_klass->byval_arg)) {
4709                 if (cfg->verbose_level > 3)
4710                         printf ("[UNSAFE-MOV-INTRISIC]\tsize mismatch and type is a struct\n");
4711                 return FALSE;
4712         }
4713
4714         /*
4715          * Same reg size category.
4716          * A quick note on why we don't require widening here.
4717          * The intrinsic is "R Array.UnsafeMov<S,R> (S s)".
4718          *
4719          * Since the source value comes from a function argument, the JIT will already have
4720          * the value in a VREG and performed any widening needed before (say, when loading from a field).
4721          */
4722         if (param_size <= 4 && return_size <= 4) {
4723                 if (cfg->verbose_level > 3)
4724                         printf ("[UNSAFE-MOV-INTRISIC]\tsize mismatch but both are of the same reg class\n");
4725                 return TRUE;
4726         }
4727
4728         return FALSE;
4729 }
4730
4731 static MonoInst*
4732 emit_array_unsafe_mov (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args)
4733 {
4734         MonoClass *param_klass = mono_class_from_mono_type (fsig->params [0]);
4735         MonoClass *return_klass = mono_class_from_mono_type (fsig->ret);
4736
4737         if (mini_is_gsharedvt_variable_type (fsig->ret))
4738                 return NULL;
4739
4740         //Valuetypes that are semantically equivalent or numbers than can be widened to
4741         if (is_unsafe_mov_compatible (cfg, param_klass, return_klass))
4742                 return args [0];
4743
4744         //Arrays of valuetypes that are semantically equivalent
4745         if (param_klass->rank == 1 && return_klass->rank == 1 && is_unsafe_mov_compatible (cfg, param_klass->element_class, return_klass->element_class))
4746                 return args [0];
4747
4748         return NULL;
4749 }
4750
4751 static MonoInst*
4752 mini_emit_inst_for_ctor (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4753 {
4754 #ifdef MONO_ARCH_SIMD_INTRINSICS
4755         MonoInst *ins = NULL;
4756
4757         if (cfg->opt & MONO_OPT_SIMD) {
4758                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
4759                 if (ins)
4760                         return ins;
4761         }
4762 #endif
4763
4764         return mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
4765 }
4766
4767 MonoInst*
4768 mini_emit_memory_barrier (MonoCompile *cfg, int kind)
4769 {
4770         MonoInst *ins = NULL;
4771         MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
4772         MONO_ADD_INS (cfg->cbb, ins);
4773         ins->backend.memory_barrier_kind = kind;
4774
4775         return ins;
4776 }
4777
4778 static MonoInst*
4779 llvm_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4780 {
4781         MonoInst *ins = NULL;
4782         int opcode = 0;
4783
4784         /* The LLVM backend supports these intrinsics */
4785         if (cmethod->klass == mono_defaults.math_class) {
4786                 if (strcmp (cmethod->name, "Sin") == 0) {
4787                         opcode = OP_SIN;
4788                 } else if (strcmp (cmethod->name, "Cos") == 0) {
4789                         opcode = OP_COS;
4790                 } else if (strcmp (cmethod->name, "Sqrt") == 0) {
4791                         opcode = OP_SQRT;
4792                 } else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8) {
4793                         opcode = OP_ABS;
4794                 }
4795
4796                 if (opcode && fsig->param_count == 1) {
4797                         MONO_INST_NEW (cfg, ins, opcode);
4798                         ins->type = STACK_R8;
4799                         ins->dreg = mono_alloc_dreg (cfg, ins->type);
4800                         ins->sreg1 = args [0]->dreg;
4801                         MONO_ADD_INS (cfg->cbb, ins);
4802                 }
4803
4804                 opcode = 0;
4805                 if (cfg->opt & MONO_OPT_CMOV) {
4806                         if (strcmp (cmethod->name, "Min") == 0) {
4807                                 if (fsig->params [0]->type == MONO_TYPE_I4)
4808                                         opcode = OP_IMIN;
4809                                 if (fsig->params [0]->type == MONO_TYPE_U4)
4810                                         opcode = OP_IMIN_UN;
4811                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
4812                                         opcode = OP_LMIN;
4813                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
4814                                         opcode = OP_LMIN_UN;
4815                         } else if (strcmp (cmethod->name, "Max") == 0) {
4816                                 if (fsig->params [0]->type == MONO_TYPE_I4)
4817                                         opcode = OP_IMAX;
4818                                 if (fsig->params [0]->type == MONO_TYPE_U4)
4819                                         opcode = OP_IMAX_UN;
4820                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
4821                                         opcode = OP_LMAX;
4822                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
4823                                         opcode = OP_LMAX_UN;
4824                         }
4825                 }
4826
4827                 if (opcode && fsig->param_count == 2) {
4828                         MONO_INST_NEW (cfg, ins, opcode);
4829                         ins->type = fsig->params [0]->type == MONO_TYPE_I4 ? STACK_I4 : STACK_I8;
4830                         ins->dreg = mono_alloc_dreg (cfg, ins->type);
4831                         ins->sreg1 = args [0]->dreg;
4832                         ins->sreg2 = args [1]->dreg;
4833                         MONO_ADD_INS (cfg->cbb, ins);
4834                 }
4835         }
4836
4837         return ins;
4838 }
4839
4840 static MonoInst*
4841 mini_emit_inst_for_sharable_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4842 {
4843         if (cmethod->klass == mono_defaults.array_class) {
4844                 if (strcmp (cmethod->name, "UnsafeStore") == 0)
4845                         return emit_array_unsafe_access (cfg, fsig, args, TRUE);
4846                 else if (strcmp (cmethod->name, "UnsafeLoad") == 0)
4847                         return emit_array_unsafe_access (cfg, fsig, args, FALSE);
4848                 else if (strcmp (cmethod->name, "UnsafeMov") == 0)
4849                         return emit_array_unsafe_mov (cfg, fsig, args);
4850         }
4851
4852         return NULL;
4853 }
4854
4855
4856 static gboolean
4857 mono_type_is_native_blittable (MonoType *t)
4858 {
4859         if (MONO_TYPE_IS_REFERENCE (t))
4860                 return FALSE;
4861
4862         if (MONO_TYPE_IS_PRIMITIVE_SCALAR (t))
4863                 return TRUE;
4864
4865         MonoClass *klass = mono_class_from_mono_type (t);
4866
4867         //MonoClass::blitable depends on mono_class_setup_fields being done.
4868         mono_class_setup_fields (klass);
4869         if (!klass->blittable)
4870                 return FALSE;
4871
4872         // If the native marshal size is different we can't convert PtrToStructure to a type load
4873         if (mono_class_native_size (klass, NULL) != mono_class_value_size (klass, NULL))
4874                 return FALSE;
4875
4876         return TRUE;
4877 }
4878
4879
4880 static MonoInst*
4881 mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4882 {
4883         MonoInst *ins = NULL;
4884         MonoClass *runtime_helpers_class = mono_class_get_runtime_helpers_class ();
4885
4886         if (cmethod->klass == mono_defaults.string_class) {
4887                 if (strcmp (cmethod->name, "get_Chars") == 0 && fsig->param_count + fsig->hasthis == 2) {
4888                         int dreg = alloc_ireg (cfg);
4889                         int index_reg = alloc_preg (cfg);
4890                         int add_reg = alloc_preg (cfg);
4891
4892 #if SIZEOF_REGISTER == 8
4893                         if (COMPILE_LLVM (cfg)) {
4894                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, index_reg, args [1]->dreg);
4895                         } else {
4896                                 /* The array reg is 64 bits but the index reg is only 32 */
4897                                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index_reg, args [1]->dreg);
4898                         }
4899 #else
4900                         index_reg = args [1]->dreg;
4901 #endif  
4902                         MONO_EMIT_BOUNDS_CHECK (cfg, args [0]->dreg, MonoString, length, index_reg);
4903
4904 #if defined(TARGET_X86) || defined(TARGET_AMD64)
4905                         EMIT_NEW_X86_LEA (cfg, ins, args [0]->dreg, index_reg, 1, MONO_STRUCT_OFFSET (MonoString, chars));
4906                         add_reg = ins->dreg;
4907                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
4908                                                                    add_reg, 0);
4909 #else
4910                         int mult_reg = alloc_preg (cfg);
4911                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, index_reg, 1);
4912                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
4913                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
4914                                                                    add_reg, MONO_STRUCT_OFFSET (MonoString, chars));
4915 #endif
4916                         type_from_op (cfg, ins, NULL, NULL);
4917                         return ins;
4918                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count + fsig->hasthis == 1) {
4919                         int dreg = alloc_ireg (cfg);
4920                         /* Decompose later to allow more optimizations */
4921                         EMIT_NEW_UNALU (cfg, ins, OP_STRLEN, dreg, args [0]->dreg);
4922                         ins->type = STACK_I4;
4923                         ins->flags |= MONO_INST_FAULT;
4924                         cfg->cbb->has_array_access = TRUE;
4925                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
4926
4927                         return ins;
4928                 } else 
4929                         return NULL;
4930         } else if (cmethod->klass == mono_defaults.object_class) {
4931                 if (strcmp (cmethod->name, "GetType") == 0 && fsig->param_count + fsig->hasthis == 1) {
4932                         int dreg = alloc_ireg_ref (cfg);
4933                         int vt_reg = alloc_preg (cfg);
4934                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vt_reg, args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4935                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, vt_reg, MONO_STRUCT_OFFSET (MonoVTable, type));
4936                         type_from_op (cfg, ins, NULL, NULL);
4937
4938                         return ins;
4939                 } else if (!cfg->backend->emulate_mul_div && strcmp (cmethod->name, "InternalGetHashCode") == 0 && fsig->param_count == 1 && !mono_gc_is_moving ()) {
4940                         int dreg = alloc_ireg (cfg);
4941                         int t1 = alloc_ireg (cfg);
4942         
4943                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, t1, args [0]->dreg, 3);
4944                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_MUL_IMM, dreg, t1, 2654435761u);
4945                         ins->type = STACK_I4;
4946
4947                         return ins;
4948                 } else if (strcmp (cmethod->name, ".ctor") == 0 && fsig->param_count == 0) {
4949                         MONO_INST_NEW (cfg, ins, OP_NOP);
4950                         MONO_ADD_INS (cfg->cbb, ins);
4951                         return ins;
4952                 } else
4953                         return NULL;
4954         } else if (cmethod->klass == mono_defaults.array_class) {
4955                 if (strcmp (cmethod->name, "GetGenericValueImpl") == 0 && fsig->param_count + fsig->hasthis == 3 && !cfg->gsharedvt)
4956                         return emit_array_generic_access (cfg, fsig, args, FALSE);
4957                 else if (strcmp (cmethod->name, "SetGenericValueImpl") == 0 && fsig->param_count + fsig->hasthis == 3 && !cfg->gsharedvt)
4958                         return emit_array_generic_access (cfg, fsig, args, TRUE);
4959
4960 #ifndef MONO_BIG_ARRAYS
4961                 /*
4962                  * This is an inline version of GetLength/GetLowerBound(0) used frequently in
4963                  * Array methods.
4964                  */
4965                 else if (((strcmp (cmethod->name, "GetLength") == 0 && fsig->param_count + fsig->hasthis == 2) ||
4966                          (strcmp (cmethod->name, "GetLowerBound") == 0 && fsig->param_count + fsig->hasthis == 2)) &&
4967                          args [1]->opcode == OP_ICONST && args [1]->inst_c0 == 0) {
4968                         int dreg = alloc_ireg (cfg);
4969                         int bounds_reg = alloc_ireg_mp (cfg);
4970                         MonoBasicBlock *end_bb, *szarray_bb;
4971                         gboolean get_length = strcmp (cmethod->name, "GetLength") == 0;
4972
4973                         NEW_BBLOCK (cfg, end_bb);
4974                         NEW_BBLOCK (cfg, szarray_bb);
4975
4976                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOAD_MEMBASE, bounds_reg,
4977                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
4978                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
4979                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, szarray_bb);
4980                         /* Non-szarray case */
4981                         if (get_length)
4982                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
4983                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
4984                         else
4985                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
4986                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
4987                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4988                         MONO_START_BB (cfg, szarray_bb);
4989                         /* Szarray case */
4990                         if (get_length)
4991                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
4992                                                                            args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
4993                         else
4994                                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4995                         MONO_START_BB (cfg, end_bb);
4996
4997                         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, dreg, dreg);
4998                         ins->type = STACK_I4;
4999                         
5000                         return ins;
5001                 }
5002 #endif
5003
5004                 if (cmethod->name [0] != 'g')
5005                         return NULL;
5006
5007                 if (strcmp (cmethod->name, "get_Rank") == 0 && fsig->param_count + fsig->hasthis == 1) {
5008                         int dreg = alloc_ireg (cfg);
5009                         int vtable_reg = alloc_preg (cfg);
5010                         MONO_EMIT_NEW_LOAD_MEMBASE_OP_FAULT (cfg, OP_LOAD_MEMBASE, vtable_reg, 
5011                                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
5012                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU1_MEMBASE, dreg,
5013                                                                    vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
5014                         type_from_op (cfg, ins, NULL, NULL);
5015
5016                         return ins;
5017                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count + fsig->hasthis == 1) {
5018                         int dreg = alloc_ireg (cfg);
5019
5020                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOADI4_MEMBASE, dreg, 
5021                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
5022                         type_from_op (cfg, ins, NULL, NULL);
5023
5024                         return ins;
5025                 } else
5026                         return NULL;
5027         } else if (cmethod->klass == runtime_helpers_class) {
5028                 if (strcmp (cmethod->name, "get_OffsetToStringData") == 0 && fsig->param_count == 0) {
5029                         EMIT_NEW_ICONST (cfg, ins, MONO_STRUCT_OFFSET (MonoString, chars));
5030                         return ins;
5031                 } else if (strcmp (cmethod->name, "IsReferenceOrContainsReferences") == 0 && fsig->param_count == 0) {
5032                         MonoGenericContext *ctx = mono_method_get_context (cmethod);
5033                         g_assert (ctx);
5034                         g_assert (ctx->method_inst);
5035                         g_assert (ctx->method_inst->type_argc == 1);
5036                         MonoType *arg_type = ctx->method_inst->type_argv [0];
5037                         MonoType *t;
5038                         MonoClass *klass;
5039
5040                         ins = NULL;
5041
5042                         /* Resolve the argument class as possible so we can handle common cases fast */
5043                         t = mini_get_underlying_type (arg_type);
5044                         klass = mono_class_from_mono_type (t);
5045                         mono_class_init (klass);
5046                         if (MONO_TYPE_IS_REFERENCE (t))
5047                                 EMIT_NEW_ICONST (cfg, ins, 1);
5048                         else if (MONO_TYPE_IS_PRIMITIVE (t))
5049                                 EMIT_NEW_ICONST (cfg, ins, 0);
5050                         else if (cfg->gshared && (t->type == MONO_TYPE_VAR || t->type == MONO_TYPE_MVAR) && !mini_type_var_is_vt (t))
5051                                 EMIT_NEW_ICONST (cfg, ins, 1);
5052                         else if (!cfg->gshared || !mini_class_check_context_used (cfg, klass))
5053                                 EMIT_NEW_ICONST (cfg, ins, klass->has_references ? 1 : 0);
5054                         else {
5055                                 g_assert (cfg->gshared);
5056
5057                                 /* Have to use the original argument class here */
5058                                 MonoClass *arg_class = mono_class_from_mono_type (arg_type);
5059                                 int context_used = mini_class_check_context_used (cfg, arg_class);
5060
5061                                 /* This returns 1 or 2 */
5062                                 MonoInst *info = mini_emit_get_rgctx_klass (cfg, context_used, arg_class, MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS);
5063                                 int dreg = alloc_ireg (cfg);
5064                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_ISUB_IMM, dreg, info->dreg, 1);
5065                         }
5066
5067                         return ins;
5068                 } else
5069                         return NULL;
5070         } else if (cmethod->klass == mono_defaults.monitor_class) {
5071                 gboolean is_enter = FALSE;
5072                 gboolean is_v4 = FALSE;
5073
5074                 if (!strcmp (cmethod->name, "Enter") && fsig->param_count == 2 && fsig->params [1]->byref) {
5075                         is_enter = TRUE;
5076                         is_v4 = TRUE;
5077                 }
5078                 if (!strcmp (cmethod->name, "Enter") && fsig->param_count == 1)
5079                         is_enter = TRUE;
5080
5081                 if (is_enter) {
5082                         /*
5083                          * To make async stack traces work, icalls which can block should have a wrapper.
5084                          * For Monitor.Enter, emit two calls: a fastpath which doesn't have a wrapper, and a slowpath, which does.
5085                          */
5086                         MonoBasicBlock *end_bb;
5087
5088                         NEW_BBLOCK (cfg, end_bb);
5089
5090                         ins = mono_emit_jit_icall (cfg, is_v4 ? (gpointer)mono_monitor_enter_v4_fast : (gpointer)mono_monitor_enter_fast, args);
5091                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, ins->dreg, 0);
5092                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, end_bb);
5093                         ins = mono_emit_jit_icall (cfg, is_v4 ? (gpointer)mono_monitor_enter_v4_internal : (gpointer)mono_monitor_enter_internal, args);
5094                         MONO_START_BB (cfg, end_bb);
5095                         return ins;
5096                 }
5097         } else if (cmethod->klass == mono_defaults.thread_class) {
5098                 if (strcmp (cmethod->name, "SpinWait_nop") == 0 && fsig->param_count == 0) {
5099                         MONO_INST_NEW (cfg, ins, OP_RELAXED_NOP);
5100                         MONO_ADD_INS (cfg->cbb, ins);
5101                         return ins;
5102                 } else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0) {
5103                         return mini_emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
5104                 } else if (!strcmp (cmethod->name, "VolatileRead") && fsig->param_count == 1) {
5105                         guint32 opcode = 0;
5106                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
5107
5108                         if (fsig->params [0]->type == MONO_TYPE_I1)
5109                                 opcode = OP_LOADI1_MEMBASE;
5110                         else if (fsig->params [0]->type == MONO_TYPE_U1)
5111                                 opcode = OP_LOADU1_MEMBASE;
5112                         else if (fsig->params [0]->type == MONO_TYPE_I2)
5113                                 opcode = OP_LOADI2_MEMBASE;
5114                         else if (fsig->params [0]->type == MONO_TYPE_U2)
5115                                 opcode = OP_LOADU2_MEMBASE;
5116                         else if (fsig->params [0]->type == MONO_TYPE_I4)
5117                                 opcode = OP_LOADI4_MEMBASE;
5118                         else if (fsig->params [0]->type == MONO_TYPE_U4)
5119                                 opcode = OP_LOADU4_MEMBASE;
5120                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
5121                                 opcode = OP_LOADI8_MEMBASE;
5122                         else if (fsig->params [0]->type == MONO_TYPE_R4)
5123                                 opcode = OP_LOADR4_MEMBASE;
5124                         else if (fsig->params [0]->type == MONO_TYPE_R8)
5125                                 opcode = OP_LOADR8_MEMBASE;
5126                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
5127                                 opcode = OP_LOAD_MEMBASE;
5128
5129                         if (opcode) {
5130                                 MONO_INST_NEW (cfg, ins, opcode);
5131                                 ins->inst_basereg = args [0]->dreg;
5132                                 ins->inst_offset = 0;
5133                                 MONO_ADD_INS (cfg->cbb, ins);
5134
5135                                 switch (fsig->params [0]->type) {
5136                                 case MONO_TYPE_I1:
5137                                 case MONO_TYPE_U1:
5138                                 case MONO_TYPE_I2:
5139                                 case MONO_TYPE_U2:
5140                                 case MONO_TYPE_I4:
5141                                 case MONO_TYPE_U4:
5142                                         ins->dreg = mono_alloc_ireg (cfg);
5143                                         ins->type = STACK_I4;
5144                                         break;
5145                                 case MONO_TYPE_I8:
5146                                 case MONO_TYPE_U8:
5147                                         ins->dreg = mono_alloc_lreg (cfg);
5148                                         ins->type = STACK_I8;
5149                                         break;
5150                                 case MONO_TYPE_I:
5151                                 case MONO_TYPE_U:
5152                                         ins->dreg = mono_alloc_ireg (cfg);
5153 #if SIZEOF_REGISTER == 8
5154                                         ins->type = STACK_I8;
5155 #else
5156                                         ins->type = STACK_I4;
5157 #endif
5158                                         break;
5159                                 case MONO_TYPE_R4:
5160                                 case MONO_TYPE_R8:
5161                                         ins->dreg = mono_alloc_freg (cfg);
5162                                         ins->type = STACK_R8;
5163                                         break;
5164                                 default:
5165                                         g_assert (mini_type_is_reference (fsig->params [0]));
5166                                         ins->dreg = mono_alloc_ireg_ref (cfg);
5167                                         ins->type = STACK_OBJ;
5168                                         break;
5169                                 }
5170
5171                                 if (opcode == OP_LOADI8_MEMBASE)
5172                                         ins = mono_decompose_opcode (cfg, ins);
5173
5174                                 mini_emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
5175
5176                                 return ins;
5177                         }
5178                 } else if (!strcmp (cmethod->name, "VolatileWrite") && fsig->param_count == 2) {
5179                         guint32 opcode = 0;
5180                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
5181
5182                         if (fsig->params [0]->type == MONO_TYPE_I1 || fsig->params [0]->type == MONO_TYPE_U1)
5183                                 opcode = OP_STOREI1_MEMBASE_REG;
5184                         else if (fsig->params [0]->type == MONO_TYPE_I2 || fsig->params [0]->type == MONO_TYPE_U2)
5185                                 opcode = OP_STOREI2_MEMBASE_REG;
5186                         else if (fsig->params [0]->type == MONO_TYPE_I4 || fsig->params [0]->type == MONO_TYPE_U4)
5187                                 opcode = OP_STOREI4_MEMBASE_REG;
5188                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
5189                                 opcode = OP_STOREI8_MEMBASE_REG;
5190                         else if (fsig->params [0]->type == MONO_TYPE_R4)
5191                                 opcode = OP_STORER4_MEMBASE_REG;
5192                         else if (fsig->params [0]->type == MONO_TYPE_R8)
5193                                 opcode = OP_STORER8_MEMBASE_REG;
5194                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
5195                                 opcode = OP_STORE_MEMBASE_REG;
5196
5197                         if (opcode) {
5198                                 mini_emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
5199
5200                                 MONO_INST_NEW (cfg, ins, opcode);
5201                                 ins->sreg1 = args [1]->dreg;
5202                                 ins->inst_destbasereg = args [0]->dreg;
5203                                 ins->inst_offset = 0;
5204                                 MONO_ADD_INS (cfg->cbb, ins);
5205
5206                                 if (opcode == OP_STOREI8_MEMBASE_REG)
5207                                         ins = mono_decompose_opcode (cfg, ins);
5208
5209                                 return ins;
5210                         }
5211                 }
5212         } else if (cmethod->klass->image == mono_defaults.corlib &&
5213                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
5214                            (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
5215                 ins = NULL;
5216
5217 #if SIZEOF_REGISTER == 8
5218                 if (!cfg->llvm_only && strcmp (cmethod->name, "Read") == 0 && fsig->param_count == 1 && (fsig->params [0]->type == MONO_TYPE_I8)) {
5219                         if (!cfg->llvm_only && mono_arch_opcode_supported (OP_ATOMIC_LOAD_I8)) {
5220                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_LOAD_I8);
5221                                 ins->dreg = mono_alloc_preg (cfg);
5222                                 ins->sreg1 = args [0]->dreg;
5223                                 ins->type = STACK_I8;
5224                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_SEQ;
5225                                 MONO_ADD_INS (cfg->cbb, ins);
5226                         } else {
5227                                 MonoInst *load_ins;
5228
5229                                 mini_emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
5230
5231                                 /* 64 bit reads are already atomic */
5232                                 MONO_INST_NEW (cfg, load_ins, OP_LOADI8_MEMBASE);
5233                                 load_ins->dreg = mono_alloc_preg (cfg);
5234                                 load_ins->inst_basereg = args [0]->dreg;
5235                                 load_ins->inst_offset = 0;
5236                                 load_ins->type = STACK_I8;
5237                                 MONO_ADD_INS (cfg->cbb, load_ins);
5238
5239                                 mini_emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
5240
5241                                 ins = load_ins;
5242                         }
5243                 }
5244 #endif
5245
5246                 if (strcmp (cmethod->name, "Increment") == 0 && fsig->param_count == 1) {
5247                         MonoInst *ins_iconst;
5248                         guint32 opcode = 0;
5249
5250                         if (fsig->params [0]->type == MONO_TYPE_I4) {
5251                                 opcode = OP_ATOMIC_ADD_I4;
5252                                 cfg->has_atomic_add_i4 = TRUE;
5253                         }
5254 #if SIZEOF_REGISTER == 8
5255                         else if (fsig->params [0]->type == MONO_TYPE_I8)
5256                                 opcode = OP_ATOMIC_ADD_I8;
5257 #endif
5258                         if (opcode) {
5259                                 if (!mono_arch_opcode_supported (opcode))
5260                                         return NULL;
5261                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
5262                                 ins_iconst->inst_c0 = 1;
5263                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
5264                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
5265
5266                                 MONO_INST_NEW (cfg, ins, opcode);
5267                                 ins->dreg = mono_alloc_ireg (cfg);
5268                                 ins->inst_basereg = args [0]->dreg;
5269                                 ins->inst_offset = 0;
5270                                 ins->sreg2 = ins_iconst->dreg;
5271                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
5272                                 MONO_ADD_INS (cfg->cbb, ins);
5273                         }
5274                 } else if (strcmp (cmethod->name, "Decrement") == 0 && fsig->param_count == 1) {
5275                         MonoInst *ins_iconst;
5276                         guint32 opcode = 0;
5277
5278                         if (fsig->params [0]->type == MONO_TYPE_I4) {
5279                                 opcode = OP_ATOMIC_ADD_I4;
5280                                 cfg->has_atomic_add_i4 = TRUE;
5281                         }
5282 #if SIZEOF_REGISTER == 8
5283                         else if (fsig->params [0]->type == MONO_TYPE_I8)
5284                                 opcode = OP_ATOMIC_ADD_I8;
5285 #endif
5286                         if (opcode) {
5287                                 if (!mono_arch_opcode_supported (opcode))
5288                                         return NULL;
5289                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
5290                                 ins_iconst->inst_c0 = -1;
5291                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
5292                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
5293
5294                                 MONO_INST_NEW (cfg, ins, opcode);
5295                                 ins->dreg = mono_alloc_ireg (cfg);
5296                                 ins->inst_basereg = args [0]->dreg;
5297                                 ins->inst_offset = 0;
5298                                 ins->sreg2 = ins_iconst->dreg;
5299                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
5300                                 MONO_ADD_INS (cfg->cbb, ins);
5301                         }
5302                 } else if (strcmp (cmethod->name, "Add") == 0 && fsig->param_count == 2) {
5303                         guint32 opcode = 0;
5304
5305                         if (fsig->params [0]->type == MONO_TYPE_I4) {
5306                                 opcode = OP_ATOMIC_ADD_I4;
5307                                 cfg->has_atomic_add_i4 = TRUE;
5308                         }
5309 #if SIZEOF_REGISTER == 8
5310                         else if (fsig->params [0]->type == MONO_TYPE_I8)
5311                                 opcode = OP_ATOMIC_ADD_I8;
5312 #endif
5313                         if (opcode) {
5314                                 if (!mono_arch_opcode_supported (opcode))
5315                                         return NULL;
5316                                 MONO_INST_NEW (cfg, ins, opcode);
5317                                 ins->dreg = mono_alloc_ireg (cfg);
5318                                 ins->inst_basereg = args [0]->dreg;
5319                                 ins->inst_offset = 0;
5320                                 ins->sreg2 = args [1]->dreg;
5321                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
5322                                 MONO_ADD_INS (cfg->cbb, ins);
5323                         }
5324                 }
5325                 else if (strcmp (cmethod->name, "Exchange") == 0 && fsig->param_count == 2) {
5326                         MonoInst *f2i = NULL, *i2f;
5327                         guint32 opcode, f2i_opcode, i2f_opcode;
5328                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
5329                         gboolean is_float = fsig->params [0]->type == MONO_TYPE_R4 || fsig->params [0]->type == MONO_TYPE_R8;
5330
5331                         if (fsig->params [0]->type == MONO_TYPE_I4 ||
5332                             fsig->params [0]->type == MONO_TYPE_R4) {
5333                                 opcode = OP_ATOMIC_EXCHANGE_I4;
5334                                 f2i_opcode = OP_MOVE_F_TO_I4;
5335                                 i2f_opcode = OP_MOVE_I4_TO_F;
5336                                 cfg->has_atomic_exchange_i4 = TRUE;
5337                         }
5338 #if SIZEOF_REGISTER == 8
5339                         else if (is_ref ||
5340                                  fsig->params [0]->type == MONO_TYPE_I8 ||
5341                                  fsig->params [0]->type == MONO_TYPE_R8 ||
5342                                  fsig->params [0]->type == MONO_TYPE_I) {
5343                                 opcode = OP_ATOMIC_EXCHANGE_I8;
5344                                 f2i_opcode = OP_MOVE_F_TO_I8;
5345                                 i2f_opcode = OP_MOVE_I8_TO_F;
5346                         }
5347 #else
5348                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I) {
5349                                 opcode = OP_ATOMIC_EXCHANGE_I4;
5350                                 cfg->has_atomic_exchange_i4 = TRUE;
5351                         }
5352 #endif
5353                         else
5354                                 return NULL;
5355
5356                         if (!mono_arch_opcode_supported (opcode))
5357                                 return NULL;
5358
5359                         if (is_float) {
5360                                 /* TODO: Decompose these opcodes instead of bailing here. */
5361                                 if (COMPILE_SOFT_FLOAT (cfg))
5362                                         return NULL;
5363
5364                                 MONO_INST_NEW (cfg, f2i, f2i_opcode);
5365                                 f2i->dreg = mono_alloc_ireg (cfg);
5366                                 f2i->sreg1 = args [1]->dreg;
5367                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
5368                                         f2i->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
5369                                 MONO_ADD_INS (cfg->cbb, f2i);
5370                         }
5371
5372                         MONO_INST_NEW (cfg, ins, opcode);
5373                         ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : mono_alloc_ireg (cfg);
5374                         ins->inst_basereg = args [0]->dreg;
5375                         ins->inst_offset = 0;
5376                         ins->sreg2 = is_float ? f2i->dreg : args [1]->dreg;
5377                         MONO_ADD_INS (cfg->cbb, ins);
5378
5379                         switch (fsig->params [0]->type) {
5380                         case MONO_TYPE_I4:
5381                                 ins->type = STACK_I4;
5382                                 break;
5383                         case MONO_TYPE_I8:
5384                                 ins->type = STACK_I8;
5385                                 break;
5386                         case MONO_TYPE_I:
5387 #if SIZEOF_REGISTER == 8
5388                                 ins->type = STACK_I8;
5389 #else
5390                                 ins->type = STACK_I4;
5391 #endif
5392                                 break;
5393                         case MONO_TYPE_R4:
5394                         case MONO_TYPE_R8:
5395                                 ins->type = STACK_R8;
5396                                 break;
5397                         default:
5398                                 g_assert (mini_type_is_reference (fsig->params [0]));
5399                                 ins->type = STACK_OBJ;
5400                                 break;
5401                         }
5402
5403                         if (is_float) {
5404                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
5405                                 i2f->dreg = mono_alloc_freg (cfg);
5406                                 i2f->sreg1 = ins->dreg;
5407                                 i2f->type = STACK_R8;
5408                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
5409                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
5410                                 MONO_ADD_INS (cfg->cbb, i2f);
5411
5412                                 ins = i2f;
5413                         }
5414
5415                         if (cfg->gen_write_barriers && is_ref)
5416                                 mini_emit_write_barrier (cfg, args [0], args [1]);
5417                 }
5418                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 3) {
5419                         MonoInst *f2i_new = NULL, *f2i_cmp = NULL, *i2f;
5420                         guint32 opcode, f2i_opcode, i2f_opcode;
5421                         gboolean is_ref = mini_type_is_reference (fsig->params [1]);
5422                         gboolean is_float = fsig->params [1]->type == MONO_TYPE_R4 || fsig->params [1]->type == MONO_TYPE_R8;
5423
5424                         if (fsig->params [1]->type == MONO_TYPE_I4 ||
5425                             fsig->params [1]->type == MONO_TYPE_R4) {
5426                                 opcode = OP_ATOMIC_CAS_I4;
5427                                 f2i_opcode = OP_MOVE_F_TO_I4;
5428                                 i2f_opcode = OP_MOVE_I4_TO_F;
5429                                 cfg->has_atomic_cas_i4 = TRUE;
5430                         }
5431 #if SIZEOF_REGISTER == 8
5432                         else if (is_ref ||
5433                                  fsig->params [1]->type == MONO_TYPE_I8 ||
5434                                  fsig->params [1]->type == MONO_TYPE_R8 ||
5435                                  fsig->params [1]->type == MONO_TYPE_I) {
5436                                 opcode = OP_ATOMIC_CAS_I8;
5437                                 f2i_opcode = OP_MOVE_F_TO_I8;
5438                                 i2f_opcode = OP_MOVE_I8_TO_F;
5439                         }
5440 #else
5441                         else if (is_ref || fsig->params [1]->type == MONO_TYPE_I) {
5442                                 opcode = OP_ATOMIC_CAS_I4;
5443                                 cfg->has_atomic_cas_i4 = TRUE;
5444                         }
5445 #endif
5446                         else
5447                                 return NULL;
5448
5449                         if (!mono_arch_opcode_supported (opcode))
5450                                 return NULL;
5451
5452                         if (is_float) {
5453                                 /* TODO: Decompose these opcodes instead of bailing here. */
5454                                 if (COMPILE_SOFT_FLOAT (cfg))
5455                                         return NULL;
5456
5457                                 MONO_INST_NEW (cfg, f2i_new, f2i_opcode);
5458                                 f2i_new->dreg = mono_alloc_ireg (cfg);
5459                                 f2i_new->sreg1 = args [1]->dreg;
5460                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
5461                                         f2i_new->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
5462                                 MONO_ADD_INS (cfg->cbb, f2i_new);
5463
5464                                 MONO_INST_NEW (cfg, f2i_cmp, f2i_opcode);
5465                                 f2i_cmp->dreg = mono_alloc_ireg (cfg);
5466                                 f2i_cmp->sreg1 = args [2]->dreg;
5467                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
5468                                         f2i_cmp->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
5469                                 MONO_ADD_INS (cfg->cbb, f2i_cmp);
5470                         }
5471
5472                         MONO_INST_NEW (cfg, ins, opcode);
5473                         ins->dreg = is_ref ? alloc_ireg_ref (cfg) : alloc_ireg (cfg);
5474                         ins->sreg1 = args [0]->dreg;
5475                         ins->sreg2 = is_float ? f2i_new->dreg : args [1]->dreg;
5476                         ins->sreg3 = is_float ? f2i_cmp->dreg : args [2]->dreg;
5477                         MONO_ADD_INS (cfg->cbb, ins);
5478
5479                         switch (fsig->params [1]->type) {
5480                         case MONO_TYPE_I4:
5481                                 ins->type = STACK_I4;
5482                                 break;
5483                         case MONO_TYPE_I8:
5484                                 ins->type = STACK_I8;
5485                                 break;
5486                         case MONO_TYPE_I:
5487 #if SIZEOF_REGISTER == 8
5488                                 ins->type = STACK_I8;
5489 #else
5490                                 ins->type = STACK_I4;
5491 #endif
5492                                 break;
5493                         case MONO_TYPE_R4:
5494                                 ins->type = cfg->r4_stack_type;
5495                                 break;
5496                         case MONO_TYPE_R8:
5497                                 ins->type = STACK_R8;
5498                                 break;
5499                         default:
5500                                 g_assert (mini_type_is_reference (fsig->params [1]));
5501                                 ins->type = STACK_OBJ;
5502                                 break;
5503                         }
5504
5505                         if (is_float) {
5506                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
5507                                 i2f->dreg = mono_alloc_freg (cfg);
5508                                 i2f->sreg1 = ins->dreg;
5509                                 i2f->type = STACK_R8;
5510                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
5511                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
5512                                 MONO_ADD_INS (cfg->cbb, i2f);
5513
5514                                 ins = i2f;
5515                         }
5516
5517                         if (cfg->gen_write_barriers && is_ref)
5518                                 mini_emit_write_barrier (cfg, args [0], args [1]);
5519                 }
5520                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 4 &&
5521                          fsig->params [1]->type == MONO_TYPE_I4) {
5522                         MonoInst *cmp, *ceq;
5523
5524                         if (!mono_arch_opcode_supported (OP_ATOMIC_CAS_I4))
5525                                 return NULL;
5526
5527                         /* int32 r = CAS (location, value, comparand); */
5528                         MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I4);
5529                         ins->dreg = alloc_ireg (cfg);
5530                         ins->sreg1 = args [0]->dreg;
5531                         ins->sreg2 = args [1]->dreg;
5532                         ins->sreg3 = args [2]->dreg;
5533                         ins->type = STACK_I4;
5534                         MONO_ADD_INS (cfg->cbb, ins);
5535
5536                         /* bool result = r == comparand; */
5537                         MONO_INST_NEW (cfg, cmp, OP_ICOMPARE);
5538                         cmp->sreg1 = ins->dreg;
5539                         cmp->sreg2 = args [2]->dreg;
5540                         cmp->type = STACK_I4;
5541                         MONO_ADD_INS (cfg->cbb, cmp);
5542
5543                         MONO_INST_NEW (cfg, ceq, OP_ICEQ);
5544                         ceq->dreg = alloc_ireg (cfg);
5545                         ceq->type = STACK_I4;
5546                         MONO_ADD_INS (cfg->cbb, ceq);
5547
5548                         /* *success = result; */
5549                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, args [3]->dreg, 0, ceq->dreg);
5550
5551                         cfg->has_atomic_cas_i4 = TRUE;
5552                 }
5553                 else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0)
5554                         ins = mini_emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
5555
5556                 if (ins)
5557                         return ins;
5558         } else if (cmethod->klass->image == mono_defaults.corlib &&
5559                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
5560                            (strcmp (cmethod->klass->name, "Volatile") == 0)) {
5561                 ins = NULL;
5562
5563                 if (!cfg->llvm_only && !strcmp (cmethod->name, "Read") && fsig->param_count == 1) {
5564                         guint32 opcode = 0;
5565                         MonoType *t = fsig->params [0];
5566                         gboolean is_ref;
5567                         gboolean is_float = t->type == MONO_TYPE_R4 || t->type == MONO_TYPE_R8;
5568
5569                         g_assert (t->byref);
5570                         /* t is a byref type, so the reference check is more complicated */
5571                         is_ref = mini_type_is_reference (&mono_class_from_mono_type (t)->byval_arg);
5572                         if (t->type == MONO_TYPE_I1)
5573                                 opcode = OP_ATOMIC_LOAD_I1;
5574                         else if (t->type == MONO_TYPE_U1 || t->type == MONO_TYPE_BOOLEAN)
5575                                 opcode = OP_ATOMIC_LOAD_U1;
5576                         else if (t->type == MONO_TYPE_I2)
5577                                 opcode = OP_ATOMIC_LOAD_I2;
5578                         else if (t->type == MONO_TYPE_U2)
5579                                 opcode = OP_ATOMIC_LOAD_U2;
5580                         else if (t->type == MONO_TYPE_I4)
5581                                 opcode = OP_ATOMIC_LOAD_I4;
5582                         else if (t->type == MONO_TYPE_U4)
5583                                 opcode = OP_ATOMIC_LOAD_U4;
5584                         else if (t->type == MONO_TYPE_R4)
5585                                 opcode = OP_ATOMIC_LOAD_R4;
5586                         else if (t->type == MONO_TYPE_R8)
5587                                 opcode = OP_ATOMIC_LOAD_R8;
5588 #if SIZEOF_REGISTER == 8
5589                         else if (t->type == MONO_TYPE_I8 || t->type == MONO_TYPE_I)
5590                                 opcode = OP_ATOMIC_LOAD_I8;
5591                         else if (is_ref || t->type == MONO_TYPE_U8 || t->type == MONO_TYPE_U)
5592                                 opcode = OP_ATOMIC_LOAD_U8;
5593 #else
5594                         else if (t->type == MONO_TYPE_I)
5595                                 opcode = OP_ATOMIC_LOAD_I4;
5596                         else if (is_ref || t->type == MONO_TYPE_U)
5597                                 opcode = OP_ATOMIC_LOAD_U4;
5598 #endif
5599
5600                         if (opcode) {
5601                                 if (!mono_arch_opcode_supported (opcode))
5602                                         return NULL;
5603
5604                                 MONO_INST_NEW (cfg, ins, opcode);
5605                                 ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : (is_float ? mono_alloc_freg (cfg) : mono_alloc_ireg (cfg));
5606                                 ins->sreg1 = args [0]->dreg;
5607                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_ACQ;
5608                                 MONO_ADD_INS (cfg->cbb, ins);
5609
5610                                 switch (t->type) {
5611                                 case MONO_TYPE_BOOLEAN:
5612                                 case MONO_TYPE_I1:
5613                                 case MONO_TYPE_U1:
5614                                 case MONO_TYPE_I2:
5615                                 case MONO_TYPE_U2:
5616                                 case MONO_TYPE_I4:
5617                                 case MONO_TYPE_U4:
5618                                         ins->type = STACK_I4;
5619                                         break;
5620                                 case MONO_TYPE_I8:
5621                                 case MONO_TYPE_U8:
5622                                         ins->type = STACK_I8;
5623                                         break;
5624                                 case MONO_TYPE_I:
5625                                 case MONO_TYPE_U:
5626 #if SIZEOF_REGISTER == 8
5627                                         ins->type = STACK_I8;
5628 #else
5629                                         ins->type = STACK_I4;
5630 #endif
5631                                         break;
5632                                 case MONO_TYPE_R4:
5633                                         ins->type = cfg->r4_stack_type;
5634                                         break;
5635                                 case MONO_TYPE_R8:
5636                                         ins->type = STACK_R8;
5637                                         break;
5638                                 default:
5639                                         g_assert (is_ref);
5640                                         ins->type = STACK_OBJ;
5641                                         break;
5642                                 }
5643                         }
5644                 }
5645
5646                 if (!cfg->llvm_only && !strcmp (cmethod->name, "Write") && fsig->param_count == 2) {
5647                         guint32 opcode = 0;
5648                         MonoType *t = fsig->params [0];
5649                         gboolean is_ref;
5650
5651                         g_assert (t->byref);
5652                         is_ref = mini_type_is_reference (&mono_class_from_mono_type (t)->byval_arg);
5653                         if (t->type == MONO_TYPE_I1)
5654                                 opcode = OP_ATOMIC_STORE_I1;
5655                         else if (t->type == MONO_TYPE_U1 || t->type == MONO_TYPE_BOOLEAN)
5656                                 opcode = OP_ATOMIC_STORE_U1;
5657                         else if (t->type == MONO_TYPE_I2)
5658                                 opcode = OP_ATOMIC_STORE_I2;
5659                         else if (t->type == MONO_TYPE_U2)
5660                                 opcode = OP_ATOMIC_STORE_U2;
5661                         else if (t->type == MONO_TYPE_I4)
5662                                 opcode = OP_ATOMIC_STORE_I4;
5663                         else if (t->type == MONO_TYPE_U4)
5664                                 opcode = OP_ATOMIC_STORE_U4;
5665                         else if (t->type == MONO_TYPE_R4)
5666                                 opcode = OP_ATOMIC_STORE_R4;
5667                         else if (t->type == MONO_TYPE_R8)
5668                                 opcode = OP_ATOMIC_STORE_R8;
5669 #if SIZEOF_REGISTER == 8
5670                         else if (t->type == MONO_TYPE_I8 || t->type == MONO_TYPE_I)
5671                                 opcode = OP_ATOMIC_STORE_I8;
5672                         else if (is_ref || t->type == MONO_TYPE_U8 || t->type == MONO_TYPE_U)
5673                                 opcode = OP_ATOMIC_STORE_U8;
5674 #else
5675                         else if (t->type == MONO_TYPE_I)
5676                                 opcode = OP_ATOMIC_STORE_I4;
5677                         else if (is_ref || t->type == MONO_TYPE_U)
5678                                 opcode = OP_ATOMIC_STORE_U4;
5679 #endif
5680
5681                         if (opcode) {
5682                                 if (!mono_arch_opcode_supported (opcode))
5683                                         return NULL;
5684
5685                                 MONO_INST_NEW (cfg, ins, opcode);
5686                                 ins->dreg = args [0]->dreg;
5687                                 ins->sreg1 = args [1]->dreg;
5688                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_REL;
5689                                 MONO_ADD_INS (cfg->cbb, ins);
5690
5691                                 if (cfg->gen_write_barriers && is_ref)
5692                                         mini_emit_write_barrier (cfg, args [0], args [1]);
5693                         }
5694                 }
5695
5696                 if (ins)
5697                         return ins;
5698         } else if (cmethod->klass->image == mono_defaults.corlib &&
5699                            (strcmp (cmethod->klass->name_space, "System.Diagnostics") == 0) &&
5700                            (strcmp (cmethod->klass->name, "Debugger") == 0)) {
5701                 if (!strcmp (cmethod->name, "Break") && fsig->param_count == 0) {
5702                         if (mini_should_insert_breakpoint (cfg->method)) {
5703                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
5704                         } else {
5705                                 MONO_INST_NEW (cfg, ins, OP_NOP);
5706                                 MONO_ADD_INS (cfg->cbb, ins);
5707                         }
5708                         return ins;
5709                 }
5710         } else if (cmethod->klass->image == mono_defaults.corlib &&
5711                    (strcmp (cmethod->klass->name_space, "System") == 0) &&
5712                    (strcmp (cmethod->klass->name, "Environment") == 0)) {
5713                 if (!strcmp (cmethod->name, "get_IsRunningOnWindows") && fsig->param_count == 0) {
5714 #ifdef TARGET_WIN32
5715                         EMIT_NEW_ICONST (cfg, ins, 1);
5716 #else
5717                         EMIT_NEW_ICONST (cfg, ins, 0);
5718 #endif
5719                 }
5720         } else if (cmethod->klass->image == mono_defaults.corlib &&
5721                            (strcmp (cmethod->klass->name_space, "System.Reflection") == 0) &&
5722                            (strcmp (cmethod->klass->name, "Assembly") == 0)) {
5723                 if (cfg->llvm_only && !strcmp (cmethod->name, "GetExecutingAssembly")) {
5724                         /* No stack walks are currently available, so implement this as an intrinsic */
5725                         MonoInst *assembly_ins;
5726
5727                         EMIT_NEW_AOTCONST (cfg, assembly_ins, MONO_PATCH_INFO_IMAGE, cfg->method->klass->image);
5728                         ins = mono_emit_jit_icall (cfg, mono_get_assembly_object, &assembly_ins);
5729                         return ins;
5730                 }
5731         } else if (cmethod->klass->image == mono_defaults.corlib &&
5732                            (strcmp (cmethod->klass->name_space, "System.Reflection") == 0) &&
5733                            (strcmp (cmethod->klass->name, "MethodBase") == 0)) {
5734                 if (cfg->llvm_only && !strcmp (cmethod->name, "GetCurrentMethod")) {
5735                         /* No stack walks are currently available, so implement this as an intrinsic */
5736                         MonoInst *method_ins;
5737                         MonoMethod *declaring = cfg->method;
5738
5739                         /* This returns the declaring generic method */
5740                         if (declaring->is_inflated)
5741                                 declaring = ((MonoMethodInflated*)cfg->method)->declaring;
5742                         EMIT_NEW_AOTCONST (cfg, method_ins, MONO_PATCH_INFO_METHODCONST, declaring);
5743                         ins = mono_emit_jit_icall (cfg, mono_get_method_object, &method_ins);
5744                         cfg->no_inline = TRUE;
5745                         if (cfg->method != cfg->current_method)
5746                                 inline_failure (cfg, "MethodBase:GetCurrentMethod ()");
5747                         return ins;
5748                 }
5749         } else if (cmethod->klass == mono_defaults.math_class) {
5750                 /* 
5751                  * There is general branchless code for Min/Max, but it does not work for 
5752                  * all inputs:
5753                  * http://everything2.com/?node_id=1051618
5754                  */
5755         } else if (cmethod->klass == mono_defaults.systemtype_class && !strcmp (cmethod->name, "op_Equality")) {
5756                 EMIT_NEW_BIALU (cfg, ins, OP_COMPARE, -1, args [0]->dreg, args [1]->dreg);
5757                 MONO_INST_NEW (cfg, ins, OP_PCEQ);
5758                 ins->dreg = alloc_preg (cfg);
5759                 ins->type = STACK_I4;
5760                 MONO_ADD_INS (cfg->cbb, ins);
5761                 return ins;
5762         } else if (((!strcmp (cmethod->klass->image->assembly->aname.name, "MonoMac") ||
5763                     !strcmp (cmethod->klass->image->assembly->aname.name, "monotouch")) &&
5764                                 !strcmp (cmethod->klass->name_space, "XamCore.ObjCRuntime") &&
5765                                 !strcmp (cmethod->klass->name, "Selector")) ||
5766                            ((!strcmp (cmethod->klass->image->assembly->aname.name, "Xamarin.iOS") ||
5767                                  !strcmp (cmethod->klass->image->assembly->aname.name, "Xamarin.Mac")) &&
5768                                 !strcmp (cmethod->klass->name_space, "ObjCRuntime") &&
5769                                 !strcmp (cmethod->klass->name, "Selector"))
5770                            ) {
5771                 if ((cfg->backend->have_objc_get_selector || cfg->compile_llvm) &&
5772                         !strcmp (cmethod->name, "GetHandle") && fsig->param_count == 1 &&
5773                     (args [0]->opcode == OP_GOT_ENTRY || args [0]->opcode == OP_AOTCONST) &&
5774                     cfg->compile_aot) {
5775                         MonoInst *pi;
5776                         MonoJumpInfoToken *ji;
5777                         char *s;
5778
5779                         if (args [0]->opcode == OP_GOT_ENTRY) {
5780                                 pi = (MonoInst *)args [0]->inst_p1;
5781                                 g_assert (pi->opcode == OP_PATCH_INFO);
5782                                 g_assert (GPOINTER_TO_INT (pi->inst_p1) == MONO_PATCH_INFO_LDSTR);
5783                                 ji = (MonoJumpInfoToken *)pi->inst_p0;
5784                         } else {
5785                                 g_assert (GPOINTER_TO_INT (args [0]->inst_p1) == MONO_PATCH_INFO_LDSTR);
5786                                 ji = (MonoJumpInfoToken *)args [0]->inst_p0;
5787                         }
5788
5789                         NULLIFY_INS (args [0]);
5790
5791                         s = mono_ldstr_utf8 (ji->image, mono_metadata_token_index (ji->token), &cfg->error);
5792                         return_val_if_nok (&cfg->error, NULL);
5793
5794                         MONO_INST_NEW (cfg, ins, OP_OBJC_GET_SELECTOR);
5795                         ins->dreg = mono_alloc_ireg (cfg);
5796                         // FIXME: Leaks
5797                         ins->inst_p0 = s;
5798                         MONO_ADD_INS (cfg->cbb, ins);
5799                         return ins;
5800                 }
5801         } else if (cmethod->klass->image == mono_defaults.corlib &&
5802                         (strcmp (cmethod->klass->name_space, "System.Runtime.InteropServices") == 0) &&
5803                         (strcmp (cmethod->klass->name, "Marshal") == 0)) {
5804                 //Convert Marshal.PtrToStructure<T> of blittable T to direct loads
5805                 if (strcmp (cmethod->name, "PtrToStructure") == 0 &&
5806                                 cmethod->is_inflated &&
5807                                 fsig->param_count == 1 &&
5808                                 !mini_method_check_context_used (cfg, cmethod)) {
5809
5810                         MonoGenericContext *method_context = mono_method_get_context (cmethod);
5811                         MonoType *arg0 = method_context->method_inst->type_argv [0];
5812                         if (mono_type_is_native_blittable (arg0))
5813                                 return mini_emit_memory_load (cfg, arg0, args [0], 0, 0);
5814                 }
5815         }
5816
5817 #ifdef MONO_ARCH_SIMD_INTRINSICS
5818         if (cfg->opt & MONO_OPT_SIMD) {
5819                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
5820                 if (ins)
5821                         return ins;
5822         }
5823 #endif
5824
5825         ins = mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
5826         if (ins)
5827                 return ins;
5828
5829         if (COMPILE_LLVM (cfg)) {
5830                 ins = llvm_emit_inst_for_method (cfg, cmethod, fsig, args);
5831                 if (ins)
5832                         return ins;
5833         }
5834
5835         return mono_arch_emit_inst_for_method (cfg, cmethod, fsig, args);
5836 }
5837
5838 /*
5839  * This entry point could be used later for arbitrary method
5840  * redirection.
5841  */
5842 inline static MonoInst*
5843 mini_redirect_call (MonoCompile *cfg, MonoMethod *method,  
5844                                         MonoMethodSignature *signature, MonoInst **args, MonoInst *this_ins)
5845 {
5846         if (method->klass == mono_defaults.string_class) {
5847                 /* managed string allocation support */
5848                 if (strcmp (method->name, "InternalAllocateStr") == 0 && !(cfg->opt & MONO_OPT_SHARED)) {
5849                         MonoInst *iargs [2];
5850                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
5851                         MonoMethod *managed_alloc = NULL;
5852
5853                         g_assert (vtable); /*Should not fail since it System.String*/
5854 #ifndef MONO_CROSS_COMPILE
5855                         managed_alloc = mono_gc_get_managed_allocator (method->klass, FALSE, FALSE);
5856 #endif
5857                         if (!managed_alloc)
5858                                 return NULL;
5859                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
5860                         iargs [1] = args [0];
5861                         return mono_emit_method_call (cfg, managed_alloc, iargs, this_ins);
5862                 }
5863         }
5864         return NULL;
5865 }
5866
5867 static void
5868 mono_save_args (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **sp)
5869 {
5870         MonoInst *store, *temp;
5871         int i;
5872
5873         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
5874                 MonoType *argtype = (sig->hasthis && (i == 0)) ? type_from_stack_type (*sp) : sig->params [i - sig->hasthis];
5875
5876                 /*
5877                  * FIXME: We should use *args++ = sp [0], but that would mean the arg
5878                  * would be different than the MonoInst's used to represent arguments, and
5879                  * the ldelema implementation can't deal with that.
5880                  * Solution: When ldelema is used on an inline argument, create a var for 
5881                  * it, emit ldelema on that var, and emit the saving code below in
5882                  * inline_method () if needed.
5883                  */
5884                 temp = mono_compile_create_var (cfg, argtype, OP_LOCAL);
5885                 cfg->args [i] = temp;
5886                 /* This uses cfg->args [i] which is set by the preceeding line */
5887                 EMIT_NEW_ARGSTORE (cfg, store, i, *sp);
5888                 store->cil_code = sp [0]->cil_code;
5889                 sp++;
5890         }
5891 }
5892
5893 #define MONO_INLINE_CALLED_LIMITED_METHODS 1
5894 #define MONO_INLINE_CALLER_LIMITED_METHODS 1
5895
5896 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
5897 static gboolean
5898 check_inline_called_method_name_limit (MonoMethod *called_method)
5899 {
5900         int strncmp_result;
5901         static const char *limit = NULL;
5902         
5903         if (limit == NULL) {
5904                 const char *limit_string = g_getenv ("MONO_INLINE_CALLED_METHOD_NAME_LIMIT");
5905
5906                 if (limit_string != NULL)
5907                         limit = limit_string;
5908                 else
5909                         limit = "";
5910         }
5911
5912         if (limit [0] != '\0') {
5913                 char *called_method_name = mono_method_full_name (called_method, TRUE);
5914
5915                 strncmp_result = strncmp (called_method_name, limit, strlen (limit));
5916                 g_free (called_method_name);
5917         
5918                 //return (strncmp_result <= 0);
5919                 return (strncmp_result == 0);
5920         } else {
5921                 return TRUE;
5922         }
5923 }
5924 #endif
5925
5926 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
5927 static gboolean
5928 check_inline_caller_method_name_limit (MonoMethod *caller_method)
5929 {
5930         int strncmp_result;
5931         static const char *limit = NULL;
5932         
5933         if (limit == NULL) {
5934                 const char *limit_string = g_getenv ("MONO_INLINE_CALLER_METHOD_NAME_LIMIT");
5935                 if (limit_string != NULL) {
5936                         limit = limit_string;
5937                 } else {
5938                         limit = "";
5939                 }
5940         }
5941
5942         if (limit [0] != '\0') {
5943                 char *caller_method_name = mono_method_full_name (caller_method, TRUE);
5944
5945                 strncmp_result = strncmp (caller_method_name, limit, strlen (limit));
5946                 g_free (caller_method_name);
5947         
5948                 //return (strncmp_result <= 0);
5949                 return (strncmp_result == 0);
5950         } else {
5951                 return TRUE;
5952         }
5953 }
5954 #endif
5955
5956 static void
5957 emit_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
5958 {
5959         static double r8_0 = 0.0;
5960         static float r4_0 = 0.0;
5961         MonoInst *ins;
5962         int t;
5963
5964         rtype = mini_get_underlying_type (rtype);
5965         t = rtype->type;
5966
5967         if (rtype->byref) {
5968                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
5969         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
5970                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
5971         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
5972                 MONO_EMIT_NEW_I8CONST (cfg, dreg, 0);
5973         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
5974                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
5975                 ins->type = STACK_R4;
5976                 ins->inst_p0 = (void*)&r4_0;
5977                 ins->dreg = dreg;
5978                 MONO_ADD_INS (cfg->cbb, ins);
5979         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
5980                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
5981                 ins->type = STACK_R8;
5982                 ins->inst_p0 = (void*)&r8_0;
5983                 ins->dreg = dreg;
5984                 MONO_ADD_INS (cfg->cbb, ins);
5985         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
5986                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
5987                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
5988         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (rtype)) {
5989                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
5990         } else {
5991                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
5992         }
5993 }
5994
5995 static void
5996 emit_dummy_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
5997 {
5998         int t;
5999
6000         rtype = mini_get_underlying_type (rtype);
6001         t = rtype->type;
6002
6003         if (rtype->byref) {
6004                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_PCONST);
6005         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
6006                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_ICONST);
6007         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
6008                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_I8CONST);
6009         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
6010                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R4CONST);
6011         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
6012                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R8CONST);
6013         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
6014                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
6015                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
6016         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (rtype)) {
6017                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
6018         } else {
6019                 emit_init_rvar (cfg, dreg, rtype);
6020         }
6021 }
6022
6023 /* If INIT is FALSE, emit dummy initialization statements to keep the IR valid */
6024 static void
6025 emit_init_local (MonoCompile *cfg, int local, MonoType *type, gboolean init)
6026 {
6027         MonoInst *var = cfg->locals [local];
6028         if (COMPILE_SOFT_FLOAT (cfg)) {
6029                 MonoInst *store;
6030                 int reg = alloc_dreg (cfg, (MonoStackType)var->type);
6031                 emit_init_rvar (cfg, reg, type);
6032                 EMIT_NEW_LOCSTORE (cfg, store, local, cfg->cbb->last_ins);
6033         } else {
6034                 if (init)
6035                         emit_init_rvar (cfg, var->dreg, type);
6036                 else
6037                         emit_dummy_init_rvar (cfg, var->dreg, type);
6038         }
6039 }
6040
6041 int
6042 mini_inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp, guchar *ip, guint real_offset, gboolean inline_always)
6043 {
6044         return inline_method (cfg, cmethod, fsig, sp, ip, real_offset, inline_always);
6045 }
6046
6047 /*
6048  * inline_method:
6049  *
6050  * Return the cost of inlining CMETHOD, or zero if it should not be inlined.
6051  */
6052 static int
6053 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
6054                guchar *ip, guint real_offset, gboolean inline_always)
6055 {
6056         MonoError error;
6057         MonoInst *ins, *rvar = NULL;
6058         MonoMethodHeader *cheader;
6059         MonoBasicBlock *ebblock, *sbblock;
6060         int i, costs;
6061         MonoMethod *prev_inlined_method;
6062         MonoInst **prev_locals, **prev_args;
6063         MonoType **prev_arg_types;
6064         guint prev_real_offset;
6065         GHashTable *prev_cbb_hash;
6066         MonoBasicBlock **prev_cil_offset_to_bb;
6067         MonoBasicBlock *prev_cbb;
6068         const unsigned char *prev_ip;
6069         unsigned char *prev_cil_start;
6070         guint32 prev_cil_offset_to_bb_len;
6071         MonoMethod *prev_current_method;
6072         MonoGenericContext *prev_generic_context;
6073         gboolean ret_var_set, prev_ret_var_set, prev_disable_inline, virtual_ = FALSE;
6074
6075         g_assert (cfg->exception_type == MONO_EXCEPTION_NONE);
6076
6077 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
6078         if ((! inline_always) && ! check_inline_called_method_name_limit (cmethod))
6079                 return 0;
6080 #endif
6081 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
6082         if ((! inline_always) && ! check_inline_caller_method_name_limit (cfg->method))
6083                 return 0;
6084 #endif
6085
6086         if (!fsig)
6087                 fsig = mono_method_signature (cmethod);
6088
6089         if (cfg->verbose_level > 2)
6090                 printf ("INLINE START %p %s -> %s\n", cmethod,  mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
6091
6092         if (!cmethod->inline_info) {
6093                 cfg->stat_inlineable_methods++;
6094                 cmethod->inline_info = 1;
6095         }
6096
6097         /* allocate local variables */
6098         cheader = mono_method_get_header_checked (cmethod, &error);
6099         if (!cheader) {
6100                 if (inline_always) {
6101                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
6102                         mono_error_move (&cfg->error, &error);
6103                 } else {
6104                         mono_error_cleanup (&error);
6105                 }
6106                 return 0;
6107         }
6108
6109         /*Must verify before creating locals as it can cause the JIT to assert.*/
6110         if (mono_compile_is_broken (cfg, cmethod, FALSE)) {
6111                 mono_metadata_free_mh (cheader);
6112                 return 0;
6113         }
6114
6115         /* allocate space to store the return value */
6116         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
6117                 rvar = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
6118         }
6119
6120         prev_locals = cfg->locals;
6121         cfg->locals = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, cheader->num_locals * sizeof (MonoInst*));
6122         for (i = 0; i < cheader->num_locals; ++i)
6123                 cfg->locals [i] = mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
6124
6125         /* allocate start and end blocks */
6126         /* This is needed so if the inline is aborted, we can clean up */
6127         NEW_BBLOCK (cfg, sbblock);
6128         sbblock->real_offset = real_offset;
6129
6130         NEW_BBLOCK (cfg, ebblock);
6131         ebblock->block_num = cfg->num_bblocks++;
6132         ebblock->real_offset = real_offset;
6133
6134         prev_args = cfg->args;
6135         prev_arg_types = cfg->arg_types;
6136         prev_inlined_method = cfg->inlined_method;
6137         prev_ret_var_set = cfg->ret_var_set;
6138         prev_real_offset = cfg->real_offset;
6139         prev_cbb_hash = cfg->cbb_hash;
6140         prev_cil_offset_to_bb = cfg->cil_offset_to_bb;
6141         prev_cil_offset_to_bb_len = cfg->cil_offset_to_bb_len;
6142         prev_cil_start = cfg->cil_start;
6143         prev_ip = cfg->ip;
6144         prev_cbb = cfg->cbb;
6145         prev_current_method = cfg->current_method;
6146         prev_generic_context = cfg->generic_context;
6147         prev_disable_inline = cfg->disable_inline;
6148
6149         cfg->inlined_method = cmethod;
6150         cfg->ret_var_set = FALSE;
6151         cfg->inline_depth ++;
6152
6153         if (ip && *ip == CEE_CALLVIRT && !(cmethod->flags & METHOD_ATTRIBUTE_STATIC))
6154                 virtual_ = TRUE;
6155
6156         costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, rvar, sp, real_offset, virtual_);
6157
6158         ret_var_set = cfg->ret_var_set;
6159
6160         cfg->inlined_method = prev_inlined_method;
6161         cfg->real_offset = prev_real_offset;
6162         cfg->cbb_hash = prev_cbb_hash;
6163         cfg->cil_offset_to_bb = prev_cil_offset_to_bb;
6164         cfg->cil_offset_to_bb_len = prev_cil_offset_to_bb_len;
6165         cfg->cil_start = prev_cil_start;
6166         cfg->ip = prev_ip;
6167         cfg->locals = prev_locals;
6168         cfg->args = prev_args;
6169         cfg->arg_types = prev_arg_types;
6170         cfg->current_method = prev_current_method;
6171         cfg->generic_context = prev_generic_context;
6172         cfg->ret_var_set = prev_ret_var_set;
6173         cfg->disable_inline = prev_disable_inline;
6174         cfg->inline_depth --;
6175
6176         if ((costs >= 0 && costs < 60) || inline_always || (costs >= 0 && (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))) {
6177                 if (cfg->verbose_level > 2)
6178                         printf ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
6179
6180                 cfg->stat_inlined_methods++;
6181
6182                 /* always add some code to avoid block split failures */
6183                 MONO_INST_NEW (cfg, ins, OP_NOP);
6184                 MONO_ADD_INS (prev_cbb, ins);
6185
6186                 prev_cbb->next_bb = sbblock;
6187                 link_bblock (cfg, prev_cbb, sbblock);
6188
6189                 /* 
6190                  * Get rid of the begin and end bblocks if possible to aid local
6191                  * optimizations.
6192                  */
6193                 if (prev_cbb->out_count == 1)
6194                         mono_merge_basic_blocks (cfg, prev_cbb, sbblock);
6195
6196                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] != ebblock))
6197                         mono_merge_basic_blocks (cfg, prev_cbb, prev_cbb->out_bb [0]);
6198
6199                 if ((ebblock->in_count == 1) && ebblock->in_bb [0]->out_count == 1) {
6200                         MonoBasicBlock *prev = ebblock->in_bb [0];
6201
6202                         if (prev->next_bb == ebblock) {
6203                                 mono_merge_basic_blocks (cfg, prev, ebblock);
6204                                 cfg->cbb = prev;
6205                                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] == prev)) {
6206                                         mono_merge_basic_blocks (cfg, prev_cbb, prev);
6207                                         cfg->cbb = prev_cbb;
6208                                 }
6209                         } else {
6210                                 /* There could be a bblock after 'prev', and making 'prev' the current bb could cause problems */
6211                                 cfg->cbb = ebblock;
6212                         }
6213                 } else {
6214                         /* 
6215                          * Its possible that the rvar is set in some prev bblock, but not in others.
6216                          * (#1835).
6217                          */
6218                         if (rvar) {
6219                                 MonoBasicBlock *bb;
6220
6221                                 for (i = 0; i < ebblock->in_count; ++i) {
6222                                         bb = ebblock->in_bb [i];
6223
6224                                         if (bb->last_ins && bb->last_ins->opcode == OP_NOT_REACHED) {
6225                                                 cfg->cbb = bb;
6226
6227                                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
6228                                         }
6229                                 }
6230                         }
6231
6232                         cfg->cbb = ebblock;
6233                 }
6234
6235                 if (rvar) {
6236                         /*
6237                          * If the inlined method contains only a throw, then the ret var is not 
6238                          * set, so set it to a dummy value.
6239                          */
6240                         if (!ret_var_set)
6241                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
6242
6243                         EMIT_NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
6244                         *sp++ = ins;
6245                 }
6246                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
6247                 return costs + 1;
6248         } else {
6249                 if (cfg->verbose_level > 2)
6250                         printf ("INLINE ABORTED %s (cost %d)\n", mono_method_full_name (cmethod, TRUE), costs);
6251                 cfg->exception_type = MONO_EXCEPTION_NONE;
6252
6253                 /* This gets rid of the newly added bblocks */
6254                 cfg->cbb = prev_cbb;
6255         }
6256         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
6257         return 0;
6258 }
6259
6260 /*
6261  * Some of these comments may well be out-of-date.
6262  * Design decisions: we do a single pass over the IL code (and we do bblock 
6263  * splitting/merging in the few cases when it's required: a back jump to an IL
6264  * address that was not already seen as bblock starting point).
6265  * Code is validated as we go (full verification is still better left to metadata/verify.c).
6266  * Complex operations are decomposed in simpler ones right away. We need to let the 
6267  * arch-specific code peek and poke inside this process somehow (except when the 
6268  * optimizations can take advantage of the full semantic info of coarse opcodes).
6269  * All the opcodes of the form opcode.s are 'normalized' to opcode.
6270  * MonoInst->opcode initially is the IL opcode or some simplification of that 
6271  * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific 
6272  * opcode with value bigger than OP_LAST.
6273  * At this point the IR can be handed over to an interpreter, a dumb code generator
6274  * or to the optimizing code generator that will translate it to SSA form.
6275  *
6276  * Profiling directed optimizations.
6277  * We may compile by default with few or no optimizations and instrument the code
6278  * or the user may indicate what methods to optimize the most either in a config file
6279  * or through repeated runs where the compiler applies offline the optimizations to 
6280  * each method and then decides if it was worth it.
6281  */
6282
6283 #define CHECK_TYPE(ins) if (!(ins)->type) UNVERIFIED
6284 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) UNVERIFIED
6285 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) UNVERIFIED
6286 #define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) UNVERIFIED
6287 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
6288 #define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
6289 #define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
6290 #define CHECK_TYPELOAD(klass) if (!(klass) || mono_class_has_failure (klass)) TYPE_LOAD_ERROR ((klass))
6291
6292 /* offset from br.s -> br like opcodes */
6293 #define BIG_BRANCH_OFFSET 13
6294
6295 static gboolean
6296 ip_in_bb (MonoCompile *cfg, MonoBasicBlock *bb, const guint8* ip)
6297 {
6298         MonoBasicBlock *b = cfg->cil_offset_to_bb [ip - cfg->cil_start];
6299
6300         return b == NULL || b == bb;
6301 }
6302
6303 static int
6304 get_basic_blocks (MonoCompile *cfg, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
6305 {
6306         unsigned char *ip = start;
6307         unsigned char *target;
6308         int i;
6309         guint cli_addr;
6310         MonoBasicBlock *bblock;
6311         const MonoOpcode *opcode;
6312
6313         while (ip < end) {
6314                 cli_addr = ip - start;
6315                 i = mono_opcode_value ((const guint8 **)&ip, end);
6316                 if (i < 0)
6317                         UNVERIFIED;
6318                 opcode = &mono_opcodes [i];
6319                 switch (opcode->argument) {
6320                 case MonoInlineNone:
6321                         ip++; 
6322                         break;
6323                 case MonoInlineString:
6324                 case MonoInlineType:
6325                 case MonoInlineField:
6326                 case MonoInlineMethod:
6327                 case MonoInlineTok:
6328                 case MonoInlineSig:
6329                 case MonoShortInlineR:
6330                 case MonoInlineI:
6331                         ip += 5;
6332                         break;
6333                 case MonoInlineVar:
6334                         ip += 3;
6335                         break;
6336                 case MonoShortInlineVar:
6337                 case MonoShortInlineI:
6338                         ip += 2;
6339                         break;
6340                 case MonoShortInlineBrTarget:
6341                         target = start + cli_addr + 2 + (signed char)ip [1];
6342                         GET_BBLOCK (cfg, bblock, target);
6343                         ip += 2;
6344                         if (ip < end)
6345                                 GET_BBLOCK (cfg, bblock, ip);
6346                         break;
6347                 case MonoInlineBrTarget:
6348                         target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
6349                         GET_BBLOCK (cfg, bblock, target);
6350                         ip += 5;
6351                         if (ip < end)
6352                                 GET_BBLOCK (cfg, bblock, ip);
6353                         break;
6354                 case MonoInlineSwitch: {
6355                         guint32 n = read32 (ip + 1);
6356                         guint32 j;
6357                         ip += 5;
6358                         cli_addr += 5 + 4 * n;
6359                         target = start + cli_addr;
6360                         GET_BBLOCK (cfg, bblock, target);
6361                         
6362                         for (j = 0; j < n; ++j) {
6363                                 target = start + cli_addr + (gint32)read32 (ip);
6364                                 GET_BBLOCK (cfg, bblock, target);
6365                                 ip += 4;
6366                         }
6367                         break;
6368                 }
6369                 case MonoInlineR:
6370                 case MonoInlineI8:
6371                         ip += 9;
6372                         break;
6373                 default:
6374                         g_assert_not_reached ();
6375                 }
6376
6377                 if (i == CEE_THROW) {
6378                         unsigned char *bb_start = ip - 1;
6379                         
6380                         /* Find the start of the bblock containing the throw */
6381                         bblock = NULL;
6382                         while ((bb_start >= start) && !bblock) {
6383                                 bblock = cfg->cil_offset_to_bb [(bb_start) - start];
6384                                 bb_start --;
6385                         }
6386                         if (bblock)
6387                                 bblock->out_of_line = 1;
6388                 }
6389         }
6390         return 0;
6391 unverified:
6392 exception_exit:
6393         *pos = ip;
6394         return 1;
6395 }
6396
6397 static inline MonoMethod *
6398 mini_get_method_allow_open (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context, MonoError *error)
6399 {
6400         MonoMethod *method;
6401
6402         error_init (error);
6403
6404         if (m->wrapper_type != MONO_WRAPPER_NONE) {
6405                 method = (MonoMethod *)mono_method_get_wrapper_data (m, token);
6406                 if (context) {
6407                         method = mono_class_inflate_generic_method_checked (method, context, error);
6408                 }
6409         } else {
6410                 method = mono_get_method_checked (m->klass->image, token, klass, context, error);
6411         }
6412
6413         return method;
6414 }
6415
6416 static inline MonoMethod *
6417 mini_get_method (MonoCompile *cfg, MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
6418 {
6419         MonoError error;
6420         MonoMethod *method = mini_get_method_allow_open (m, token, klass, context, cfg ? &cfg->error : &error);
6421
6422         if (method && cfg && !cfg->gshared && mono_class_is_open_constructed_type (&method->klass->byval_arg)) {
6423                 mono_error_set_bad_image (&cfg->error, cfg->method->klass->image, "Method with open type while not compiling gshared");
6424                 method = NULL;
6425         }
6426
6427         if (!method && !cfg)
6428                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
6429
6430         return method;
6431 }
6432
6433 static inline MonoMethodSignature*
6434 mini_get_signature (MonoMethod *method, guint32 token, MonoGenericContext *context, MonoError *error)
6435 {
6436         MonoMethodSignature *fsig;
6437
6438         error_init (error);
6439         if (method->wrapper_type != MONO_WRAPPER_NONE) {
6440                 fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
6441         } else {
6442                 fsig = mono_metadata_parse_signature_checked (method->klass->image, token, error);
6443                 return_val_if_nok (error, NULL);
6444         }
6445         if (context) {
6446                 fsig = mono_inflate_generic_signature(fsig, context, error);
6447         }
6448         return fsig;
6449 }
6450
6451 static MonoMethod*
6452 throw_exception (void)
6453 {
6454         static MonoMethod *method = NULL;
6455
6456         if (!method) {
6457                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
6458                 method = mono_class_get_method_from_name (secman->securitymanager, "ThrowException", 1);
6459         }
6460         g_assert (method);
6461         return method;
6462 }
6463
6464 static void
6465 emit_throw_exception (MonoCompile *cfg, MonoException *ex)
6466 {
6467         MonoMethod *thrower = throw_exception ();
6468         MonoInst *args [1];
6469
6470         EMIT_NEW_PCONST (cfg, args [0], ex);
6471         mono_emit_method_call (cfg, thrower, args, NULL);
6472 }
6473
6474 /*
6475  * Return the original method is a wrapper is specified. We can only access 
6476  * the custom attributes from the original method.
6477  */
6478 static MonoMethod*
6479 get_original_method (MonoMethod *method)
6480 {
6481         if (method->wrapper_type == MONO_WRAPPER_NONE)
6482                 return method;
6483
6484         /* native code (which is like Critical) can call any managed method XXX FIXME XXX to validate all usages */
6485         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)
6486                 return NULL;
6487
6488         /* in other cases we need to find the original method */
6489         return mono_marshal_method_from_wrapper (method);
6490 }
6491
6492 static void
6493 ensure_method_is_allowed_to_access_field (MonoCompile *cfg, MonoMethod *caller, MonoClassField *field)
6494 {
6495         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
6496         MonoException *ex = mono_security_core_clr_is_field_access_allowed (get_original_method (caller), field);
6497         if (ex)
6498                 emit_throw_exception (cfg, ex);
6499 }
6500
6501 static void
6502 ensure_method_is_allowed_to_call_method (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee)
6503 {
6504         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
6505         MonoException *ex = mono_security_core_clr_is_call_allowed (get_original_method (caller), callee);
6506         if (ex)
6507                 emit_throw_exception (cfg, ex);
6508 }
6509
6510 /*
6511  * Check that the IL instructions at ip are the array initialization
6512  * sequence and return the pointer to the data and the size.
6513  */
6514 static const char*
6515 initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, MonoClass *klass, guint32 len, int *out_size, guint32 *out_field_token)
6516 {
6517         /*
6518          * newarr[System.Int32]
6519          * dup
6520          * ldtoken field valuetype ...
6521          * call void class [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle)
6522          */
6523         if (ip [0] == CEE_DUP && ip [1] == CEE_LDTOKEN && ip [5] == 0x4 && ip [6] == CEE_CALL) {
6524                 MonoError error;
6525                 guint32 token = read32 (ip + 7);
6526                 guint32 field_token = read32 (ip + 2);
6527                 guint32 field_index = field_token & 0xffffff;
6528                 guint32 rva;
6529                 const char *data_ptr;
6530                 int size = 0;
6531                 MonoMethod *cmethod;
6532                 MonoClass *dummy_class;
6533                 MonoClassField *field = mono_field_from_token_checked (method->klass->image, field_token, &dummy_class, NULL, &error);
6534                 int dummy_align;
6535
6536                 if (!field) {
6537                         mono_error_cleanup (&error); /* FIXME don't swallow the error */
6538                         return NULL;
6539                 }
6540
6541                 *out_field_token = field_token;
6542
6543                 cmethod = mini_get_method (NULL, method, token, NULL, NULL);
6544                 if (!cmethod)
6545                         return NULL;
6546                 if (strcmp (cmethod->name, "InitializeArray") || strcmp (cmethod->klass->name, "RuntimeHelpers") || cmethod->klass->image != mono_defaults.corlib)
6547                         return NULL;
6548                 switch (mini_get_underlying_type (&klass->byval_arg)->type) {
6549                 case MONO_TYPE_I1:
6550                 case MONO_TYPE_U1:
6551                         size = 1; break;
6552                 /* we need to swap on big endian, so punt. Should we handle R4 and R8 as well? */
6553 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
6554                 case MONO_TYPE_I2:
6555                 case MONO_TYPE_U2:
6556                         size = 2; break;
6557                 case MONO_TYPE_I4:
6558                 case MONO_TYPE_U4:
6559                 case MONO_TYPE_R4:
6560                         size = 4; break;
6561                 case MONO_TYPE_R8:
6562                 case MONO_TYPE_I8:
6563                 case MONO_TYPE_U8:
6564                         size = 8; break;
6565 #endif
6566                 default:
6567                         return NULL;
6568                 }
6569                 size *= len;
6570                 if (size > mono_type_size (field->type, &dummy_align))
6571                     return NULL;
6572                 *out_size = size;
6573                 /*g_print ("optimized in %s: size: %d, numelems: %d\n", method->name, size, newarr->inst_newa_len->inst_c0);*/
6574                 if (!image_is_dynamic (method->klass->image)) {
6575                         field_index = read32 (ip + 2) & 0xffffff;
6576                         mono_metadata_field_info (method->klass->image, field_index - 1, NULL, &rva, NULL);
6577                         data_ptr = mono_image_rva_map (method->klass->image, rva);
6578                         /*g_print ("field: 0x%08x, rva: %d, rva_ptr: %p\n", read32 (ip + 2), rva, data_ptr);*/
6579                         /* for aot code we do the lookup on load */
6580                         if (aot && data_ptr)
6581                                 return (const char *)GUINT_TO_POINTER (rva);
6582                 } else {
6583                         /*FIXME is it possible to AOT a SRE assembly not meant to be saved? */ 
6584                         g_assert (!aot);
6585                         data_ptr = mono_field_get_data (field);
6586                 }
6587                 return data_ptr;
6588         }
6589         return NULL;
6590 }
6591
6592 static void
6593 set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsigned char *ip)
6594 {
6595         MonoError error;
6596         char *method_fname = mono_method_full_name (method, TRUE);
6597         char *method_code;
6598         MonoMethodHeader *header = mono_method_get_header_checked (method, &error);
6599
6600         if (!header) {
6601                 method_code = g_strdup_printf ("could not parse method body due to %s", mono_error_get_message (&error));
6602                 mono_error_cleanup (&error);
6603         } else if (header->code_size == 0)
6604                 method_code = g_strdup ("method body is empty.");
6605         else
6606                 method_code = mono_disasm_code_one (NULL, method, ip, NULL);
6607         mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("Invalid IL code in %s: %s\n", method_fname, method_code));
6608         g_free (method_fname);
6609         g_free (method_code);
6610         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
6611 }
6612
6613 static guint32
6614 mono_type_to_stloc_coerce (MonoType *type)
6615 {
6616         if (type->byref)
6617                 return 0;
6618
6619         type = mini_get_underlying_type (type);
6620 handle_enum:
6621         switch (type->type) {
6622         case MONO_TYPE_I1:
6623                 return OP_ICONV_TO_I1;
6624         case MONO_TYPE_U1:
6625                 return OP_ICONV_TO_U1;
6626         case MONO_TYPE_I2:
6627                 return OP_ICONV_TO_I2;
6628         case MONO_TYPE_U2:
6629                 return OP_ICONV_TO_U2;
6630         case MONO_TYPE_I4:
6631         case MONO_TYPE_U4:
6632         case MONO_TYPE_I:
6633         case MONO_TYPE_U:
6634         case MONO_TYPE_PTR:
6635         case MONO_TYPE_FNPTR:
6636         case MONO_TYPE_CLASS:
6637         case MONO_TYPE_STRING:
6638         case MONO_TYPE_OBJECT:
6639         case MONO_TYPE_SZARRAY:
6640         case MONO_TYPE_ARRAY:
6641         case MONO_TYPE_I8:
6642         case MONO_TYPE_U8:
6643         case MONO_TYPE_R4:
6644         case MONO_TYPE_R8:
6645         case MONO_TYPE_TYPEDBYREF:
6646         case MONO_TYPE_GENERICINST:
6647                 return 0;
6648         case MONO_TYPE_VALUETYPE:
6649                 if (type->data.klass->enumtype) {
6650                         type = mono_class_enum_basetype (type->data.klass);
6651                         goto handle_enum;
6652                 }
6653                 return 0;
6654         case MONO_TYPE_VAR:
6655         case MONO_TYPE_MVAR: //TODO I believe we don't need to handle gsharedvt as there won't be match and, for example, u1 is not covariant to u32
6656                 return 0;
6657         default:
6658                 g_error ("unknown type 0x%02x in mono_type_to_stloc_coerce", type->type);
6659         }
6660         return -1;
6661 }
6662
6663 static void
6664 emit_stloc_ir (MonoCompile *cfg, MonoInst **sp, MonoMethodHeader *header, int n)
6665 {
6666         MonoInst *ins;
6667         guint32 coerce_op = mono_type_to_stloc_coerce (header->locals [n]);
6668
6669         if (coerce_op) {
6670                 if (cfg->cbb->last_ins == sp [0] && sp [0]->opcode == coerce_op) {
6671                         if (cfg->verbose_level > 2)
6672                                 printf ("Found existing coercing is enough for stloc\n");
6673                 } else {
6674                         MONO_INST_NEW (cfg, ins, coerce_op);
6675                         ins->dreg = alloc_ireg (cfg);
6676                         ins->sreg1 = sp [0]->dreg;
6677                         ins->type = STACK_I4;
6678                         ins->klass = mono_class_from_mono_type (header->locals [n]);
6679                         MONO_ADD_INS (cfg->cbb, ins);
6680                         *sp = mono_decompose_opcode (cfg, ins);
6681                 }
6682         }
6683
6684
6685         guint32 opcode = mono_type_to_regmove (cfg, header->locals [n]);
6686         if ((opcode == OP_MOVE) && cfg->cbb->last_ins == sp [0]  &&
6687                         ((sp [0]->opcode == OP_ICONST) || (sp [0]->opcode == OP_I8CONST))) {
6688                 /* Optimize reg-reg moves away */
6689                 /* 
6690                  * Can't optimize other opcodes, since sp[0] might point to
6691                  * the last ins of a decomposed opcode.
6692                  */
6693                 sp [0]->dreg = (cfg)->locals [n]->dreg;
6694         } else {
6695                 EMIT_NEW_LOCSTORE (cfg, ins, n, *sp);
6696         }
6697 }
6698
6699 static void
6700 emit_starg_ir (MonoCompile *cfg, MonoInst **sp, int n)
6701 {
6702         MonoInst *ins;
6703         guint32 coerce_op = mono_type_to_stloc_coerce (cfg->arg_types [n]);
6704
6705         if (coerce_op) {
6706                 if (cfg->cbb->last_ins == sp [0] && sp [0]->opcode == coerce_op) {
6707                         if (cfg->verbose_level > 2)
6708                                 printf ("Found existing coercing is enough for starg\n");
6709                 } else {
6710                         MONO_INST_NEW (cfg, ins, coerce_op);
6711                         ins->dreg = alloc_ireg (cfg);
6712                         ins->sreg1 = sp [0]->dreg;
6713                         ins->type = STACK_I4;
6714                         ins->klass = mono_class_from_mono_type (cfg->arg_types [n]);
6715                         MONO_ADD_INS (cfg->cbb, ins);
6716                         *sp = mono_decompose_opcode (cfg, ins);
6717                 }
6718         }
6719
6720         EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
6721 }
6722
6723 /*
6724  * ldloca inhibits many optimizations so try to get rid of it in common
6725  * cases.
6726  */
6727 static inline unsigned char *
6728 emit_optimized_ldloca_ir (MonoCompile *cfg, unsigned char *ip, unsigned char *end, int size)
6729 {
6730         int local, token;
6731         MonoClass *klass;
6732         MonoType *type;
6733
6734         if (size == 1) {
6735                 local = ip [1];
6736                 ip += 2;
6737         } else {
6738                 local = read16 (ip + 2);
6739                 ip += 4;
6740         }
6741         
6742         if (ip + 6 < end && (ip [0] == CEE_PREFIX1) && (ip [1] == CEE_INITOBJ) && ip_in_bb (cfg, cfg->cbb, ip + 1)) {
6743                 /* From the INITOBJ case */
6744                 token = read32 (ip + 2);
6745                 klass = mini_get_class (cfg->current_method, token, cfg->generic_context);
6746                 CHECK_TYPELOAD (klass);
6747                 type = mini_get_underlying_type (&klass->byval_arg);
6748                 emit_init_local (cfg, local, type, TRUE);
6749                 return ip + 6;
6750         }
6751  exception_exit:
6752         return NULL;
6753 }
6754
6755 static MonoInst*
6756 emit_llvmonly_virtual_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used, MonoInst **sp)
6757 {
6758         MonoInst *icall_args [16];
6759         MonoInst *call_target, *ins, *vtable_ins;
6760         int arg_reg, this_reg, vtable_reg;
6761         gboolean is_iface = mono_class_is_interface (cmethod->klass);
6762         gboolean is_gsharedvt = cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig);
6763         gboolean variant_iface = FALSE;
6764         guint32 slot;
6765         int offset;
6766         gboolean special_array_interface = cmethod->klass->is_array_special_interface;
6767
6768         /*
6769          * In llvm-only mode, vtables contain function descriptors instead of
6770          * method addresses/trampolines.
6771          */
6772         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
6773
6774         if (is_iface)
6775                 slot = mono_method_get_imt_slot (cmethod);
6776         else
6777                 slot = mono_method_get_vtable_index (cmethod);
6778
6779         this_reg = sp [0]->dreg;
6780
6781         if (is_iface && mono_class_has_variant_generic_params (cmethod->klass))
6782                 variant_iface = TRUE;
6783
6784         if (!fsig->generic_param_count && !is_iface && !is_gsharedvt) {
6785                 /*
6786                  * The simplest case, a normal virtual call.
6787                  */
6788                 int slot_reg = alloc_preg (cfg);
6789                 int addr_reg = alloc_preg (cfg);
6790                 int arg_reg = alloc_preg (cfg);
6791                 MonoBasicBlock *non_null_bb;
6792
6793                 vtable_reg = alloc_preg (cfg);
6794                 EMIT_NEW_LOAD_MEMBASE (cfg, vtable_ins, OP_LOAD_MEMBASE, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
6795                 offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) + (slot * SIZEOF_VOID_P);
6796
6797                 /* Load the vtable slot, which contains a function descriptor. */
6798                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, slot_reg, vtable_reg, offset);
6799
6800                 NEW_BBLOCK (cfg, non_null_bb);
6801
6802                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, slot_reg, 0);
6803                 cfg->cbb->last_ins->flags |= MONO_INST_LIKELY;
6804                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, non_null_bb);
6805
6806                 /* Slow path */
6807                 // FIXME: Make the wrapper use the preserveall cconv
6808                 // FIXME: Use one icall per slot for small slot numbers ?
6809                 icall_args [0] = vtable_ins;
6810                 EMIT_NEW_ICONST (cfg, icall_args [1], slot);
6811                 /* Make the icall return the vtable slot value to save some code space */
6812                 ins = mono_emit_jit_icall (cfg, mono_init_vtable_slot, icall_args);
6813                 ins->dreg = slot_reg;
6814                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, non_null_bb);
6815
6816                 /* Fastpath */
6817                 MONO_START_BB (cfg, non_null_bb);
6818                 /* Load the address + arg from the vtable slot */
6819                 EMIT_NEW_LOAD_MEMBASE (cfg, call_target, OP_LOAD_MEMBASE, addr_reg, slot_reg, 0);
6820                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, arg_reg, slot_reg, SIZEOF_VOID_P);
6821
6822                 return emit_extra_arg_calli (cfg, fsig, sp, arg_reg, call_target);
6823         }
6824
6825         if (!fsig->generic_param_count && is_iface && !variant_iface && !is_gsharedvt && !special_array_interface) {
6826                 /*
6827                  * A simple interface call
6828                  *
6829                  * We make a call through an imt slot to obtain the function descriptor we need to call.
6830                  * The imt slot contains a function descriptor for a runtime function + arg.
6831                  */
6832                 int slot_reg = alloc_preg (cfg);
6833                 int addr_reg = alloc_preg (cfg);
6834                 int arg_reg = alloc_preg (cfg);
6835                 MonoInst *thunk_addr_ins, *thunk_arg_ins, *ftndesc_ins;
6836
6837                 vtable_reg = alloc_preg (cfg);
6838                 EMIT_NEW_LOAD_MEMBASE (cfg, vtable_ins, OP_LOAD_MEMBASE, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
6839                 offset = ((gint32)slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
6840
6841                 /*
6842                  * The slot is already initialized when the vtable is created so there is no need
6843                  * to check it here.
6844                  */
6845
6846                 /* Load the imt slot, which contains a function descriptor. */
6847                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, slot_reg, vtable_reg, offset);
6848
6849                 /* Load the address + arg of the imt thunk from the imt slot */
6850                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_addr_ins, OP_LOAD_MEMBASE, addr_reg, slot_reg, 0);
6851                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_arg_ins, OP_LOAD_MEMBASE, arg_reg, slot_reg, SIZEOF_VOID_P);
6852                 /*
6853                  * IMT thunks in llvm-only mode are C functions which take an info argument
6854                  * plus the imt method and return the ftndesc to call.
6855                  */
6856                 icall_args [0] = thunk_arg_ins;
6857                 icall_args [1] = emit_get_rgctx_method (cfg, context_used,
6858                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD);
6859                 ftndesc_ins = mini_emit_calli (cfg, helper_sig_llvmonly_imt_trampoline, icall_args, thunk_addr_ins, NULL, NULL);
6860
6861                 return emit_llvmonly_calli (cfg, fsig, sp, ftndesc_ins);
6862         }
6863
6864         if ((fsig->generic_param_count || variant_iface || special_array_interface) && !is_gsharedvt) {
6865                 /*
6866                  * This is similar to the interface case, the vtable slot points to an imt thunk which is
6867                  * dynamically extended as more instantiations are discovered.
6868                  * This handles generic virtual methods both on classes and interfaces.
6869                  */
6870                 int slot_reg = alloc_preg (cfg);
6871                 int addr_reg = alloc_preg (cfg);
6872                 int arg_reg = alloc_preg (cfg);
6873                 int ftndesc_reg = alloc_preg (cfg);
6874                 MonoInst *thunk_addr_ins, *thunk_arg_ins, *ftndesc_ins;
6875                 MonoBasicBlock *slowpath_bb, *end_bb;
6876
6877                 NEW_BBLOCK (cfg, slowpath_bb);
6878                 NEW_BBLOCK (cfg, end_bb);
6879
6880                 vtable_reg = alloc_preg (cfg);
6881                 EMIT_NEW_LOAD_MEMBASE (cfg, vtable_ins, OP_LOAD_MEMBASE, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
6882                 if (is_iface)
6883                         offset = ((gint32)slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
6884                 else
6885                         offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) + (slot * SIZEOF_VOID_P);
6886
6887                 /* Load the slot, which contains a function descriptor. */
6888                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, slot_reg, vtable_reg, offset);
6889
6890                 /* These slots are not initialized, so fall back to the slow path until they are initialized */
6891                 /* That happens when mono_method_add_generic_virtual_invocation () creates an IMT thunk */
6892                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, slot_reg, 0);
6893                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, slowpath_bb);
6894
6895                 /* Fastpath */
6896                 /* Same as with iface calls */
6897                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_addr_ins, OP_LOAD_MEMBASE, addr_reg, slot_reg, 0);
6898                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_arg_ins, OP_LOAD_MEMBASE, arg_reg, slot_reg, SIZEOF_VOID_P);
6899                 icall_args [0] = thunk_arg_ins;
6900                 icall_args [1] = emit_get_rgctx_method (cfg, context_used,
6901                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD);
6902                 ftndesc_ins = mini_emit_calli (cfg, helper_sig_llvmonly_imt_trampoline, icall_args, thunk_addr_ins, NULL, NULL);
6903                 ftndesc_ins->dreg = ftndesc_reg;
6904                 /*
6905                  * Unlike normal iface calls, these imt thunks can return NULL, i.e. when they are passed an instantiation
6906                  * they don't know about yet. Fall back to the slowpath in that case.
6907                  */
6908                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, ftndesc_reg, 0);
6909                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, slowpath_bb);
6910
6911                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
6912
6913                 /* Slowpath */
6914                 MONO_START_BB (cfg, slowpath_bb);
6915                 icall_args [0] = vtable_ins;
6916                 EMIT_NEW_ICONST (cfg, icall_args [1], slot);
6917                 icall_args [2] = emit_get_rgctx_method (cfg, context_used,
6918                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD);
6919                 if (is_iface)
6920                         ftndesc_ins = mono_emit_jit_icall (cfg, mono_resolve_generic_virtual_iface_call, icall_args);
6921                 else
6922                         ftndesc_ins = mono_emit_jit_icall (cfg, mono_resolve_generic_virtual_call, icall_args);
6923                 ftndesc_ins->dreg = ftndesc_reg;
6924                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
6925
6926                 /* Common case */
6927                 MONO_START_BB (cfg, end_bb);
6928                 return emit_llvmonly_calli (cfg, fsig, sp, ftndesc_ins);
6929         }
6930
6931         /*
6932          * Non-optimized cases
6933          */
6934         icall_args [0] = sp [0];
6935         EMIT_NEW_ICONST (cfg, icall_args [1], slot);
6936
6937         icall_args [2] = emit_get_rgctx_method (cfg, context_used,
6938                                                                                         cmethod, MONO_RGCTX_INFO_METHOD);
6939
6940         arg_reg = alloc_preg (cfg);
6941         MONO_EMIT_NEW_PCONST (cfg, arg_reg, NULL);
6942         EMIT_NEW_VARLOADA_VREG (cfg, icall_args [3], arg_reg, &mono_defaults.int_class->byval_arg);
6943
6944         g_assert (is_gsharedvt);
6945         if (is_iface)
6946                 call_target = mono_emit_jit_icall (cfg, mono_resolve_iface_call_gsharedvt, icall_args);
6947         else
6948                 call_target = mono_emit_jit_icall (cfg, mono_resolve_vcall_gsharedvt, icall_args);
6949
6950         /*
6951          * Pass the extra argument even if the callee doesn't receive it, most
6952          * calling conventions allow this.
6953          */
6954         return emit_extra_arg_calli (cfg, fsig, sp, arg_reg, call_target);
6955 }
6956
6957 static gboolean
6958 is_exception_class (MonoClass *klass)
6959 {
6960         while (klass) {
6961                 if (klass == mono_defaults.exception_class)
6962                         return TRUE;
6963                 klass = klass->parent;
6964         }
6965         return FALSE;
6966 }
6967
6968 /*
6969  * is_jit_optimizer_disabled:
6970  *
6971  *   Determine whenever M's assembly has a DebuggableAttribute with the
6972  * IsJITOptimizerDisabled flag set.
6973  */
6974 static gboolean
6975 is_jit_optimizer_disabled (MonoMethod *m)
6976 {
6977         MonoError error;
6978         MonoAssembly *ass = m->klass->image->assembly;
6979         MonoCustomAttrInfo* attrs;
6980         MonoClass *klass;
6981         int i;
6982         gboolean val = FALSE;
6983
6984         g_assert (ass);
6985         if (ass->jit_optimizer_disabled_inited)
6986                 return ass->jit_optimizer_disabled;
6987
6988         klass = mono_class_try_get_debuggable_attribute_class ();
6989
6990         if (!klass) {
6991                 /* Linked away */
6992                 ass->jit_optimizer_disabled = FALSE;
6993                 mono_memory_barrier ();
6994                 ass->jit_optimizer_disabled_inited = TRUE;
6995                 return FALSE;
6996         }
6997
6998         attrs = mono_custom_attrs_from_assembly_checked (ass, FALSE, &error);
6999         mono_error_cleanup (&error); /* FIXME don't swallow the error */
7000         if (attrs) {
7001                 for (i = 0; i < attrs->num_attrs; ++i) {
7002                         MonoCustomAttrEntry *attr = &attrs->attrs [i];
7003                         const gchar *p;
7004                         MonoMethodSignature *sig;
7005
7006                         if (!attr->ctor || attr->ctor->klass != klass)
7007                                 continue;
7008                         /* Decode the attribute. See reflection.c */
7009                         p = (const char*)attr->data;
7010                         g_assert (read16 (p) == 0x0001);
7011                         p += 2;
7012
7013                         // FIXME: Support named parameters
7014                         sig = mono_method_signature (attr->ctor);
7015                         if (sig->param_count != 2 || sig->params [0]->type != MONO_TYPE_BOOLEAN || sig->params [1]->type != MONO_TYPE_BOOLEAN)
7016                                 continue;
7017                         /* Two boolean arguments */
7018                         p ++;
7019                         val = *p;
7020                 }
7021                 mono_custom_attrs_free (attrs);
7022         }
7023
7024         ass->jit_optimizer_disabled = val;
7025         mono_memory_barrier ();
7026         ass->jit_optimizer_disabled_inited = TRUE;
7027
7028         return val;
7029 }
7030
7031 static gboolean
7032 is_supported_tail_call (MonoCompile *cfg, MonoMethod *method, MonoMethod *cmethod, MonoMethodSignature *fsig, int call_opcode)
7033 {
7034         gboolean supported_tail_call;
7035         int i;
7036
7037         supported_tail_call = mono_arch_tail_call_supported (cfg, mono_method_signature (method), mono_method_signature (cmethod));
7038
7039         for (i = 0; i < fsig->param_count; ++i) {
7040                 if (fsig->params [i]->byref || fsig->params [i]->type == MONO_TYPE_PTR || fsig->params [i]->type == MONO_TYPE_FNPTR)
7041                         /* These can point to the current method's stack */
7042                         supported_tail_call = FALSE;
7043         }
7044         if (fsig->hasthis && cmethod->klass->valuetype)
7045                 /* this might point to the current method's stack */
7046                 supported_tail_call = FALSE;
7047         if (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
7048                 supported_tail_call = FALSE;
7049         if (cfg->method->save_lmf)
7050                 supported_tail_call = FALSE;
7051         if (cmethod->wrapper_type && cmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD)
7052                 supported_tail_call = FALSE;
7053         if (call_opcode != CEE_CALL)
7054                 supported_tail_call = FALSE;
7055
7056         /* Debugging support */
7057 #if 0
7058         if (supported_tail_call) {
7059                 if (!mono_debug_count ())
7060                         supported_tail_call = FALSE;
7061         }
7062 #endif
7063
7064         return supported_tail_call;
7065 }
7066
7067 /*
7068  * handle_ctor_call:
7069  *
7070  *   Handle calls made to ctors from NEWOBJ opcodes.
7071  */
7072 static void
7073 handle_ctor_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used,
7074                                   MonoInst **sp, guint8 *ip, int *inline_costs)
7075 {
7076         MonoInst *vtable_arg = NULL, *callvirt_this_arg = NULL, *ins;
7077
7078         if (cmethod->klass->valuetype && mono_class_generic_sharing_enabled (cmethod->klass) &&
7079                                         mono_method_is_generic_sharable (cmethod, TRUE)) {
7080                 if (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst) {
7081                         mono_class_vtable (cfg->domain, cmethod->klass);
7082                         CHECK_TYPELOAD (cmethod->klass);
7083
7084                         vtable_arg = emit_get_rgctx_method (cfg, context_used,
7085                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
7086                 } else {
7087                         if (context_used) {
7088                                 vtable_arg = mini_emit_get_rgctx_klass (cfg, context_used,
7089                                                                                                    cmethod->klass, MONO_RGCTX_INFO_VTABLE);
7090                         } else {
7091                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
7092
7093                                 CHECK_TYPELOAD (cmethod->klass);
7094                                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
7095                         }
7096                 }
7097         }
7098
7099         /* Avoid virtual calls to ctors if possible */
7100         if (mono_class_is_marshalbyref (cmethod->klass))
7101                 callvirt_this_arg = sp [0];
7102
7103         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_ctor (cfg, cmethod, fsig, sp))) {
7104                 g_assert (MONO_TYPE_IS_VOID (fsig->ret));
7105                 CHECK_CFG_EXCEPTION;
7106         } else if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used && !vtable_arg &&
7107                            mono_method_check_inlining (cfg, cmethod) &&
7108                            !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE)) {
7109                 int costs;
7110
7111                 if ((costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, FALSE))) {
7112                         cfg->real_offset += 5;
7113
7114                         *inline_costs += costs - 5;
7115                 } else {
7116                         INLINE_FAILURE ("inline failure");
7117                         // FIXME-VT: Clean this up
7118                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))
7119                                 GSHAREDVT_FAILURE(*ip);
7120                         mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, callvirt_this_arg, NULL, NULL);
7121                 }
7122         } else if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
7123                 MonoInst *addr;
7124
7125                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE);
7126
7127                 if (cfg->llvm_only) {
7128                         // FIXME: Avoid initializing vtable_arg
7129                         emit_llvmonly_calli (cfg, fsig, sp, addr);
7130                 } else {
7131                         mini_emit_calli (cfg, fsig, sp, addr, NULL, vtable_arg);
7132                 }
7133         } else if (context_used &&
7134                            ((!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
7135                                  !mono_class_generic_sharing_enabled (cmethod->klass)) || cfg->gsharedvt)) {
7136                 MonoInst *cmethod_addr;
7137
7138                 /* Generic calls made out of gsharedvt methods cannot be patched, so use an indirect call */
7139
7140                 if (cfg->llvm_only) {
7141                         MonoInst *addr = emit_get_rgctx_method (cfg, context_used, cmethod,
7142                                                                                                         MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
7143                         emit_llvmonly_calli (cfg, fsig, sp, addr);
7144                 } else {
7145                         cmethod_addr = emit_get_rgctx_method (cfg, context_used,
7146                                                                                                   cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
7147
7148                         mini_emit_calli (cfg, fsig, sp, cmethod_addr, NULL, vtable_arg);
7149                 }
7150         } else {
7151                 INLINE_FAILURE ("ctor call");
7152                 ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp,
7153                                                                                   callvirt_this_arg, NULL, vtable_arg);
7154         }
7155  exception_exit:
7156         return;
7157 }
7158
7159 static void
7160 emit_setret (MonoCompile *cfg, MonoInst *val)
7161 {
7162         MonoType *ret_type = mini_get_underlying_type (mono_method_signature (cfg->method)->ret);
7163         MonoInst *ins;
7164
7165         if (mini_type_to_stind (cfg, ret_type) == CEE_STOBJ) {
7166                 MonoInst *ret_addr;
7167
7168                 if (!cfg->vret_addr) {
7169                         EMIT_NEW_VARSTORE (cfg, ins, cfg->ret, ret_type, val);
7170                 } else {
7171                         EMIT_NEW_RETLOADA (cfg, ret_addr);
7172
7173                         EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STOREV_MEMBASE, ret_addr->dreg, 0, val->dreg);
7174                         ins->klass = mono_class_from_mono_type (ret_type);
7175                 }
7176         } else {
7177 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
7178                 if (COMPILE_SOFT_FLOAT (cfg) && !ret_type->byref && ret_type->type == MONO_TYPE_R4) {
7179                         MonoInst *iargs [1];
7180                         MonoInst *conv;
7181
7182                         iargs [0] = val;
7183                         conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
7184                         mono_arch_emit_setret (cfg, cfg->method, conv);
7185                 } else {
7186                         mono_arch_emit_setret (cfg, cfg->method, val);
7187                 }
7188 #else
7189                 mono_arch_emit_setret (cfg, cfg->method, val);
7190 #endif
7191         }
7192 }
7193
7194 /*
7195  * mono_method_to_ir:
7196  *
7197  * Translate the .net IL into linear IR.
7198  *
7199  * @start_bblock: if not NULL, the starting basic block, used during inlining.
7200  * @end_bblock: if not NULL, the ending basic block, used during inlining.
7201  * @return_var: if not NULL, the place where the return value is stored, used during inlining.   
7202  * @inline_args: if not NULL, contains the arguments to the inline call
7203  * @inline_offset: if not zero, the real offset from the inline call, or zero otherwise.
7204  * @is_virtual_call: whether this method is being called as a result of a call to callvirt
7205  *
7206  * This method is used to turn ECMA IL into Mono's internal Linear IR
7207  * reprensetation.  It is used both for entire methods, as well as
7208  * inlining existing methods.  In the former case, the @start_bblock,
7209  * @end_bblock, @return_var, @inline_args are all set to NULL, and the
7210  * inline_offset is set to zero.
7211  * 
7212  * Returns: the inline cost, or -1 if there was an error processing this method.
7213  */
7214 int
7215 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
7216                    MonoInst *return_var, MonoInst **inline_args, 
7217                    guint inline_offset, gboolean is_virtual_call)
7218 {
7219         MonoError error;
7220         MonoInst *ins, **sp, **stack_start;
7221         MonoBasicBlock *tblock = NULL, *init_localsbb = NULL;
7222         MonoSimpleBasicBlock *bb = NULL, *original_bb = NULL;
7223         MonoMethod *cmethod, *method_definition;
7224         MonoInst **arg_array;
7225         MonoMethodHeader *header;
7226         MonoImage *image;
7227         guint32 token, ins_flag;
7228         MonoClass *klass;
7229         MonoClass *constrained_class = NULL;
7230         unsigned char *ip, *end, *target, *err_pos;
7231         MonoMethodSignature *sig;
7232         MonoGenericContext *generic_context = NULL;
7233         MonoGenericContainer *generic_container = NULL;
7234         MonoType **param_types;
7235         int i, n, start_new_bblock, dreg;
7236         int num_calls = 0, inline_costs = 0;
7237         int breakpoint_id = 0;
7238         guint num_args;
7239         GSList *class_inits = NULL;
7240         gboolean dont_verify, dont_verify_stloc, readonly = FALSE;
7241         int context_used;
7242         gboolean init_locals, seq_points, skip_dead_blocks;
7243         gboolean sym_seq_points = FALSE;
7244         MonoDebugMethodInfo *minfo;
7245         MonoBitSet *seq_point_locs = NULL;
7246         MonoBitSet *seq_point_set_locs = NULL;
7247
7248         cfg->disable_inline = is_jit_optimizer_disabled (method);
7249
7250         /* serialization and xdomain stuff may need access to private fields and methods */
7251         dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
7252         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE;
7253         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH;
7254         dont_verify |= method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; /* bug #77896 */
7255         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP;
7256         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP_INVOKE;
7257
7258         /* still some type unsafety issues in marshal wrappers... (unknown is PtrToStructure) */
7259         dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE;
7260         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_UNKNOWN;
7261         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED;
7262         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_STELEMREF;
7263
7264         image = method->klass->image;
7265         header = mono_method_get_header_checked (method, &cfg->error);
7266         if (!header) {
7267                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
7268                 goto exception_exit;
7269         } else {
7270                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
7271         }
7272
7273         generic_container = mono_method_get_generic_container (method);
7274         sig = mono_method_signature (method);
7275         num_args = sig->hasthis + sig->param_count;
7276         ip = (unsigned char*)header->code;
7277         cfg->cil_start = ip;
7278         end = ip + header->code_size;
7279         cfg->stat_cil_code_size += header->code_size;
7280
7281         seq_points = cfg->gen_seq_points && cfg->method == method;
7282
7283         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
7284                 /* We could hit a seq point before attaching to the JIT (#8338) */
7285                 seq_points = FALSE;
7286         }
7287
7288         if (cfg->gen_sdb_seq_points && cfg->method == method) {
7289                 minfo = mono_debug_lookup_method (method);
7290                 if (minfo) {
7291                         MonoSymSeqPoint *sps;
7292                         int i, n_il_offsets;
7293
7294                         mono_debug_get_seq_points (minfo, NULL, NULL, NULL, &sps, &n_il_offsets);
7295                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
7296                         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);
7297                         sym_seq_points = TRUE;
7298                         for (i = 0; i < n_il_offsets; ++i) {
7299                                 if (sps [i].il_offset < header->code_size)
7300                                         mono_bitset_set_fast (seq_point_locs, sps [i].il_offset);
7301                         }
7302                         g_free (sps);
7303
7304                         MonoDebugMethodAsyncInfo* asyncMethod = mono_debug_lookup_method_async_debug_info (method);
7305                         if (asyncMethod) {
7306                                 for (i = 0; asyncMethod != NULL && i < asyncMethod->num_awaits; i++)
7307                                 {
7308                                         mono_bitset_set_fast (seq_point_locs, asyncMethod->resume_offsets[i]);
7309                                         mono_bitset_set_fast (seq_point_locs, asyncMethod->yield_offsets[i]);
7310                                 }
7311                                 mono_debug_free_method_async_debug_info (asyncMethod);
7312                         }
7313                 } else if (!method->wrapper_type && !method->dynamic && mono_debug_image_has_debug_info (method->klass->image)) {
7314                         /* Methods without line number info like auto-generated property accessors */
7315                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
7316                         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);
7317                         sym_seq_points = TRUE;
7318                 }
7319         }
7320
7321         /* 
7322          * Methods without init_locals set could cause asserts in various passes
7323          * (#497220). To work around this, we emit dummy initialization opcodes
7324          * (OP_DUMMY_ICONST etc.) which generate no code. These are only supported
7325          * on some platforms.
7326          */
7327         if ((cfg->opt & MONO_OPT_UNSAFE) && cfg->backend->have_dummy_init)
7328                 init_locals = header->init_locals;
7329         else
7330                 init_locals = TRUE;
7331
7332         method_definition = method;
7333         while (method_definition->is_inflated) {
7334                 MonoMethodInflated *imethod = (MonoMethodInflated *) method_definition;
7335                 method_definition = imethod->declaring;
7336         }
7337
7338         /* SkipVerification is not allowed if core-clr is enabled */
7339         if (!dont_verify && mini_assembly_can_skip_verification (cfg->domain, method)) {
7340                 dont_verify = TRUE;
7341                 dont_verify_stloc = TRUE;
7342         }
7343
7344         if (sig->is_inflated)
7345                 generic_context = mono_method_get_context (method);
7346         else if (generic_container)
7347                 generic_context = &generic_container->context;
7348         cfg->generic_context = generic_context;
7349
7350         if (!cfg->gshared)
7351                 g_assert (!sig->has_type_parameters);
7352
7353         if (sig->generic_param_count && method->wrapper_type == MONO_WRAPPER_NONE) {
7354                 g_assert (method->is_inflated);
7355                 g_assert (mono_method_get_context (method)->method_inst);
7356         }
7357         if (method->is_inflated && mono_method_get_context (method)->method_inst)
7358                 g_assert (sig->generic_param_count);
7359
7360         if (cfg->method == method) {
7361                 cfg->real_offset = 0;
7362         } else {
7363                 cfg->real_offset = inline_offset;
7364         }
7365
7366         cfg->cil_offset_to_bb = (MonoBasicBlock **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoBasicBlock*) * header->code_size);
7367         cfg->cil_offset_to_bb_len = header->code_size;
7368
7369         cfg->current_method = method;
7370
7371         if (cfg->verbose_level > 2)
7372                 printf ("method to IR %s\n", mono_method_full_name (method, TRUE));
7373
7374         param_types = (MonoType **)mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * num_args);
7375         if (sig->hasthis)
7376                 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
7377         for (n = 0; n < sig->param_count; ++n)
7378                 param_types [n + sig->hasthis] = sig->params [n];
7379         cfg->arg_types = param_types;
7380
7381         cfg->dont_inline = g_list_prepend (cfg->dont_inline, method);
7382         if (cfg->method == method) {
7383
7384                 cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
7385
7386                 /* ENTRY BLOCK */
7387                 NEW_BBLOCK (cfg, start_bblock);
7388                 cfg->bb_entry = start_bblock;
7389                 start_bblock->cil_code = NULL;
7390                 start_bblock->cil_length = 0;
7391
7392                 /* EXIT BLOCK */
7393                 NEW_BBLOCK (cfg, end_bblock);
7394                 cfg->bb_exit = end_bblock;
7395                 end_bblock->cil_code = NULL;
7396                 end_bblock->cil_length = 0;
7397                 end_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
7398                 g_assert (cfg->num_bblocks == 2);
7399
7400                 arg_array = cfg->args;
7401
7402                 if (header->num_clauses) {
7403                         cfg->spvars = g_hash_table_new (NULL, NULL);
7404                         cfg->exvars = g_hash_table_new (NULL, NULL);
7405                 }
7406                 /* handle exception clauses */
7407                 for (i = 0; i < header->num_clauses; ++i) {
7408                         MonoBasicBlock *try_bb;
7409                         MonoExceptionClause *clause = &header->clauses [i];
7410                         GET_BBLOCK (cfg, try_bb, ip + clause->try_offset);
7411
7412                         try_bb->real_offset = clause->try_offset;
7413                         try_bb->try_start = TRUE;
7414                         try_bb->region = ((i + 1) << 8) | clause->flags;
7415                         GET_BBLOCK (cfg, tblock, ip + clause->handler_offset);
7416                         tblock->real_offset = clause->handler_offset;
7417                         tblock->flags |= BB_EXCEPTION_HANDLER;
7418
7419                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY)
7420                                 mono_create_exvar_for_offset (cfg, clause->handler_offset);
7421                         /*
7422                          * Linking the try block with the EH block hinders inlining as we won't be able to 
7423                          * merge the bblocks from inlining and produce an artificial hole for no good reason.
7424                          */
7425                         if (COMPILE_LLVM (cfg))
7426                                 link_bblock (cfg, try_bb, tblock);
7427
7428                         if (*(ip + clause->handler_offset) == CEE_POP)
7429                                 tblock->flags |= BB_EXCEPTION_DEAD_OBJ;
7430
7431                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
7432                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER ||
7433                             clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
7434                                 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
7435                                 MONO_ADD_INS (tblock, ins);
7436
7437                                 if (seq_points && clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY && clause->flags != MONO_EXCEPTION_CLAUSE_FILTER) {
7438                                         /* finally clauses already have a seq point */
7439                                         /* seq points for filter clauses are emitted below */
7440                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
7441                                         MONO_ADD_INS (tblock, ins);
7442                                 }
7443
7444                                 /* todo: is a fault block unsafe to optimize? */
7445                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
7446                                         tblock->flags |= BB_EXCEPTION_UNSAFE;
7447                         }
7448
7449                         /*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);
7450                           while (p < end) {
7451                           printf ("%s", mono_disasm_code_one (NULL, method, p, &p));
7452                           }*/
7453                         /* catch and filter blocks get the exception object on the stack */
7454                         if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
7455                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
7456
7457                                 /* mostly like handle_stack_args (), but just sets the input args */
7458                                 /* printf ("handling clause at IL_%04x\n", clause->handler_offset); */
7459                                 tblock->in_scount = 1;
7460                                 tblock->in_stack = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
7461                                 tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
7462
7463                                 cfg->cbb = tblock;
7464
7465 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
7466                                 /* The EH code passes in the exception in a register to both JITted and LLVM compiled code */
7467                                 if (!cfg->compile_llvm) {
7468                                         MONO_INST_NEW (cfg, ins, OP_GET_EX_OBJ);
7469                                         ins->dreg = tblock->in_stack [0]->dreg;
7470                                         MONO_ADD_INS (tblock, ins);
7471                                 }
7472 #else
7473                                 MonoInst *dummy_use;
7474
7475                                 /* 
7476                                  * Add a dummy use for the exvar so its liveness info will be
7477                                  * correct.
7478                                  */
7479                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, tblock->in_stack [0]);
7480 #endif
7481
7482                                 if (seq_points && clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
7483                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
7484                                         MONO_ADD_INS (tblock, ins);
7485                                 }
7486                                 
7487                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
7488                                         GET_BBLOCK (cfg, tblock, ip + clause->data.filter_offset);
7489                                         tblock->flags |= BB_EXCEPTION_HANDLER;
7490                                         tblock->real_offset = clause->data.filter_offset;
7491                                         tblock->in_scount = 1;
7492                                         tblock->in_stack = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
7493                                         /* The filter block shares the exvar with the handler block */
7494                                         tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
7495                                         MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
7496                                         MONO_ADD_INS (tblock, ins);
7497                                 }
7498                         }
7499
7500                         if (clause->flags != MONO_EXCEPTION_CLAUSE_FILTER &&
7501                                         clause->data.catch_class &&
7502                                         cfg->gshared &&
7503                                         mono_class_check_context_used (clause->data.catch_class)) {
7504                                 /*
7505                                  * In shared generic code with catch
7506                                  * clauses containing type variables
7507                                  * the exception handling code has to
7508                                  * be able to get to the rgctx.
7509                                  * Therefore we have to make sure that
7510                                  * the vtable/mrgctx argument (for
7511                                  * static or generic methods) or the
7512                                  * "this" argument (for non-static
7513                                  * methods) are live.
7514                                  */
7515                                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
7516                                                 mini_method_get_context (method)->method_inst ||
7517                                                 method->klass->valuetype) {
7518                                         mono_get_vtable_var (cfg);
7519                                 } else {
7520                                         MonoInst *dummy_use;
7521
7522                                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, arg_array [0]);
7523                                 }
7524                         }
7525                 }
7526         } else {
7527                 arg_array = (MonoInst **) alloca (sizeof (MonoInst *) * num_args);
7528                 cfg->cbb = start_bblock;
7529                 cfg->args = arg_array;
7530                 mono_save_args (cfg, sig, inline_args);
7531         }
7532
7533         /* FIRST CODE BLOCK */
7534         NEW_BBLOCK (cfg, tblock);
7535         tblock->cil_code = ip;
7536         cfg->cbb = tblock;
7537         cfg->ip = ip;
7538
7539         ADD_BBLOCK (cfg, tblock);
7540
7541         if (cfg->method == method) {
7542                 breakpoint_id = mono_debugger_method_has_breakpoint (method);
7543                 if (breakpoint_id) {
7544                         MONO_INST_NEW (cfg, ins, OP_BREAK);
7545                         MONO_ADD_INS (cfg->cbb, ins);
7546                 }
7547         }
7548
7549         /* we use a separate basic block for the initialization code */
7550         NEW_BBLOCK (cfg, init_localsbb);
7551         if (cfg->method == method)
7552                 cfg->bb_init = init_localsbb;
7553         init_localsbb->real_offset = cfg->real_offset;
7554         start_bblock->next_bb = init_localsbb;
7555         init_localsbb->next_bb = cfg->cbb;
7556         link_bblock (cfg, start_bblock, init_localsbb);
7557         link_bblock (cfg, init_localsbb, cfg->cbb);
7558                 
7559         cfg->cbb = init_localsbb;
7560
7561         if (cfg->gsharedvt && cfg->method == method) {
7562                 MonoGSharedVtMethodInfo *info;
7563                 MonoInst *var, *locals_var;
7564                 int dreg;
7565
7566                 info = (MonoGSharedVtMethodInfo *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoGSharedVtMethodInfo));
7567                 info->method = cfg->method;
7568                 info->count_entries = 16;
7569                 info->entries = (MonoRuntimeGenericContextInfoTemplate *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
7570                 cfg->gsharedvt_info = info;
7571
7572                 var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
7573                 /* prevent it from being register allocated */
7574                 //var->flags |= MONO_INST_VOLATILE;
7575                 cfg->gsharedvt_info_var = var;
7576
7577                 ins = emit_get_rgctx_gsharedvt_method (cfg, mini_method_check_context_used (cfg, method), method, info);
7578                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, var->dreg, ins->dreg);
7579
7580                 /* Allocate locals */
7581                 locals_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
7582                 /* prevent it from being register allocated */
7583                 //locals_var->flags |= MONO_INST_VOLATILE;
7584                 cfg->gsharedvt_locals_var = locals_var;
7585
7586                 dreg = alloc_ireg (cfg);
7587                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, dreg, var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, locals_size));
7588
7589                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
7590                 ins->dreg = locals_var->dreg;
7591                 ins->sreg1 = dreg;
7592                 MONO_ADD_INS (cfg->cbb, ins);
7593                 cfg->gsharedvt_locals_var_ins = ins;
7594                 
7595                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
7596                 /*
7597                 if (init_locals)
7598                         ins->flags |= MONO_INST_INIT;
7599                 */
7600         }
7601
7602         if (mono_security_core_clr_enabled ()) {
7603                 /* check if this is native code, e.g. an icall or a p/invoke */
7604                 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
7605                         MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
7606                         if (wrapped) {
7607                                 gboolean pinvk = (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL);
7608                                 gboolean icall = (wrapped->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL);
7609
7610                                 /* if this ia a native call then it can only be JITted from platform code */
7611                                 if ((icall || pinvk) && method->klass && method->klass->image) {
7612                                         if (!mono_security_core_clr_is_platform_image (method->klass->image)) {
7613                                                 MonoException *ex = icall ? mono_get_exception_security () : 
7614                                                         mono_get_exception_method_access ();
7615                                                 emit_throw_exception (cfg, ex);
7616                                         }
7617                                 }
7618                         }
7619                 }
7620         }
7621
7622         CHECK_CFG_EXCEPTION;
7623
7624         if (header->code_size == 0)
7625                 UNVERIFIED;
7626
7627         if (get_basic_blocks (cfg, header, cfg->real_offset, ip, end, &err_pos)) {
7628                 ip = err_pos;
7629                 UNVERIFIED;
7630         }
7631
7632         if (cfg->method == method)
7633                 mono_debug_init_method (cfg, cfg->cbb, breakpoint_id);
7634
7635         for (n = 0; n < header->num_locals; ++n) {
7636                 if (header->locals [n]->type == MONO_TYPE_VOID && !header->locals [n]->byref)
7637                         UNVERIFIED;
7638         }
7639         class_inits = NULL;
7640
7641         /* We force the vtable variable here for all shared methods
7642            for the possibility that they might show up in a stack
7643            trace where their exact instantiation is needed. */
7644         if (cfg->gshared && method == cfg->method) {
7645                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
7646                                 mini_method_get_context (method)->method_inst ||
7647                                 method->klass->valuetype) {
7648                         mono_get_vtable_var (cfg);
7649                 } else {
7650                         /* FIXME: Is there a better way to do this?
7651                            We need the variable live for the duration
7652                            of the whole method. */
7653                         cfg->args [0]->flags |= MONO_INST_VOLATILE;
7654                 }
7655         }
7656
7657         /* add a check for this != NULL to inlined methods */
7658         if (is_virtual_call) {
7659                 MonoInst *arg_ins;
7660
7661                 NEW_ARGLOAD (cfg, arg_ins, 0);
7662                 MONO_ADD_INS (cfg->cbb, arg_ins);
7663                 MONO_EMIT_NEW_CHECK_THIS (cfg, arg_ins->dreg);
7664         }
7665
7666         skip_dead_blocks = !dont_verify;
7667         if (skip_dead_blocks) {
7668                 original_bb = bb = mono_basic_block_split (method, &cfg->error, header);
7669                 CHECK_CFG_ERROR;
7670                 g_assert (bb);
7671         }
7672
7673         /* we use a spare stack slot in SWITCH and NEWOBJ and others */
7674         stack_start = sp = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
7675
7676         ins_flag = 0;
7677         start_new_bblock = 0;
7678         while (ip < end) {
7679                 if (cfg->method == method)
7680                         cfg->real_offset = ip - header->code;
7681                 else
7682                         cfg->real_offset = inline_offset;
7683                 cfg->ip = ip;
7684
7685                 context_used = 0;
7686
7687                 if (start_new_bblock) {
7688                         cfg->cbb->cil_length = ip - cfg->cbb->cil_code;
7689                         if (start_new_bblock == 2) {
7690                                 g_assert (ip == tblock->cil_code);
7691                         } else {
7692                                 GET_BBLOCK (cfg, tblock, ip);
7693                         }
7694                         cfg->cbb->next_bb = tblock;
7695                         cfg->cbb = tblock;
7696                         start_new_bblock = 0;
7697                         for (i = 0; i < cfg->cbb->in_scount; ++i) {
7698                                 if (cfg->verbose_level > 3)
7699                                         printf ("loading %d from temp %d\n", i, (int)cfg->cbb->in_stack [i]->inst_c0);
7700                                 EMIT_NEW_TEMPLOAD (cfg, ins, cfg->cbb->in_stack [i]->inst_c0);
7701                                 *sp++ = ins;
7702                         }
7703                         if (class_inits)
7704                                 g_slist_free (class_inits);
7705                         class_inits = NULL;
7706                 } else {
7707                         if ((tblock = cfg->cil_offset_to_bb [ip - cfg->cil_start]) && (tblock != cfg->cbb)) {
7708                                 link_bblock (cfg, cfg->cbb, tblock);
7709                                 if (sp != stack_start) {
7710                                         handle_stack_args (cfg, stack_start, sp - stack_start);
7711                                         sp = stack_start;
7712                                         CHECK_UNVERIFIABLE (cfg);
7713                                 }
7714                                 cfg->cbb->next_bb = tblock;
7715                                 cfg->cbb = tblock;
7716                                 for (i = 0; i < cfg->cbb->in_scount; ++i) {
7717                                         if (cfg->verbose_level > 3)
7718                                                 printf ("loading %d from temp %d\n", i, (int)cfg->cbb->in_stack [i]->inst_c0);
7719                                         EMIT_NEW_TEMPLOAD (cfg, ins, cfg->cbb->in_stack [i]->inst_c0);
7720                                         *sp++ = ins;
7721                                 }
7722                                 g_slist_free (class_inits);
7723                                 class_inits = NULL;
7724                         }
7725                 }
7726
7727                 if (skip_dead_blocks) {
7728                         int ip_offset = ip - header->code;
7729
7730                         if (ip_offset == bb->end)
7731                                 bb = bb->next;
7732
7733                         if (bb->dead) {
7734                                 int op_size = mono_opcode_size (ip, end);
7735                                 g_assert (op_size > 0); /*The BB formation pass must catch all bad ops*/
7736
7737                                 if (cfg->verbose_level > 3) printf ("SKIPPING DEAD OP at %x\n", ip_offset);
7738
7739                                 if (ip_offset + op_size == bb->end) {
7740                                         MONO_INST_NEW (cfg, ins, OP_NOP);
7741                                         MONO_ADD_INS (cfg->cbb, ins);
7742                                         start_new_bblock = 1;
7743                                 }
7744
7745                                 ip += op_size;
7746                                 continue;
7747                         }
7748                 }
7749                 /*
7750                  * Sequence points are points where the debugger can place a breakpoint.
7751                  * Currently, we generate these automatically at points where the IL
7752                  * stack is empty.
7753                  */
7754                 if (seq_points && ((!sym_seq_points && (sp == stack_start)) || (sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code)))) {
7755                         /*
7756                          * Make methods interruptable at the beginning, and at the targets of
7757                          * backward branches.
7758                          * Also, do this at the start of every bblock in methods with clauses too,
7759                          * to be able to handle instructions with inprecise control flow like
7760                          * throw/endfinally.
7761                          * Backward branches are handled at the end of method-to-ir ().
7762                          */
7763                         gboolean intr_loc = ip == header->code || (!cfg->cbb->last_ins && cfg->header->num_clauses);
7764                         gboolean sym_seq_point = sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code);
7765
7766                         /* Avoid sequence points on empty IL like .volatile */
7767                         // FIXME: Enable this
7768                         //if (!(cfg->cbb->last_ins && cfg->cbb->last_ins->opcode == OP_SEQ_POINT)) {
7769                         NEW_SEQ_POINT (cfg, ins, ip - header->code, intr_loc);
7770                         if ((sp != stack_start) && !sym_seq_point)
7771                                 ins->flags |= MONO_INST_NONEMPTY_STACK;
7772                         MONO_ADD_INS (cfg->cbb, ins);
7773
7774                         if (sym_seq_points)
7775                                 mono_bitset_set_fast (seq_point_set_locs, ip - header->code);
7776                 }
7777
7778                 cfg->cbb->real_offset = cfg->real_offset;
7779
7780                 if ((cfg->method == method) && cfg->coverage_info) {
7781                         guint32 cil_offset = ip - header->code;
7782                         gpointer counter = &cfg->coverage_info->data [cil_offset].count;
7783                         cfg->coverage_info->data [cil_offset].cil_code = ip;
7784
7785                         if (mono_arch_opcode_supported (OP_ATOMIC_ADD_I4)) {
7786                                 MonoInst *one_ins, *load_ins;
7787
7788                                 EMIT_NEW_PCONST (cfg, load_ins, counter);
7789                                 EMIT_NEW_ICONST (cfg, one_ins, 1);
7790                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_ADD_I4);
7791                                 ins->dreg = mono_alloc_ireg (cfg);
7792                                 ins->inst_basereg = load_ins->dreg;
7793                                 ins->inst_offset = 0;
7794                                 ins->sreg2 = one_ins->dreg;
7795                                 ins->type = STACK_I4;
7796                                 MONO_ADD_INS (cfg->cbb, ins);
7797                         } else {
7798                                 EMIT_NEW_PCONST (cfg, ins, counter);
7799                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, ins->dreg, 0, 1);
7800                         }
7801                 }
7802
7803                 if (cfg->verbose_level > 3)
7804                         printf ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
7805
7806                 switch (*ip) {
7807                 case CEE_NOP:
7808                         if (seq_points && !sym_seq_points && sp != stack_start) {
7809                                 /*
7810                                  * The C# compiler uses these nops to notify the JIT that it should
7811                                  * insert seq points.
7812                                  */
7813                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, FALSE);
7814                                 MONO_ADD_INS (cfg->cbb, ins);
7815                         }
7816                         if (cfg->keep_cil_nops)
7817                                 MONO_INST_NEW (cfg, ins, OP_HARD_NOP);
7818                         else
7819                                 MONO_INST_NEW (cfg, ins, OP_NOP);
7820                         ip++;
7821                         MONO_ADD_INS (cfg->cbb, ins);
7822                         break;
7823                 case CEE_BREAK:
7824                         if (mini_should_insert_breakpoint (cfg->method)) {
7825                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
7826                         } else {
7827                                 MONO_INST_NEW (cfg, ins, OP_NOP);
7828                         }
7829                         ip++;
7830                         MONO_ADD_INS (cfg->cbb, ins);
7831                         break;
7832                 case CEE_LDARG_0:
7833                 case CEE_LDARG_1:
7834                 case CEE_LDARG_2:
7835                 case CEE_LDARG_3:
7836                         CHECK_STACK_OVF (1);
7837                         n = (*ip)-CEE_LDARG_0;
7838                         CHECK_ARG (n);
7839                         EMIT_NEW_ARGLOAD (cfg, ins, n);
7840                         ip++;
7841                         *sp++ = ins;
7842                         break;
7843                 case CEE_LDLOC_0:
7844                 case CEE_LDLOC_1:
7845                 case CEE_LDLOC_2:
7846                 case CEE_LDLOC_3:
7847                         CHECK_STACK_OVF (1);
7848                         n = (*ip)-CEE_LDLOC_0;
7849                         CHECK_LOCAL (n);
7850                         EMIT_NEW_LOCLOAD (cfg, ins, n);
7851                         ip++;
7852                         *sp++ = ins;
7853                         break;
7854                 case CEE_STLOC_0:
7855                 case CEE_STLOC_1:
7856                 case CEE_STLOC_2:
7857                 case CEE_STLOC_3: {
7858                         CHECK_STACK (1);
7859                         n = (*ip)-CEE_STLOC_0;
7860                         CHECK_LOCAL (n);
7861                         --sp;
7862                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
7863                                 UNVERIFIED;
7864                         emit_stloc_ir (cfg, sp, header, n);
7865                         ++ip;
7866                         inline_costs += 1;
7867                         break;
7868                         }
7869                 case CEE_LDARG_S:
7870                         CHECK_OPSIZE (2);
7871                         CHECK_STACK_OVF (1);
7872                         n = ip [1];
7873                         CHECK_ARG (n);
7874                         EMIT_NEW_ARGLOAD (cfg, ins, n);
7875                         *sp++ = ins;
7876                         ip += 2;
7877                         break;
7878                 case CEE_LDARGA_S:
7879                         CHECK_OPSIZE (2);
7880                         CHECK_STACK_OVF (1);
7881                         n = ip [1];
7882                         CHECK_ARG (n);
7883                         NEW_ARGLOADA (cfg, ins, n);
7884                         MONO_ADD_INS (cfg->cbb, ins);
7885                         *sp++ = ins;
7886                         ip += 2;
7887                         break;
7888                 case CEE_STARG_S:
7889                         CHECK_OPSIZE (2);
7890                         CHECK_STACK (1);
7891                         --sp;
7892                         n = ip [1];
7893                         CHECK_ARG (n);
7894                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [ip [1]], *sp))
7895                                 UNVERIFIED;
7896                         emit_starg_ir (cfg, sp, n);
7897                         ip += 2;
7898                         break;
7899                 case CEE_LDLOC_S:
7900                         CHECK_OPSIZE (2);
7901                         CHECK_STACK_OVF (1);
7902                         n = ip [1];
7903                         CHECK_LOCAL (n);
7904                         if ((ip [2] == CEE_LDFLD) && ip_in_bb (cfg, cfg->cbb, ip + 2) && MONO_TYPE_ISSTRUCT (header->locals [n])) {
7905                                 /* Avoid loading a struct just to load one of its fields */
7906                                 EMIT_NEW_LOCLOADA (cfg, ins, n);
7907                         } else {
7908                                 EMIT_NEW_LOCLOAD (cfg, ins, n);
7909                         }
7910                         *sp++ = ins;
7911                         ip += 2;
7912                         break;
7913                 case CEE_LDLOCA_S: {
7914                         unsigned char *tmp_ip;
7915                         CHECK_OPSIZE (2);
7916                         CHECK_STACK_OVF (1);
7917                         CHECK_LOCAL (ip [1]);
7918
7919                         if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 1))) {
7920                                 ip = tmp_ip;
7921                                 inline_costs += 1;
7922                                 break;
7923                         }
7924
7925                         EMIT_NEW_LOCLOADA (cfg, ins, ip [1]);
7926                         *sp++ = ins;
7927                         ip += 2;
7928                         break;
7929                 }
7930                 case CEE_STLOC_S:
7931                         CHECK_OPSIZE (2);
7932                         CHECK_STACK (1);
7933                         --sp;
7934                         CHECK_LOCAL (ip [1]);
7935                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [ip [1]], *sp))
7936                                 UNVERIFIED;
7937                         emit_stloc_ir (cfg, sp, header, ip [1]);
7938                         ip += 2;
7939                         inline_costs += 1;
7940                         break;
7941                 case CEE_LDNULL:
7942                         CHECK_STACK_OVF (1);
7943                         EMIT_NEW_PCONST (cfg, ins, NULL);
7944                         ins->type = STACK_OBJ;
7945                         ++ip;
7946                         *sp++ = ins;
7947                         break;
7948                 case CEE_LDC_I4_M1:
7949                         CHECK_STACK_OVF (1);
7950                         EMIT_NEW_ICONST (cfg, ins, -1);
7951                         ++ip;
7952                         *sp++ = ins;
7953                         break;
7954                 case CEE_LDC_I4_0:
7955                 case CEE_LDC_I4_1:
7956                 case CEE_LDC_I4_2:
7957                 case CEE_LDC_I4_3:
7958                 case CEE_LDC_I4_4:
7959                 case CEE_LDC_I4_5:
7960                 case CEE_LDC_I4_6:
7961                 case CEE_LDC_I4_7:
7962                 case CEE_LDC_I4_8:
7963                         CHECK_STACK_OVF (1);
7964                         EMIT_NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
7965                         ++ip;
7966                         *sp++ = ins;
7967                         break;
7968                 case CEE_LDC_I4_S:
7969                         CHECK_OPSIZE (2);
7970                         CHECK_STACK_OVF (1);
7971                         ++ip;
7972                         EMIT_NEW_ICONST (cfg, ins, *((signed char*)ip));
7973                         ++ip;
7974                         *sp++ = ins;
7975                         break;
7976                 case CEE_LDC_I4:
7977                         CHECK_OPSIZE (5);
7978                         CHECK_STACK_OVF (1);
7979                         EMIT_NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
7980                         ip += 5;
7981                         *sp++ = ins;
7982                         break;
7983                 case CEE_LDC_I8:
7984                         CHECK_OPSIZE (9);
7985                         CHECK_STACK_OVF (1);
7986                         MONO_INST_NEW (cfg, ins, OP_I8CONST);
7987                         ins->type = STACK_I8;
7988                         ins->dreg = alloc_dreg (cfg, STACK_I8);
7989                         ++ip;
7990                         ins->inst_l = (gint64)read64 (ip);
7991                         MONO_ADD_INS (cfg->cbb, ins);
7992                         ip += 8;
7993                         *sp++ = ins;
7994                         break;
7995                 case CEE_LDC_R4: {
7996                         float *f;
7997                         gboolean use_aotconst = FALSE;
7998
7999 #ifdef TARGET_POWERPC
8000                         /* FIXME: Clean this up */
8001                         if (cfg->compile_aot)
8002                                 use_aotconst = TRUE;
8003 #endif
8004
8005                         /* FIXME: we should really allocate this only late in the compilation process */
8006                         f = (float *)mono_domain_alloc (cfg->domain, sizeof (float));
8007                         CHECK_OPSIZE (5);
8008                         CHECK_STACK_OVF (1);
8009
8010                         if (use_aotconst) {
8011                                 MonoInst *cons;
8012                                 int dreg;
8013
8014                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R4, f);
8015
8016                                 dreg = alloc_freg (cfg);
8017                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR4_MEMBASE, dreg, cons->dreg, 0);
8018                                 ins->type = cfg->r4_stack_type;
8019                         } else {
8020                                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
8021                                 ins->type = cfg->r4_stack_type;
8022                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8023                                 ins->inst_p0 = f;
8024                                 MONO_ADD_INS (cfg->cbb, ins);
8025                         }
8026                         ++ip;
8027                         readr4 (ip, f);
8028                         ip += 4;
8029                         *sp++ = ins;                    
8030                         break;
8031                 }
8032                 case CEE_LDC_R8: {
8033                         double *d;
8034                         gboolean use_aotconst = FALSE;
8035
8036 #ifdef TARGET_POWERPC
8037                         /* FIXME: Clean this up */
8038                         if (cfg->compile_aot)
8039                                 use_aotconst = TRUE;
8040 #endif
8041
8042                         /* FIXME: we should really allocate this only late in the compilation process */
8043                         d = (double *)mono_domain_alloc (cfg->domain, sizeof (double));
8044                         CHECK_OPSIZE (9);
8045                         CHECK_STACK_OVF (1);
8046
8047                         if (use_aotconst) {
8048                                 MonoInst *cons;
8049                                 int dreg;
8050
8051                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R8, d);
8052
8053                                 dreg = alloc_freg (cfg);
8054                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR8_MEMBASE, dreg, cons->dreg, 0);
8055                                 ins->type = STACK_R8;
8056                         } else {
8057                                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
8058                                 ins->type = STACK_R8;
8059                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8060                                 ins->inst_p0 = d;
8061                                 MONO_ADD_INS (cfg->cbb, ins);
8062                         }
8063                         ++ip;
8064                         readr8 (ip, d);
8065                         ip += 8;
8066                         *sp++ = ins;
8067                         break;
8068                 }
8069                 case CEE_DUP: {
8070                         MonoInst *temp, *store;
8071                         CHECK_STACK (1);
8072                         CHECK_STACK_OVF (1);
8073                         sp--;
8074                         ins = *sp;
8075
8076                         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
8077                         EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
8078
8079                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8080                         *sp++ = ins;
8081
8082                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8083                         *sp++ = ins;
8084
8085                         ++ip;
8086                         inline_costs += 2;
8087                         break;
8088                 }
8089                 case CEE_POP:
8090                         CHECK_STACK (1);
8091                         ip++;
8092                         --sp;
8093
8094 #ifdef TARGET_X86
8095                         if (sp [0]->type == STACK_R8)
8096                                 /* we need to pop the value from the x86 FP stack */
8097                                 MONO_EMIT_NEW_UNALU (cfg, OP_X86_FPOP, -1, sp [0]->dreg);
8098 #endif
8099                         break;
8100                 case CEE_JMP: {
8101                         MonoCallInst *call;
8102                         MonoMethodSignature *fsig;
8103                         int i, n;
8104
8105                         INLINE_FAILURE ("jmp");
8106                         GSHAREDVT_FAILURE (*ip);
8107
8108                         CHECK_OPSIZE (5);
8109                         if (stack_start != sp)
8110                                 UNVERIFIED;
8111                         token = read32 (ip + 1);
8112                         /* FIXME: check the signature matches */
8113                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
8114                         CHECK_CFG_ERROR;
8115  
8116                         if (cfg->gshared && mono_method_check_context_used (cmethod))
8117                                 GENERIC_SHARING_FAILURE (CEE_JMP);
8118
8119                         mini_profiler_emit_tail_call (cfg, cmethod);
8120
8121                         fsig = mono_method_signature (cmethod);
8122                         n = fsig->param_count + fsig->hasthis;
8123                         if (cfg->llvm_only) {
8124                                 MonoInst **args;
8125
8126                                 args = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
8127                                 for (i = 0; i < n; ++i)
8128                                         EMIT_NEW_ARGLOAD (cfg, args [i], i);
8129                                 ins = mono_emit_method_call_full (cfg, cmethod, fsig, TRUE, args, NULL, NULL, NULL);
8130                                 /*
8131                                  * The code in mono-basic-block.c treats the rest of the code as dead, but we
8132                                  * have to emit a normal return since llvm expects it.
8133                                  */
8134                                 if (cfg->ret)
8135                                         emit_setret (cfg, ins);
8136                                 MONO_INST_NEW (cfg, ins, OP_BR);
8137                                 ins->inst_target_bb = end_bblock;
8138                                 MONO_ADD_INS (cfg->cbb, ins);
8139                                 link_bblock (cfg, cfg->cbb, end_bblock);
8140                                 ip += 5;
8141                                 break;
8142                         } else if (cfg->backend->have_op_tail_call) {
8143                                 /* Handle tail calls similarly to calls */
8144                                 DISABLE_AOT (cfg);
8145
8146                                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
8147                                 call->method = cmethod;
8148                                 call->tail_call = TRUE;
8149                                 call->signature = mono_method_signature (cmethod);
8150                                 call->args = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
8151                                 call->inst.inst_p0 = cmethod;
8152                                 for (i = 0; i < n; ++i)
8153                                         EMIT_NEW_ARGLOAD (cfg, call->args [i], i);
8154
8155                                 if (mini_type_is_vtype (mini_get_underlying_type (call->signature->ret)))
8156                                         call->vret_var = cfg->vret_addr;
8157
8158                                 mono_arch_emit_call (cfg, call);
8159                                 cfg->param_area = MAX(cfg->param_area, call->stack_usage);
8160                                 MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
8161                         } else {
8162                                 for (i = 0; i < num_args; ++i)
8163                                         /* Prevent arguments from being optimized away */
8164                                         arg_array [i]->flags |= MONO_INST_VOLATILE;
8165
8166                                 MONO_INST_NEW_CALL (cfg, call, OP_JMP);
8167                                 ins = (MonoInst*)call;
8168                                 ins->inst_p0 = cmethod;
8169                                 MONO_ADD_INS (cfg->cbb, ins);
8170                         }
8171
8172                         ip += 5;
8173                         start_new_bblock = 1;
8174                         break;
8175                 }
8176                 case CEE_CALLI: {
8177                         MonoInst *addr;
8178                         MonoMethodSignature *fsig;
8179
8180                         CHECK_OPSIZE (5);
8181                         token = read32 (ip + 1);
8182
8183                         ins = NULL;
8184
8185                         //GSHAREDVT_FAILURE (*ip);
8186                         cmethod = NULL;
8187                         CHECK_STACK (1);
8188                         --sp;
8189                         addr = *sp;
8190                         fsig = mini_get_signature (method, token, generic_context, &cfg->error);
8191                         CHECK_CFG_ERROR;
8192
8193                         if (method->dynamic && fsig->pinvoke) {
8194                                 MonoInst *args [3];
8195
8196                                 /*
8197                                  * This is a call through a function pointer using a pinvoke
8198                                  * signature. Have to create a wrapper and call that instead.
8199                                  * FIXME: This is very slow, need to create a wrapper at JIT time
8200                                  * instead based on the signature.
8201                                  */
8202                                 EMIT_NEW_IMAGECONST (cfg, args [0], method->klass->image);
8203                                 EMIT_NEW_PCONST (cfg, args [1], fsig);
8204                                 args [2] = addr;
8205                                 addr = mono_emit_jit_icall (cfg, mono_get_native_calli_wrapper, args);
8206                         }
8207
8208                         n = fsig->param_count + fsig->hasthis;
8209
8210                         CHECK_STACK (n);
8211
8212                         //g_assert (!virtual_ || fsig->hasthis);
8213
8214                         sp -= n;
8215
8216                         inline_costs += 10 * num_calls++;
8217
8218                         /*
8219                          * Making generic calls out of gsharedvt methods.
8220                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
8221                          * patching gshared method addresses into a gsharedvt method.
8222                          */
8223                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
8224                                 /*
8225                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
8226                                  */
8227                                 MonoInst *callee = addr;
8228
8229                                 if (method->wrapper_type != MONO_WRAPPER_DELEGATE_INVOKE)
8230                                         /* Not tested */
8231                                         GSHAREDVT_FAILURE (*ip);
8232
8233                                 if (cfg->llvm_only)
8234                                         // FIXME:
8235                                         GSHAREDVT_FAILURE (*ip);
8236
8237                                 addr = emit_get_rgctx_sig (cfg, context_used,
8238                                                                                           fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
8239                                 ins = (MonoInst*)mini_emit_calli (cfg, fsig, sp, addr, NULL, callee);
8240                                 goto calli_end;
8241                         }
8242
8243                         /* Prevent inlining of methods with indirect calls */
8244                         INLINE_FAILURE ("indirect call");
8245
8246                         if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST || addr->opcode == OP_GOT_ENTRY) {
8247                                 MonoJumpInfoType info_type;
8248                                 gpointer info_data;
8249
8250                                 /*
8251                                  * Instead of emitting an indirect call, emit a direct call
8252                                  * with the contents of the aotconst as the patch info.
8253                                  */
8254                                 if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST) {
8255                                         info_type = (MonoJumpInfoType)addr->inst_c1;
8256                                         info_data = addr->inst_p0;
8257                                 } else {
8258                                         info_type = (MonoJumpInfoType)addr->inst_right->inst_c1;
8259                                         info_data = addr->inst_right->inst_left;
8260                                 }
8261
8262                                 if (info_type == MONO_PATCH_INFO_ICALL_ADDR) {
8263                                         ins = (MonoInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_ICALL_ADDR_CALL, info_data, fsig, sp);
8264                                         NULLIFY_INS (addr);
8265                                         goto calli_end;
8266                                 } else if (info_type == MONO_PATCH_INFO_JIT_ICALL_ADDR) {
8267                                         ins = (MonoInst*)mono_emit_abs_call (cfg, info_type, info_data, fsig, sp);
8268                                         NULLIFY_INS (addr);
8269                                         goto calli_end;
8270                                 }
8271                         }
8272                         ins = (MonoInst*)mini_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8273
8274                         calli_end:
8275
8276                         /* End of call, INS should contain the result of the call, if any */
8277
8278                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8279                                 g_assert (ins);
8280                                 *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
8281                         }
8282
8283                         CHECK_CFG_EXCEPTION;
8284
8285                         ip += 5;
8286                         ins_flag = 0;
8287                         constrained_class = NULL;
8288                         break;
8289                 }
8290                 case CEE_CALL:
8291                 case CEE_CALLVIRT: {
8292                         MonoInst *addr = NULL;
8293                         MonoMethodSignature *fsig = NULL;
8294                         int array_rank = 0;
8295                         int virtual_ = *ip == CEE_CALLVIRT;
8296                         gboolean pass_imt_from_rgctx = FALSE;
8297                         MonoInst *imt_arg = NULL;
8298                         MonoInst *keep_this_alive = NULL;
8299                         gboolean pass_vtable = FALSE;
8300                         gboolean pass_mrgctx = FALSE;
8301                         MonoInst *vtable_arg = NULL;
8302                         gboolean check_this = FALSE;
8303                         gboolean supported_tail_call = FALSE;
8304                         gboolean tail_call = FALSE;
8305                         gboolean need_seq_point = FALSE;
8306                         guint32 call_opcode = *ip;
8307                         gboolean emit_widen = TRUE;
8308                         gboolean push_res = TRUE;
8309                         gboolean skip_ret = FALSE;
8310                         gboolean delegate_invoke = FALSE;
8311                         gboolean direct_icall = FALSE;
8312                         gboolean constrained_partial_call = FALSE;
8313                         MonoMethod *cil_method;
8314
8315                         CHECK_OPSIZE (5);
8316                         token = read32 (ip + 1);
8317
8318                         ins = NULL;
8319
8320                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
8321                         CHECK_CFG_ERROR;
8322
8323                         cil_method = cmethod;
8324                                 
8325                         if (constrained_class) {
8326                                 if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->gshared) {
8327                                         if (!mini_is_gsharedvt_klass (constrained_class)) {
8328                                                 g_assert (!cmethod->klass->valuetype);
8329                                                 if (!mini_type_is_reference (&constrained_class->byval_arg))
8330                                                         constrained_partial_call = TRUE;
8331                                         }
8332                                 }
8333
8334                                 if (method->wrapper_type != MONO_WRAPPER_NONE) {
8335                                         if (cfg->verbose_level > 2)
8336                                                 printf ("DM Constrained call to %s\n", mono_type_get_full_name (constrained_class));
8337                                         if (!((constrained_class->byval_arg.type == MONO_TYPE_VAR ||
8338                                                    constrained_class->byval_arg.type == MONO_TYPE_MVAR) &&
8339                                                   cfg->gshared)) {
8340                                                 cmethod = mono_get_method_constrained_with_method (image, cil_method, constrained_class, generic_context, &cfg->error);
8341                                                 CHECK_CFG_ERROR;
8342                                         }
8343                                 } else {
8344                                         if (cfg->verbose_level > 2)
8345                                                 printf ("Constrained call to %s\n", mono_type_get_full_name (constrained_class));
8346
8347                                         if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->gshared) {
8348                                                 /* 
8349                                                  * This is needed since get_method_constrained can't find 
8350                                                  * the method in klass representing a type var.
8351                                                  * The type var is guaranteed to be a reference type in this
8352                                                  * case.
8353                                                  */
8354                                                 if (!mini_is_gsharedvt_klass (constrained_class))
8355                                                         g_assert (!cmethod->klass->valuetype);
8356                                         } else {
8357                                                 cmethod = mono_get_method_constrained_checked (image, token, constrained_class, generic_context, &cil_method, &cfg->error);
8358                                                 CHECK_CFG_ERROR;
8359                                         }
8360                                 }
8361
8362                                 if (constrained_class->enumtype && !strcmp (cmethod->name, "GetHashCode")) {
8363                                         /* Use the corresponding method from the base type to avoid boxing */
8364                                         MonoType *base_type = mono_class_enum_basetype (constrained_class);
8365                                         g_assert (base_type);
8366                                         constrained_class = mono_class_from_mono_type (base_type);
8367                                         cmethod = mono_class_get_method_from_name (constrained_class, cmethod->name, 0);
8368                                         g_assert (cmethod);
8369                                 }
8370                         }
8371                                         
8372                         if (!dont_verify && !cfg->skip_visibility) {
8373                                 MonoMethod *target_method = cil_method;
8374                                 if (method->is_inflated) {
8375                                         target_method = mini_get_method_allow_open (method, token, NULL, &(mono_method_get_generic_container (method_definition)->context), &cfg->error);
8376                                         CHECK_CFG_ERROR;
8377                                 }
8378                                 if (!mono_method_can_access_method (method_definition, target_method) &&
8379                                         !mono_method_can_access_method (method, cil_method))
8380                                         emit_method_access_failure (cfg, method, cil_method);
8381                         }
8382
8383                         if (mono_security_core_clr_enabled ())
8384                                 ensure_method_is_allowed_to_call_method (cfg, method, cil_method);
8385
8386                         if (!virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
8387                                 /* MS.NET seems to silently convert this to a callvirt */
8388                                 virtual_ = 1;
8389
8390                         {
8391                                 /*
8392                                  * MS.NET accepts non virtual calls to virtual final methods of transparent proxy classes and
8393                                  * converts to a callvirt.
8394                                  *
8395                                  * tests/bug-515884.il is an example of this behavior
8396                                  */
8397                                 const int test_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_STATIC;
8398                                 const int expected_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL;
8399                                 if (!virtual_ && mono_class_is_marshalbyref (cmethod->klass) && (cmethod->flags & test_flags) == expected_flags && cfg->method->wrapper_type == MONO_WRAPPER_NONE)
8400                                         virtual_ = 1;
8401                         }
8402
8403                         if (!cmethod->klass->inited)
8404                                 if (!mono_class_init (cmethod->klass))
8405                                         TYPE_LOAD_ERROR (cmethod->klass);
8406
8407                         fsig = mono_method_signature (cmethod);
8408                         if (!fsig)
8409                                 LOAD_ERROR;
8410                         if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
8411                                 mini_class_is_system_array (cmethod->klass)) {
8412                                 array_rank = cmethod->klass->rank;
8413                         } else if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && icall_is_direct_callable (cfg, cmethod)) {
8414                                 direct_icall = TRUE;
8415                         } else if (fsig->pinvoke) {
8416                                 MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
8417                                 fsig = mono_method_signature (wrapper);
8418                         } else if (constrained_class) {
8419                         } else {
8420                                 fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
8421                                 CHECK_CFG_ERROR;
8422                         }
8423
8424                         if (cfg->llvm_only && !cfg->method->wrapper_type && (!cmethod || cmethod->is_inflated))
8425                                 cfg->signatures = g_slist_prepend_mempool (cfg->mempool, cfg->signatures, fsig);
8426
8427                         /* See code below */
8428                         if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
8429                                 MonoBasicBlock *tbb;
8430
8431                                 GET_BBLOCK (cfg, tbb, ip + 5);
8432                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
8433                                         /*
8434                                          * We want to extend the try block to cover the call, but we can't do it if the
8435                                          * call is made directly since its followed by an exception check.
8436                                          */
8437                                         direct_icall = FALSE;
8438                                 }
8439                         }
8440
8441                         mono_save_token_info (cfg, image, token, cil_method);
8442
8443                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip + 5 - header->code)))
8444                                 need_seq_point = TRUE;
8445
8446                         /* Don't support calls made using type arguments for now */
8447                         /*
8448                           if (cfg->gsharedvt) {
8449                           if (mini_is_gsharedvt_signature (fsig))
8450                           GSHAREDVT_FAILURE (*ip);
8451                           }
8452                         */
8453
8454                         if (cmethod->string_ctor && method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE)
8455                                 g_assert_not_reached ();
8456
8457                         n = fsig->param_count + fsig->hasthis;
8458
8459                         if (!cfg->gshared && mono_class_is_gtd (cmethod->klass))
8460                                 UNVERIFIED;
8461
8462                         if (!cfg->gshared)
8463                                 g_assert (!mono_method_check_context_used (cmethod));
8464
8465                         CHECK_STACK (n);
8466
8467                         //g_assert (!virtual_ || fsig->hasthis);
8468
8469                         sp -= n;
8470
8471                         if (cmethod && cmethod->klass->image == mono_defaults.corlib && !strcmp (cmethod->klass->name, "ThrowHelper"))
8472                                 cfg->cbb->out_of_line = TRUE;
8473
8474                         /*
8475                          * We have the `constrained.' prefix opcode.
8476                          */
8477                         if (constrained_class) {
8478                                 if (mini_is_gsharedvt_klass (constrained_class)) {
8479                                         if ((cmethod->klass != mono_defaults.object_class) && constrained_class->valuetype && cmethod->klass->valuetype) {
8480                                                 /* The 'Own method' case below */
8481                                         } else if (cmethod->klass->image != mono_defaults.corlib && !mono_class_is_interface (cmethod->klass) && !cmethod->klass->valuetype) {
8482                                                 /* 'The type parameter is instantiated as a reference type' case below. */
8483                                         } else {
8484                                                 ins = handle_constrained_gsharedvt_call (cfg, cmethod, fsig, sp, constrained_class, &emit_widen);
8485                                                 CHECK_CFG_EXCEPTION;
8486                                                 g_assert (ins);
8487                                                 goto call_end;
8488                                         }
8489                                 }
8490
8491                                 if (constrained_partial_call) {
8492                                         gboolean need_box = TRUE;
8493
8494                                         /*
8495                                          * The receiver is a valuetype, but the exact type is not known at compile time. This means the
8496                                          * called method is not known at compile time either. The called method could end up being
8497                                          * one of the methods on the parent classes (object/valuetype/enum), in which case we need
8498                                          * to box the receiver.
8499                                          * A simple solution would be to box always and make a normal virtual call, but that would
8500                                          * be bad performance wise.
8501                                          */
8502                                         if (mono_class_is_interface (cmethod->klass) && mono_class_is_ginst (cmethod->klass)) {
8503                                                 /*
8504                                                  * The parent classes implement no generic interfaces, so the called method will be a vtype method, so no boxing neccessary.
8505                                                  */
8506                                                 need_box = FALSE;
8507                                         }
8508
8509                                         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)) {
8510                                                 /* The called method is not virtual, i.e. Object:GetType (), the receiver is a vtype, has to box */
8511                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
8512                                                 ins->klass = constrained_class;
8513                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
8514                                                 CHECK_CFG_EXCEPTION;
8515                                         } else if (need_box) {
8516                                                 MonoInst *box_type;
8517                                                 MonoBasicBlock *is_ref_bb, *end_bb;
8518                                                 MonoInst *nonbox_call;
8519
8520                                                 /*
8521                                                  * Determine at runtime whenever the called method is defined on object/valuetype/enum, and emit a boxing call
8522                                                  * if needed.
8523                                                  * FIXME: It is possible to inline the called method in a lot of cases, i.e. for T_INT,
8524                                                  * the no-box case goes to a method in Int32, while the box case goes to a method in Enum.
8525                                                  */
8526                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
8527
8528                                                 NEW_BBLOCK (cfg, is_ref_bb);
8529                                                 NEW_BBLOCK (cfg, end_bb);
8530
8531                                                 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);
8532                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, box_type->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
8533                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
8534
8535                                                 /* Non-ref case */
8536                                                 nonbox_call = (MonoInst*)mini_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8537
8538                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
8539
8540                                                 /* Ref case */
8541                                                 MONO_START_BB (cfg, is_ref_bb);
8542                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
8543                                                 ins->klass = constrained_class;
8544                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
8545                                                 ins = (MonoInst*)mini_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8546
8547                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
8548
8549                                                 MONO_START_BB (cfg, end_bb);
8550                                                 cfg->cbb = end_bb;
8551
8552                                                 nonbox_call->dreg = ins->dreg;
8553                                                 goto call_end;
8554                                         } else {
8555                                                 g_assert (mono_class_is_interface (cmethod->klass));
8556                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
8557                                                 ins = (MonoInst*)mini_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8558                                                 goto call_end;
8559                                         }
8560                                 } else if (constrained_class->valuetype && (cmethod->klass == mono_defaults.object_class || cmethod->klass == mono_defaults.enum_class->parent || cmethod->klass == mono_defaults.enum_class)) {
8561                                         /*
8562                                          * The type parameter is instantiated as a valuetype,
8563                                          * but that type doesn't override the method we're
8564                                          * calling, so we need to box `this'.
8565                                          */
8566                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
8567                                         ins->klass = constrained_class;
8568                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
8569                                         CHECK_CFG_EXCEPTION;
8570                                 } else if (!constrained_class->valuetype) {
8571                                         int dreg = alloc_ireg_ref (cfg);
8572
8573                                         /*
8574                                          * The type parameter is instantiated as a reference
8575                                          * type.  We have a managed pointer on the stack, so
8576                                          * we need to dereference it here.
8577                                          */
8578                                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, sp [0]->dreg, 0);
8579                                         ins->type = STACK_OBJ;
8580                                         sp [0] = ins;
8581                                 } else {
8582                                         if (cmethod->klass->valuetype) {
8583                                                 /* Own method */
8584                                         } else {
8585                                                 /* Interface method */
8586                                                 int ioffset, slot;
8587
8588                                                 mono_class_setup_vtable (constrained_class);
8589                                                 CHECK_TYPELOAD (constrained_class);
8590                                                 ioffset = mono_class_interface_offset (constrained_class, cmethod->klass);
8591                                                 if (ioffset == -1)
8592                                                         TYPE_LOAD_ERROR (constrained_class);
8593                                                 slot = mono_method_get_vtable_slot (cmethod);
8594                                                 if (slot == -1)
8595                                                         TYPE_LOAD_ERROR (cmethod->klass);
8596                                                 cmethod = constrained_class->vtable [ioffset + slot];
8597
8598                                                 if (cmethod->klass == mono_defaults.enum_class) {
8599                                                         /* Enum implements some interfaces, so treat this as the first case */
8600                                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
8601                                                         ins->klass = constrained_class;
8602                                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
8603                                                         CHECK_CFG_EXCEPTION;
8604                                                 }
8605                                         }
8606                                         virtual_ = 0;
8607                                 }
8608                                 constrained_class = NULL;
8609                         }
8610
8611                         if (check_call_signature (cfg, fsig, sp))
8612                                 UNVERIFIED;
8613
8614                         if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (cmethod->name, "Invoke"))
8615                                 delegate_invoke = TRUE;
8616
8617                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_sharable_method (cfg, cmethod, fsig, sp))) {
8618                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8619                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
8620                                         emit_widen = FALSE;
8621                                 }
8622
8623                                 goto call_end;
8624                         }
8625
8626                         /* 
8627                          * If the callee is a shared method, then its static cctor
8628                          * might not get called after the call was patched.
8629                          */
8630                         if (cfg->gshared && cmethod->klass != method->klass && mono_class_is_ginst (cmethod->klass) && mono_method_is_generic_sharable (cmethod, TRUE) && mono_class_needs_cctor_run (cmethod->klass, method)) {
8631                                 emit_class_init (cfg, cmethod->klass);
8632                                 CHECK_TYPELOAD (cmethod->klass);
8633                         }
8634
8635                         check_method_sharing (cfg, cmethod, &pass_vtable, &pass_mrgctx);
8636
8637                         if (cfg->gshared) {
8638                                 MonoGenericContext *cmethod_context = mono_method_get_context (cmethod);
8639
8640                                 context_used = mini_method_check_context_used (cfg, cmethod);
8641
8642                                 if (context_used && mono_class_is_interface (cmethod->klass)) {
8643                                         /* Generic method interface
8644                                            calls are resolved via a
8645                                            helper function and don't
8646                                            need an imt. */
8647                                         if (!cmethod_context || !cmethod_context->method_inst)
8648                                                 pass_imt_from_rgctx = TRUE;
8649                                 }
8650
8651                                 /*
8652                                  * If a shared method calls another
8653                                  * shared method then the caller must
8654                                  * have a generic sharing context
8655                                  * because the magic trampoline
8656                                  * requires it.  FIXME: We shouldn't
8657                                  * have to force the vtable/mrgctx
8658                                  * variable here.  Instead there
8659                                  * should be a flag in the cfg to
8660                                  * request a generic sharing context.
8661                                  */
8662                                 if (context_used &&
8663                                                 ((cfg->method->flags & METHOD_ATTRIBUTE_STATIC) || cfg->method->klass->valuetype))
8664                                         mono_get_vtable_var (cfg);
8665                         }
8666
8667                         if (pass_vtable) {
8668                                 if (context_used) {
8669                                         vtable_arg = mini_emit_get_rgctx_klass (cfg, context_used, cmethod->klass, MONO_RGCTX_INFO_VTABLE);
8670                                 } else {
8671                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
8672
8673                                         CHECK_TYPELOAD (cmethod->klass);
8674                                         EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
8675                                 }
8676                         }
8677
8678                         if (pass_mrgctx) {
8679                                 g_assert (!vtable_arg);
8680
8681                                 if (!cfg->compile_aot) {
8682                                         /* 
8683                                          * emit_get_rgctx_method () calls mono_class_vtable () so check 
8684                                          * for type load errors before.
8685                                          */
8686                                         mono_class_setup_vtable (cmethod->klass);
8687                                         CHECK_TYPELOAD (cmethod->klass);
8688                                 }
8689
8690                                 vtable_arg = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
8691
8692                                 /* !marshalbyref is needed to properly handle generic methods + remoting */
8693                                 if ((!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
8694                                          MONO_METHOD_IS_FINAL (cmethod)) &&
8695                                         !mono_class_is_marshalbyref (cmethod->klass)) {
8696                                         if (virtual_)
8697                                                 check_this = TRUE;
8698                                         virtual_ = 0;
8699                                 }
8700                         }
8701
8702                         if (pass_imt_from_rgctx) {
8703                                 g_assert (!pass_vtable);
8704
8705                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
8706                                         cmethod, MONO_RGCTX_INFO_METHOD);
8707                         }
8708
8709                         if (check_this)
8710                                 MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
8711
8712                         /* Calling virtual generic methods */
8713                         if (virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) &&
8714                             !(MONO_METHOD_IS_FINAL (cmethod) && 
8715                               cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) &&
8716                             fsig->generic_param_count && 
8717                                 !(cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) &&
8718                                 !cfg->llvm_only) {
8719                                 MonoInst *this_temp, *this_arg_temp, *store;
8720                                 MonoInst *iargs [4];
8721
8722                                 g_assert (fsig->is_inflated);
8723
8724                                 /* Prevent inlining of methods that contain indirect calls */
8725                                 INLINE_FAILURE ("virtual generic call");
8726
8727                                 if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))
8728                                         GSHAREDVT_FAILURE (*ip);
8729
8730                                 if (cfg->backend->have_generalized_imt_trampoline && cfg->backend->gshared_supported && cmethod->wrapper_type == MONO_WRAPPER_NONE) {
8731                                         g_assert (!imt_arg);
8732                                         if (!context_used)
8733                                                 g_assert (cmethod->is_inflated);
8734                                         imt_arg = emit_get_rgctx_method (cfg, context_used,
8735                                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
8736                                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, sp [0], imt_arg, NULL);
8737                                 } else {
8738                                         this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
8739                                         NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
8740                                         MONO_ADD_INS (cfg->cbb, store);
8741
8742                                         /* FIXME: This should be a managed pointer */
8743                                         this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8744
8745                                         EMIT_NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
8746                                         iargs [1] = emit_get_rgctx_method (cfg, context_used,
8747                                                                                                            cmethod, MONO_RGCTX_INFO_METHOD);
8748                                         EMIT_NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
8749                                         addr = mono_emit_jit_icall (cfg,
8750                                                                                                 mono_helper_compile_generic_method, iargs);
8751
8752                                         EMIT_NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
8753
8754                                         ins = (MonoInst*)mini_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8755                                 }
8756
8757                                 goto call_end;
8758                         }
8759
8760                         /*
8761                          * Implement a workaround for the inherent races involved in locking:
8762                          * Monitor.Enter ()
8763                          * try {
8764                          * } finally {
8765                          *    Monitor.Exit ()
8766                          * }
8767                          * If a thread abort happens between the call to Monitor.Enter () and the start of the
8768                          * try block, the Exit () won't be executed, see:
8769                          * http://www.bluebytesoftware.com/blog/2007/01/30/MonitorEnterThreadAbortsAndOrphanedLocks.aspx
8770                          * To work around this, we extend such try blocks to include the last x bytes
8771                          * of the Monitor.Enter () call.
8772                          */
8773                         if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
8774                                 MonoBasicBlock *tbb;
8775
8776                                 GET_BBLOCK (cfg, tbb, ip + 5);
8777                                 /* 
8778                                  * Only extend try blocks with a finally, to avoid catching exceptions thrown
8779                                  * from Monitor.Enter like ArgumentNullException.
8780                                  */
8781                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
8782                                         /* Mark this bblock as needing to be extended */
8783                                         tbb->extend_try_block = TRUE;
8784                                 }
8785                         }
8786
8787                         /* Conversion to a JIT intrinsic */
8788                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_method (cfg, cmethod, fsig, sp))) {
8789                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8790                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
8791                                         emit_widen = FALSE;
8792                                 }
8793                                 goto call_end;
8794                         }
8795                         CHECK_CFG_ERROR;
8796                         
8797                         /* Inlining */
8798                         if ((cfg->opt & MONO_OPT_INLINE) &&
8799                                 (!virtual_ || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || MONO_METHOD_IS_FINAL (cmethod)) &&
8800                             mono_method_check_inlining (cfg, cmethod)) {
8801                                 int costs;
8802                                 gboolean always = FALSE;
8803
8804                                 if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
8805                                         (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
8806                                         /* Prevent inlining of methods that call wrappers */
8807                                         INLINE_FAILURE ("wrapper call");
8808                                         cmethod = mono_marshal_get_native_wrapper (cmethod, TRUE, FALSE);
8809                                         always = TRUE;
8810                                 }
8811
8812                                 costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, always);
8813                                 if (costs) {
8814                                         cfg->real_offset += 5;
8815
8816                                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8817                                                 /* *sp is already set by inline_method */
8818                                                 sp++;
8819                                                 push_res = FALSE;
8820                                         }
8821
8822                                         inline_costs += costs;
8823
8824                                         goto call_end;
8825                                 }
8826                         }
8827
8828                         /* Tail recursion elimination */
8829                         if ((cfg->opt & MONO_OPT_TAILC) && call_opcode == CEE_CALL && cmethod == method && ip [5] == CEE_RET && !vtable_arg) {
8830                                 gboolean has_vtargs = FALSE;
8831                                 int i;
8832
8833                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
8834                                 INLINE_FAILURE ("tail call");
8835
8836                                 /* keep it simple */
8837                                 for (i =  fsig->param_count - 1; i >= 0; i--) {
8838                                         if (MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->params [i])) 
8839                                                 has_vtargs = TRUE;
8840                                 }
8841
8842                                 if (!has_vtargs) {
8843                                         if (need_seq_point) {
8844                                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
8845                                                 need_seq_point = FALSE;
8846                                         }
8847                                         for (i = 0; i < n; ++i)
8848                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
8849
8850                                         mini_profiler_emit_tail_call (cfg, cmethod);
8851
8852                                         MONO_INST_NEW (cfg, ins, OP_BR);
8853                                         MONO_ADD_INS (cfg->cbb, ins);
8854                                         tblock = start_bblock->out_bb [0];
8855                                         link_bblock (cfg, cfg->cbb, tblock);
8856                                         ins->inst_target_bb = tblock;
8857                                         start_new_bblock = 1;
8858
8859                                         /* skip the CEE_RET, too */
8860                                         if (ip_in_bb (cfg, cfg->cbb, ip + 5))
8861                                                 skip_ret = TRUE;
8862                                         push_res = FALSE;
8863                                         goto call_end;
8864                                 }
8865                         }
8866
8867                         inline_costs += 10 * num_calls++;
8868
8869                         /*
8870                          * Synchronized wrappers.
8871                          * Its hard to determine where to replace a method with its synchronized
8872                          * wrapper without causing an infinite recursion. The current solution is
8873                          * to add the synchronized wrapper in the trampolines, and to
8874                          * change the called method to a dummy wrapper, and resolve that wrapper
8875                          * to the real method in mono_jit_compile_method ().
8876                          */
8877                         if (cfg->method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
8878                                 MonoMethod *orig = mono_marshal_method_from_wrapper (cfg->method);
8879                                 if (cmethod == orig || (cmethod->is_inflated && mono_method_get_declaring_generic_method (cmethod) == orig))
8880                                         cmethod = mono_marshal_get_synchronized_inner_wrapper (cmethod);
8881                         }
8882
8883                         /*
8884                          * Making generic calls out of gsharedvt methods.
8885                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
8886                          * patching gshared method addresses into a gsharedvt method.
8887                          */
8888                         if (cfg->gsharedvt && (mini_is_gsharedvt_signature (fsig) || cmethod->is_inflated || mono_class_is_ginst (cmethod->klass)) &&
8889                                 !(cmethod->klass->rank && cmethod->klass->byval_arg.type != MONO_TYPE_SZARRAY) &&
8890                                 (!(cfg->llvm_only && virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL)))) {
8891                                 MonoRgctxInfoType info_type;
8892
8893                                 if (virtual_) {
8894                                         //if (mono_class_is_interface (cmethod->klass))
8895                                                 //GSHAREDVT_FAILURE (*ip);
8896                                         // disable for possible remoting calls
8897                                         if (fsig->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class))
8898                                                 GSHAREDVT_FAILURE (*ip);
8899                                         if (fsig->generic_param_count) {
8900                                                 /* virtual generic call */
8901                                                 g_assert (!imt_arg);
8902                                                 /* Same as the virtual generic case above */
8903                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
8904                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
8905                                                 /* This is not needed, as the trampoline code will pass one, and it might be passed in the same reg as the imt arg */
8906                                                 vtable_arg = NULL;
8907                                         } else if (mono_class_is_interface (cmethod->klass) && !imt_arg) {
8908                                                 /* This can happen when we call a fully instantiated iface method */
8909                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
8910                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
8911                                                 vtable_arg = NULL;
8912                                         }
8913                                 }
8914
8915                                 if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (cmethod->name, "Invoke")))
8916                                         keep_this_alive = sp [0];
8917
8918                                 if (virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))
8919                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
8920                                 else
8921                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE;
8922                                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, info_type);
8923
8924                                 if (cfg->llvm_only) {
8925                                         // FIXME: Avoid initializing vtable_arg
8926                                         ins = emit_llvmonly_calli (cfg, fsig, sp, addr);
8927                                 } else {
8928                                         ins = (MonoInst*)mini_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
8929                                 }
8930                                 goto call_end;
8931                         }
8932
8933                         /* Generic sharing */
8934
8935                         /*
8936                          * Use this if the callee is gsharedvt sharable too, since
8937                          * at runtime we might find an instantiation so the call cannot
8938                          * be patched (the 'no_patch' code path in mini-trampolines.c).
8939                          */
8940                         if (context_used && !imt_arg && !array_rank && !delegate_invoke &&
8941                                 (!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
8942                                  !mono_class_generic_sharing_enabled (cmethod->klass)) &&
8943                                 (!virtual_ || MONO_METHOD_IS_FINAL (cmethod) ||
8944                                  !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))) {
8945                                 INLINE_FAILURE ("gshared");
8946
8947                                 g_assert (cfg->gshared && cmethod);
8948                                 g_assert (!addr);
8949
8950                                 /*
8951                                  * We are compiling a call to a
8952                                  * generic method from shared code,
8953                                  * which means that we have to look up
8954                                  * the method in the rgctx and do an
8955                                  * indirect call.
8956                                  */
8957                                 if (fsig->hasthis)
8958                                         MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
8959
8960                                 if (cfg->llvm_only) {
8961                                         if (cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig))
8962                                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER);
8963                                         else
8964                                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
8965                                         // FIXME: Avoid initializing imt_arg/vtable_arg
8966                                         ins = emit_llvmonly_calli (cfg, fsig, sp, addr);
8967                                 } else {
8968                                         addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
8969                                         ins = (MonoInst*)mini_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
8970                                 }
8971                                 goto call_end;
8972                         }
8973
8974                         /* Direct calls to icalls */
8975                         if (direct_icall) {
8976                                 MonoMethod *wrapper;
8977                                 int costs;
8978
8979                                 /* Inline the wrapper */
8980                                 wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
8981
8982                                 costs = inline_method (cfg, wrapper, fsig, sp, ip, cfg->real_offset, TRUE);
8983                                 g_assert (costs > 0);
8984                                 cfg->real_offset += 5;
8985
8986                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8987                                         /* *sp is already set by inline_method */
8988                                         sp++;
8989                                         push_res = FALSE;
8990                                 }
8991
8992                                 inline_costs += costs;
8993
8994                                 goto call_end;
8995                         }
8996                                         
8997                         /* Array methods */
8998                         if (array_rank) {
8999                                 MonoInst *addr;
9000
9001                                 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ 
9002                                         MonoInst *val = sp [fsig->param_count];
9003
9004                                         if (val->type == STACK_OBJ) {
9005                                                 MonoInst *iargs [2];
9006
9007                                                 iargs [0] = sp [0];
9008                                                 iargs [1] = val;
9009                                                 
9010                                                 mono_emit_jit_icall (cfg, mono_helper_stelem_ref_check, iargs);
9011                                         }
9012                                         
9013                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, TRUE);
9014                                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, fsig->params [fsig->param_count - 1], addr->dreg, 0, val->dreg);
9015                                         if (cfg->gen_write_barriers && val->type == STACK_OBJ && !MONO_INS_IS_PCONST_NULL (val))
9016                                                 mini_emit_write_barrier (cfg, addr, val);
9017                                         if (cfg->gen_write_barriers && mini_is_gsharedvt_klass (cmethod->klass))
9018                                                 GSHAREDVT_FAILURE (*ip);
9019                                 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
9020                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9021
9022                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, addr->dreg, 0);
9023                                 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
9024                                         if (!cmethod->klass->element_class->valuetype && !readonly)
9025                                                 mini_emit_check_array_type (cfg, sp [0], cmethod->klass);
9026                                         CHECK_TYPELOAD (cmethod->klass);
9027                                         
9028                                         readonly = FALSE;
9029                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9030                                         ins = addr;
9031                                 } else {
9032                                         g_assert_not_reached ();
9033                                 }
9034
9035                                 emit_widen = FALSE;
9036                                 goto call_end;
9037                         }
9038
9039                         ins = mini_redirect_call (cfg, cmethod, fsig, sp, virtual_ ? sp [0] : NULL);
9040                         if (ins)
9041                                 goto call_end;
9042
9043                         /* Tail prefix / tail call optimization */
9044
9045                         /* FIXME: Enabling TAILC breaks some inlining/stack trace/etc tests */
9046                         /* FIXME: runtime generic context pointer for jumps? */
9047                         /* FIXME: handle this for generic sharing eventually */
9048                         if ((ins_flag & MONO_INST_TAILCALL) &&
9049                                 !vtable_arg && !cfg->gshared && is_supported_tail_call (cfg, method, cmethod, fsig, call_opcode))
9050                                 supported_tail_call = TRUE;
9051
9052                         if (supported_tail_call) {
9053                                 MonoCallInst *call;
9054
9055                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9056                                 INLINE_FAILURE ("tail call");
9057
9058                                 //printf ("HIT: %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
9059
9060                                 if (cfg->backend->have_op_tail_call) {
9061                                         /* Handle tail calls similarly to normal calls */
9062                                         tail_call = TRUE;
9063                                 } else {
9064                                         mini_profiler_emit_tail_call (cfg, cmethod);
9065
9066                                         MONO_INST_NEW_CALL (cfg, call, OP_JMP);
9067                                         call->tail_call = TRUE;
9068                                         call->method = cmethod;
9069                                         call->signature = mono_method_signature (cmethod);
9070
9071                                         /*
9072                                          * We implement tail calls by storing the actual arguments into the 
9073                                          * argument variables, then emitting a CEE_JMP.
9074                                          */
9075                                         for (i = 0; i < n; ++i) {
9076                                                 /* Prevent argument from being register allocated */
9077                                                 arg_array [i]->flags |= MONO_INST_VOLATILE;
9078                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9079                                         }
9080                                         ins = (MonoInst*)call;
9081                                         ins->inst_p0 = cmethod;
9082                                         ins->inst_p1 = arg_array [0];
9083                                         MONO_ADD_INS (cfg->cbb, ins);
9084                                         link_bblock (cfg, cfg->cbb, end_bblock);
9085                                         start_new_bblock = 1;
9086
9087                                         // FIXME: Eliminate unreachable epilogs
9088
9089                                         /*
9090                                          * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9091                                          * only reachable from this call.
9092                                          */
9093                                         GET_BBLOCK (cfg, tblock, ip + 5);
9094                                         if (tblock == cfg->cbb || tblock->in_count == 0)
9095                                                 skip_ret = TRUE;
9096                                         push_res = FALSE;
9097
9098                                         goto call_end;
9099                                 }
9100                         }
9101
9102                         /*
9103                          * Virtual calls in llvm-only mode.
9104                          */
9105                         if (cfg->llvm_only && virtual_ && cmethod && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
9106                                 ins = emit_llvmonly_virtual_call (cfg, cmethod, fsig, context_used, sp);
9107                                 goto call_end;
9108                         }
9109
9110                         /* Common call */
9111                         if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING) && !(cmethod->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))
9112                                 INLINE_FAILURE ("call");
9113                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, tail_call, sp, virtual_ ? sp [0] : NULL,
9114                                                                                           imt_arg, vtable_arg);
9115
9116                         if (tail_call && !cfg->llvm_only) {
9117                                 link_bblock (cfg, cfg->cbb, end_bblock);
9118                                 start_new_bblock = 1;
9119
9120                                 // FIXME: Eliminate unreachable epilogs
9121
9122                                 /*
9123                                  * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9124                                  * only reachable from this call.
9125                                  */
9126                                 GET_BBLOCK (cfg, tblock, ip + 5);
9127                                 if (tblock == cfg->cbb || tblock->in_count == 0)
9128                                         skip_ret = TRUE;
9129                                 push_res = FALSE;
9130                         }
9131
9132                         call_end:
9133
9134                         /* End of call, INS should contain the result of the call, if any */
9135
9136                         if (push_res && !MONO_TYPE_IS_VOID (fsig->ret)) {
9137                                 g_assert (ins);
9138                                 if (emit_widen)
9139                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
9140                                 else
9141                                         *sp++ = ins;
9142                         }
9143
9144                         if (keep_this_alive) {
9145                                 MonoInst *dummy_use;
9146
9147                                 /* See mono_emit_method_call_full () */
9148                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, keep_this_alive);
9149                         }
9150
9151                         if (cfg->llvm_only && cmethod && method_needs_stack_walk (cfg, cmethod)) {
9152                                 /*
9153                                  * Clang can convert these calls to tail calls which screw up the stack
9154                                  * walk. This happens even when the -fno-optimize-sibling-calls
9155                                  * option is passed to clang.
9156                                  * Work around this by emitting a dummy call.
9157                                  */
9158                                 mono_emit_jit_icall (cfg, mono_dummy_jit_icall, NULL);
9159                         }
9160
9161                         CHECK_CFG_EXCEPTION;
9162
9163                         ip += 5;
9164                         if (skip_ret) {
9165                                 g_assert (*ip == CEE_RET);
9166                                 ip += 1;
9167                         }
9168                         ins_flag = 0;
9169                         constrained_class = NULL;
9170                         if (need_seq_point)
9171                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
9172                         break;
9173                 }
9174                 case CEE_RET:
9175                         mini_profiler_emit_leave (cfg, sig->ret->type != MONO_TYPE_VOID ? sp [-1] : NULL);
9176
9177                         if (cfg->method != method) {
9178                                 /* return from inlined method */
9179                                 /* 
9180                                  * If in_count == 0, that means the ret is unreachable due to
9181                                  * being preceeded by a throw. In that case, inline_method () will
9182                                  * handle setting the return value 
9183                                  * (test case: test_0_inline_throw ()).
9184                                  */
9185                                 if (return_var && cfg->cbb->in_count) {
9186                                         MonoType *ret_type = mono_method_signature (method)->ret;
9187
9188                                         MonoInst *store;
9189                                         CHECK_STACK (1);
9190                                         --sp;
9191
9192                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
9193                                                 UNVERIFIED;
9194
9195                                         //g_assert (returnvar != -1);
9196                                         EMIT_NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
9197                                         cfg->ret_var_set = TRUE;
9198                                 } 
9199                         } else {
9200                                 if (cfg->lmf_var && cfg->cbb->in_count && !cfg->llvm_only)
9201                                         emit_pop_lmf (cfg);
9202
9203                                 if (cfg->ret) {
9204                                         MonoType *ret_type = mini_get_underlying_type (mono_method_signature (method)->ret);
9205
9206                                         if (seq_points && !sym_seq_points) {
9207                                                 /* 
9208                                                  * Place a seq point here too even through the IL stack is not
9209                                                  * empty, so a step over on
9210                                                  * call <FOO>
9211                                                  * ret
9212                                                  * will work correctly.
9213                                                  */
9214                                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, TRUE);
9215                                                 MONO_ADD_INS (cfg->cbb, ins);
9216                                         }
9217
9218                                         g_assert (!return_var);
9219                                         CHECK_STACK (1);
9220                                         --sp;
9221
9222                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
9223                                                 UNVERIFIED;
9224
9225                                         emit_setret (cfg, *sp);
9226                                 }
9227                         }
9228                         if (sp != stack_start)
9229                                 UNVERIFIED;
9230                         MONO_INST_NEW (cfg, ins, OP_BR);
9231                         ip++;
9232                         ins->inst_target_bb = end_bblock;
9233                         MONO_ADD_INS (cfg->cbb, ins);
9234                         link_bblock (cfg, cfg->cbb, end_bblock);
9235                         start_new_bblock = 1;
9236                         break;
9237                 case CEE_BR_S:
9238                         CHECK_OPSIZE (2);
9239                         MONO_INST_NEW (cfg, ins, OP_BR);
9240                         ip++;
9241                         target = ip + 1 + (signed char)(*ip);
9242                         ++ip;
9243                         GET_BBLOCK (cfg, tblock, target);
9244                         link_bblock (cfg, cfg->cbb, tblock);
9245                         ins->inst_target_bb = tblock;
9246                         if (sp != stack_start) {
9247                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9248                                 sp = stack_start;
9249                                 CHECK_UNVERIFIABLE (cfg);
9250                         }
9251                         MONO_ADD_INS (cfg->cbb, ins);
9252                         start_new_bblock = 1;
9253                         inline_costs += BRANCH_COST;
9254                         break;
9255                 case CEE_BEQ_S:
9256                 case CEE_BGE_S:
9257                 case CEE_BGT_S:
9258                 case CEE_BLE_S:
9259                 case CEE_BLT_S:
9260                 case CEE_BNE_UN_S:
9261                 case CEE_BGE_UN_S:
9262                 case CEE_BGT_UN_S:
9263                 case CEE_BLE_UN_S:
9264                 case CEE_BLT_UN_S:
9265                         CHECK_OPSIZE (2);
9266                         CHECK_STACK (2);
9267                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
9268                         ip++;
9269                         target = ip + 1 + *(signed char*)ip;
9270                         ip++;
9271
9272                         ADD_BINCOND (NULL);
9273
9274                         sp = stack_start;
9275                         inline_costs += BRANCH_COST;
9276                         break;
9277                 case CEE_BR:
9278                         CHECK_OPSIZE (5);
9279                         MONO_INST_NEW (cfg, ins, OP_BR);
9280                         ip++;
9281
9282                         target = ip + 4 + (gint32)read32(ip);
9283                         ip += 4;
9284                         GET_BBLOCK (cfg, tblock, target);
9285                         link_bblock (cfg, cfg->cbb, tblock);
9286                         ins->inst_target_bb = tblock;
9287                         if (sp != stack_start) {
9288                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9289                                 sp = stack_start;
9290                                 CHECK_UNVERIFIABLE (cfg);
9291                         }
9292
9293                         MONO_ADD_INS (cfg->cbb, ins);
9294
9295                         start_new_bblock = 1;
9296                         inline_costs += BRANCH_COST;
9297                         break;
9298                 case CEE_BRFALSE_S:
9299                 case CEE_BRTRUE_S:
9300                 case CEE_BRFALSE:
9301                 case CEE_BRTRUE: {
9302                         MonoInst *cmp;
9303                         gboolean is_short = ((*ip) == CEE_BRFALSE_S) || ((*ip) == CEE_BRTRUE_S);
9304                         gboolean is_true = ((*ip) == CEE_BRTRUE_S) || ((*ip) == CEE_BRTRUE);
9305                         guint32 opsize = is_short ? 1 : 4;
9306
9307                         CHECK_OPSIZE (opsize);
9308                         CHECK_STACK (1);
9309                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
9310                                 UNVERIFIED;
9311                         ip ++;
9312                         target = ip + opsize + (is_short ? *(signed char*)ip : (gint32)read32(ip));
9313                         ip += opsize;
9314
9315                         sp--;
9316
9317                         GET_BBLOCK (cfg, tblock, target);
9318                         link_bblock (cfg, cfg->cbb, tblock);
9319                         GET_BBLOCK (cfg, tblock, ip);
9320                         link_bblock (cfg, cfg->cbb, tblock);
9321
9322                         if (sp != stack_start) {
9323                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9324                                 CHECK_UNVERIFIABLE (cfg);
9325                         }
9326
9327                         MONO_INST_NEW(cfg, cmp, OP_ICOMPARE_IMM);
9328                         cmp->sreg1 = sp [0]->dreg;
9329                         type_from_op (cfg, cmp, sp [0], NULL);
9330                         CHECK_TYPE (cmp);
9331
9332 #if SIZEOF_REGISTER == 4
9333                         if (cmp->opcode == OP_LCOMPARE_IMM) {
9334                                 /* Convert it to OP_LCOMPARE */
9335                                 MONO_INST_NEW (cfg, ins, OP_I8CONST);
9336                                 ins->type = STACK_I8;
9337                                 ins->dreg = alloc_dreg (cfg, STACK_I8);
9338                                 ins->inst_l = 0;
9339                                 MONO_ADD_INS (cfg->cbb, ins);
9340                                 cmp->opcode = OP_LCOMPARE;
9341                                 cmp->sreg2 = ins->dreg;
9342                         }
9343 #endif
9344                         MONO_ADD_INS (cfg->cbb, cmp);
9345
9346                         MONO_INST_NEW (cfg, ins, is_true ? CEE_BNE_UN : CEE_BEQ);
9347                         type_from_op (cfg, ins, sp [0], NULL);
9348                         MONO_ADD_INS (cfg->cbb, ins);
9349                         ins->inst_many_bb = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);
9350                         GET_BBLOCK (cfg, tblock, target);
9351                         ins->inst_true_bb = tblock;
9352                         GET_BBLOCK (cfg, tblock, ip);
9353                         ins->inst_false_bb = tblock;
9354                         start_new_bblock = 2;
9355
9356                         sp = stack_start;
9357                         inline_costs += BRANCH_COST;
9358                         break;
9359                 }
9360                 case CEE_BEQ:
9361                 case CEE_BGE:
9362                 case CEE_BGT:
9363                 case CEE_BLE:
9364                 case CEE_BLT:
9365                 case CEE_BNE_UN:
9366                 case CEE_BGE_UN:
9367                 case CEE_BGT_UN:
9368                 case CEE_BLE_UN:
9369                 case CEE_BLT_UN:
9370                         CHECK_OPSIZE (5);
9371                         CHECK_STACK (2);
9372                         MONO_INST_NEW (cfg, ins, *ip);
9373                         ip++;
9374                         target = ip + 4 + (gint32)read32(ip);
9375                         ip += 4;
9376
9377                         ADD_BINCOND (NULL);
9378
9379                         sp = stack_start;
9380                         inline_costs += BRANCH_COST;
9381                         break;
9382                 case CEE_SWITCH: {
9383                         MonoInst *src1;
9384                         MonoBasicBlock **targets;
9385                         MonoBasicBlock *default_bblock;
9386                         MonoJumpInfoBBTable *table;
9387                         int offset_reg = alloc_preg (cfg);
9388                         int target_reg = alloc_preg (cfg);
9389                         int table_reg = alloc_preg (cfg);
9390                         int sum_reg = alloc_preg (cfg);
9391                         gboolean use_op_switch;
9392
9393                         CHECK_OPSIZE (5);
9394                         CHECK_STACK (1);
9395                         n = read32 (ip + 1);
9396                         --sp;
9397                         src1 = sp [0];
9398                         if ((src1->type != STACK_I4) && (src1->type != STACK_PTR)) 
9399                                 UNVERIFIED;
9400
9401                         ip += 5;
9402                         CHECK_OPSIZE (n * sizeof (guint32));
9403                         target = ip + n * sizeof (guint32);
9404
9405                         GET_BBLOCK (cfg, default_bblock, target);
9406                         default_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
9407
9408                         targets = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * n);
9409                         for (i = 0; i < n; ++i) {
9410                                 GET_BBLOCK (cfg, tblock, target + (gint32)read32(ip));
9411                                 targets [i] = tblock;
9412                                 targets [i]->flags |= BB_INDIRECT_JUMP_TARGET;
9413                                 ip += 4;
9414                         }
9415
9416                         if (sp != stack_start) {
9417                                 /* 
9418                                  * Link the current bb with the targets as well, so handle_stack_args
9419                                  * will set their in_stack correctly.
9420                                  */
9421                                 link_bblock (cfg, cfg->cbb, default_bblock);
9422                                 for (i = 0; i < n; ++i)
9423                                         link_bblock (cfg, cfg->cbb, targets [i]);
9424
9425                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9426                                 sp = stack_start;
9427                                 CHECK_UNVERIFIABLE (cfg);
9428
9429                                 /* Undo the links */
9430                                 mono_unlink_bblock (cfg, cfg->cbb, default_bblock);
9431                                 for (i = 0; i < n; ++i)
9432                                         mono_unlink_bblock (cfg, cfg->cbb, targets [i]);
9433                         }
9434
9435                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, src1->dreg, n);
9436                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBGE_UN, default_bblock);
9437
9438                         for (i = 0; i < n; ++i)
9439                                 link_bblock (cfg, cfg->cbb, targets [i]);
9440
9441                         table = (MonoJumpInfoBBTable *)mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
9442                         table->table = targets;
9443                         table->table_size = n;
9444
9445                         use_op_switch = FALSE;
9446 #ifdef TARGET_ARM
9447                         /* ARM implements SWITCH statements differently */
9448                         /* FIXME: Make it use the generic implementation */
9449                         if (!cfg->compile_aot)
9450                                 use_op_switch = TRUE;
9451 #endif
9452
9453                         if (COMPILE_LLVM (cfg))
9454                                 use_op_switch = TRUE;
9455
9456                         cfg->cbb->has_jump_table = 1;
9457
9458                         if (use_op_switch) {
9459                                 MONO_INST_NEW (cfg, ins, OP_SWITCH);
9460                                 ins->sreg1 = src1->dreg;
9461                                 ins->inst_p0 = table;
9462                                 ins->inst_many_bb = targets;
9463                                 ins->klass = (MonoClass *)GUINT_TO_POINTER (n);
9464                                 MONO_ADD_INS (cfg->cbb, ins);
9465                         } else {
9466                                 if (sizeof (gpointer) == 8)
9467                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 3);
9468                                 else
9469                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 2);
9470
9471 #if SIZEOF_REGISTER == 8
9472                                 /* The upper word might not be zero, and we add it to a 64 bit address later */
9473                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, offset_reg, offset_reg);
9474 #endif
9475
9476                                 if (cfg->compile_aot) {
9477                                         MONO_EMIT_NEW_AOTCONST (cfg, table_reg, table, MONO_PATCH_INFO_SWITCH);
9478                                 } else {
9479                                         MONO_INST_NEW (cfg, ins, OP_JUMP_TABLE);
9480                                         ins->inst_c1 = MONO_PATCH_INFO_SWITCH;
9481                                         ins->inst_p0 = table;
9482                                         ins->dreg = table_reg;
9483                                         MONO_ADD_INS (cfg->cbb, ins);
9484                                 }
9485
9486                                 /* FIXME: Use load_memindex */
9487                                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, table_reg, offset_reg);
9488                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, target_reg, sum_reg, 0);
9489                                 MONO_EMIT_NEW_UNALU (cfg, OP_BR_REG, -1, target_reg);
9490                         }
9491                         start_new_bblock = 1;
9492                         inline_costs += (BRANCH_COST * 2);
9493                         break;
9494                 }
9495                 case CEE_LDIND_I1:
9496                 case CEE_LDIND_U1:
9497                 case CEE_LDIND_I2:
9498                 case CEE_LDIND_U2:
9499                 case CEE_LDIND_I4:
9500                 case CEE_LDIND_U4:
9501                 case CEE_LDIND_I8:
9502                 case CEE_LDIND_I:
9503                 case CEE_LDIND_R4:
9504                 case CEE_LDIND_R8:
9505                 case CEE_LDIND_REF:
9506                         CHECK_STACK (1);
9507                         --sp;
9508
9509                         ins = mini_emit_memory_load (cfg, &ldind_to_type (*ip)->byval_arg, sp [0], 0, ins_flag);
9510                         *sp++ = ins;
9511                         ins_flag = 0;
9512                         ++ip;
9513                         break;
9514                 case CEE_STIND_REF:
9515                 case CEE_STIND_I1:
9516                 case CEE_STIND_I2:
9517                 case CEE_STIND_I4:
9518                 case CEE_STIND_I8:
9519                 case CEE_STIND_R4:
9520                 case CEE_STIND_R8:
9521                 case CEE_STIND_I:
9522                         CHECK_STACK (2);
9523                         sp -= 2;
9524
9525                         if (ins_flag & MONO_INST_VOLATILE) {
9526                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
9527                                 mini_emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
9528                         }
9529
9530                         NEW_STORE_MEMBASE (cfg, ins, stind_to_store_membase (*ip), sp [0]->dreg, 0, sp [1]->dreg);
9531                         ins->flags |= ins_flag;
9532                         ins_flag = 0;
9533
9534                         MONO_ADD_INS (cfg->cbb, ins);
9535
9536                         if (cfg->gen_write_barriers && *ip == CEE_STIND_REF && method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER && !MONO_INS_IS_PCONST_NULL (sp [1]))
9537                                 mini_emit_write_barrier (cfg, sp [0], sp [1]);
9538
9539                         inline_costs += 1;
9540                         ++ip;
9541                         break;
9542
9543                 case CEE_MUL:
9544                         CHECK_STACK (2);
9545
9546                         MONO_INST_NEW (cfg, ins, (*ip));
9547                         sp -= 2;
9548                         ins->sreg1 = sp [0]->dreg;
9549                         ins->sreg2 = sp [1]->dreg;
9550                         type_from_op (cfg, ins, sp [0], sp [1]);
9551                         CHECK_TYPE (ins);
9552                         ins->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type);
9553
9554                         /* Use the immediate opcodes if possible */
9555                         if ((sp [1]->opcode == OP_ICONST) && mono_arch_is_inst_imm (sp [1]->inst_c0)) {
9556                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
9557                                 if (imm_opcode != -1) {
9558                                         ins->opcode = imm_opcode;
9559                                         ins->inst_p1 = (gpointer)(gssize)(sp [1]->inst_c0);
9560                                         ins->sreg2 = -1;
9561
9562                                         NULLIFY_INS (sp [1]);
9563                                 }
9564                         }
9565
9566                         MONO_ADD_INS ((cfg)->cbb, (ins));
9567
9568                         *sp++ = mono_decompose_opcode (cfg, ins);
9569                         ip++;
9570                         break;
9571                 case CEE_ADD:
9572                 case CEE_SUB:
9573                 case CEE_DIV:
9574                 case CEE_DIV_UN:
9575                 case CEE_REM:
9576                 case CEE_REM_UN:
9577                 case CEE_AND:
9578                 case CEE_OR:
9579                 case CEE_XOR:
9580                 case CEE_SHL:
9581                 case CEE_SHR:
9582                 case CEE_SHR_UN:
9583                         CHECK_STACK (2);
9584
9585                         MONO_INST_NEW (cfg, ins, (*ip));
9586                         sp -= 2;
9587                         ins->sreg1 = sp [0]->dreg;
9588                         ins->sreg2 = sp [1]->dreg;
9589                         type_from_op (cfg, ins, sp [0], sp [1]);
9590                         CHECK_TYPE (ins);
9591                         add_widen_op (cfg, ins, &sp [0], &sp [1]);
9592                         ins->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type);
9593
9594                         /* FIXME: Pass opcode to is_inst_imm */
9595
9596                         /* Use the immediate opcodes if possible */
9597                         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)) {
9598                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
9599                                 if (imm_opcode != -1) {
9600                                         ins->opcode = imm_opcode;
9601                                         if (sp [1]->opcode == OP_I8CONST) {
9602 #if SIZEOF_REGISTER == 8
9603                                                 ins->inst_imm = sp [1]->inst_l;
9604 #else
9605                                                 ins->inst_ls_word = sp [1]->inst_ls_word;
9606                                                 ins->inst_ms_word = sp [1]->inst_ms_word;
9607 #endif
9608                                         }
9609                                         else
9610                                                 ins->inst_imm = (gssize)(sp [1]->inst_c0);
9611                                         ins->sreg2 = -1;
9612
9613                                         /* Might be followed by an instruction added by add_widen_op */
9614                                         if (sp [1]->next == NULL)
9615                                                 NULLIFY_INS (sp [1]);
9616                                 }
9617                         }
9618                         MONO_ADD_INS ((cfg)->cbb, (ins));
9619
9620                         *sp++ = mono_decompose_opcode (cfg, ins);
9621                         ip++;
9622                         break;
9623                 case CEE_NEG:
9624                 case CEE_NOT:
9625                 case CEE_CONV_I1:
9626                 case CEE_CONV_I2:
9627                 case CEE_CONV_I4:
9628                 case CEE_CONV_R4:
9629                 case CEE_CONV_R8:
9630                 case CEE_CONV_U4:
9631                 case CEE_CONV_I8:
9632                 case CEE_CONV_U8:
9633                 case CEE_CONV_OVF_I8:
9634                 case CEE_CONV_OVF_U8:
9635                 case CEE_CONV_R_UN:
9636                         CHECK_STACK (1);
9637
9638                         /* Special case this earlier so we have long constants in the IR */
9639                         if ((((*ip) == CEE_CONV_I8) || ((*ip) == CEE_CONV_U8)) && (sp [-1]->opcode == OP_ICONST)) {
9640                                 int data = sp [-1]->inst_c0;
9641                                 sp [-1]->opcode = OP_I8CONST;
9642                                 sp [-1]->type = STACK_I8;
9643 #if SIZEOF_REGISTER == 8
9644                                 if ((*ip) == CEE_CONV_U8)
9645                                         sp [-1]->inst_c0 = (guint32)data;
9646                                 else
9647                                         sp [-1]->inst_c0 = data;
9648 #else
9649                                 sp [-1]->inst_ls_word = data;
9650                                 if ((*ip) == CEE_CONV_U8)
9651                                         sp [-1]->inst_ms_word = 0;
9652                                 else
9653                                         sp [-1]->inst_ms_word = (data < 0) ? -1 : 0;
9654 #endif
9655                                 sp [-1]->dreg = alloc_dreg (cfg, STACK_I8);
9656                         }
9657                         else {
9658                                 ADD_UNOP (*ip);
9659                         }
9660                         ip++;
9661                         break;
9662                 case CEE_CONV_OVF_I4:
9663                 case CEE_CONV_OVF_I1:
9664                 case CEE_CONV_OVF_I2:
9665                 case CEE_CONV_OVF_I:
9666                 case CEE_CONV_OVF_U:
9667                         CHECK_STACK (1);
9668
9669                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
9670                                 ADD_UNOP (CEE_CONV_OVF_I8);
9671                                 ADD_UNOP (*ip);
9672                         } else {
9673                                 ADD_UNOP (*ip);
9674                         }
9675                         ip++;
9676                         break;
9677                 case CEE_CONV_OVF_U1:
9678                 case CEE_CONV_OVF_U2:
9679                 case CEE_CONV_OVF_U4:
9680                         CHECK_STACK (1);
9681
9682                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
9683                                 ADD_UNOP (CEE_CONV_OVF_U8);
9684                                 ADD_UNOP (*ip);
9685                         } else {
9686                                 ADD_UNOP (*ip);
9687                         }
9688                         ip++;
9689                         break;
9690                 case CEE_CONV_OVF_I1_UN:
9691                 case CEE_CONV_OVF_I2_UN:
9692                 case CEE_CONV_OVF_I4_UN:
9693                 case CEE_CONV_OVF_I8_UN:
9694                 case CEE_CONV_OVF_U1_UN:
9695                 case CEE_CONV_OVF_U2_UN:
9696                 case CEE_CONV_OVF_U4_UN:
9697                 case CEE_CONV_OVF_U8_UN:
9698                 case CEE_CONV_OVF_I_UN:
9699                 case CEE_CONV_OVF_U_UN:
9700                 case CEE_CONV_U2:
9701                 case CEE_CONV_U1:
9702                 case CEE_CONV_I:
9703                 case CEE_CONV_U:
9704                         CHECK_STACK (1);
9705                         ADD_UNOP (*ip);
9706                         CHECK_CFG_EXCEPTION;
9707                         ip++;
9708                         break;
9709                 case CEE_ADD_OVF:
9710                 case CEE_ADD_OVF_UN:
9711                 case CEE_MUL_OVF:
9712                 case CEE_MUL_OVF_UN:
9713                 case CEE_SUB_OVF:
9714                 case CEE_SUB_OVF_UN:
9715                         CHECK_STACK (2);
9716                         ADD_BINOP (*ip);
9717                         ip++;
9718                         break;
9719                 case CEE_CPOBJ:
9720                         GSHAREDVT_FAILURE (*ip);
9721                         CHECK_OPSIZE (5);
9722                         CHECK_STACK (2);
9723                         token = read32 (ip + 1);
9724                         klass = mini_get_class (method, token, generic_context);
9725                         CHECK_TYPELOAD (klass);
9726                         sp -= 2;
9727                         mini_emit_memory_copy (cfg, sp [0], sp [1], klass, FALSE, ins_flag);
9728                         ins_flag = 0;
9729                         ip += 5;
9730                         break;
9731                 case CEE_LDOBJ: {
9732                         int loc_index = -1;
9733                         int stloc_len = 0;
9734
9735                         CHECK_OPSIZE (5);
9736                         CHECK_STACK (1);
9737                         --sp;
9738                         token = read32 (ip + 1);
9739                         klass = mini_get_class (method, token, generic_context);
9740                         CHECK_TYPELOAD (klass);
9741
9742                         /* Optimize the common ldobj+stloc combination */
9743                         switch (ip [5]) {
9744                         case CEE_STLOC_S:
9745                                 loc_index = ip [6];
9746                                 stloc_len = 2;
9747                                 break;
9748                         case CEE_STLOC_0:
9749                         case CEE_STLOC_1:
9750                         case CEE_STLOC_2:
9751                         case CEE_STLOC_3:
9752                                 loc_index = ip [5] - CEE_STLOC_0;
9753                                 stloc_len = 1;
9754                                 break;
9755                         default:
9756                                 break;
9757                         }
9758
9759                         if ((loc_index != -1) && ip_in_bb (cfg, cfg->cbb, ip + 5)) {
9760                                 CHECK_LOCAL (loc_index);
9761
9762                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
9763                                 ins->dreg = cfg->locals [loc_index]->dreg;
9764                                 ins->flags |= ins_flag;
9765                                 ip += 5;
9766                                 ip += stloc_len;
9767                                 if (ins_flag & MONO_INST_VOLATILE) {
9768                                         /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
9769                                         mini_emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
9770                                 }
9771                                 ins_flag = 0;
9772                                 break;
9773                         }
9774
9775                         /* Optimize the ldobj+stobj combination */
9776                         if (((ip [5] == CEE_STOBJ) && ip_in_bb (cfg, cfg->cbb, ip + 5) && read32 (ip + 6) == token)) {
9777                                 CHECK_STACK (1);
9778
9779                                 sp --;
9780
9781                                 mini_emit_memory_copy (cfg, sp [0], sp [1], klass, FALSE, ins_flag);
9782
9783                                 ip += 5 + 5;
9784                                 ins_flag = 0;
9785                                 break;
9786                         }
9787
9788                         ins = mini_emit_memory_load (cfg, &klass->byval_arg, sp [0], 0, ins_flag);
9789                         *sp++ = ins;
9790
9791                         ip += 5;
9792                         ins_flag = 0;
9793                         inline_costs += 1;
9794                         break;
9795                 }
9796                 case CEE_LDSTR:
9797                         CHECK_STACK_OVF (1);
9798                         CHECK_OPSIZE (5);
9799                         n = read32 (ip + 1);
9800
9801                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
9802                                 EMIT_NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
9803                                 ins->type = STACK_OBJ;
9804                                 *sp = ins;
9805                         }
9806                         else if (method->wrapper_type != MONO_WRAPPER_NONE) {
9807                                 MonoInst *iargs [1];
9808                                 char *str = (char *)mono_method_get_wrapper_data (method, n);
9809
9810                                 if (cfg->compile_aot)
9811                                         EMIT_NEW_LDSTRLITCONST (cfg, iargs [0], str);
9812                                 else
9813                                         EMIT_NEW_PCONST (cfg, iargs [0], str);
9814                                 *sp = mono_emit_jit_icall (cfg, mono_string_new_wrapper, iargs);
9815                         } else {
9816                                 if (cfg->opt & MONO_OPT_SHARED) {
9817                                         MonoInst *iargs [3];
9818
9819                                         if (cfg->compile_aot) {
9820                                                 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
9821                                         }
9822                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
9823                                         EMIT_NEW_IMAGECONST (cfg, iargs [1], image);
9824                                         EMIT_NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
9825                                         *sp = mono_emit_jit_icall (cfg, ves_icall_mono_ldstr, iargs);
9826                                         mono_ldstr_checked (cfg->domain, image, mono_metadata_token_index (n), &cfg->error);
9827                                         CHECK_CFG_ERROR;
9828                                 } else {
9829                                         if (cfg->cbb->out_of_line) {
9830                                                 MonoInst *iargs [2];
9831
9832                                                 if (image == mono_defaults.corlib) {
9833                                                         /* 
9834                                                          * Avoid relocations in AOT and save some space by using a 
9835                                                          * version of helper_ldstr specialized to mscorlib.
9836                                                          */
9837                                                         EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (n));
9838                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr_mscorlib, iargs);
9839                                                 } else {
9840                                                         /* Avoid creating the string object */
9841                                                         EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
9842                                                         EMIT_NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n));
9843                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr, iargs);
9844                                                 }
9845                                         } 
9846                                         else
9847                                         if (cfg->compile_aot) {
9848                                                 NEW_LDSTRCONST (cfg, ins, image, n);
9849                                                 *sp = ins;
9850                                                 MONO_ADD_INS (cfg->cbb, ins);
9851                                         } 
9852                                         else {
9853                                                 NEW_PCONST (cfg, ins, NULL);
9854                                                 ins->type = STACK_OBJ;
9855                                                 ins->inst_p0 = mono_ldstr_checked (cfg->domain, image, mono_metadata_token_index (n), &cfg->error);
9856                                                 CHECK_CFG_ERROR;
9857                                                 
9858                                                 if (!ins->inst_p0)
9859                                                         OUT_OF_MEMORY_FAILURE;
9860
9861                                                 *sp = ins;
9862                                                 MONO_ADD_INS (cfg->cbb, ins);
9863                                         }
9864                                 }
9865                         }
9866
9867                         sp++;
9868                         ip += 5;
9869                         break;
9870                 case CEE_NEWOBJ: {
9871                         MonoInst *iargs [2];
9872                         MonoMethodSignature *fsig;
9873                         MonoInst this_ins;
9874                         MonoInst *alloc;
9875                         MonoInst *vtable_arg = NULL;
9876
9877                         CHECK_OPSIZE (5);
9878                         token = read32 (ip + 1);
9879                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
9880                         CHECK_CFG_ERROR;
9881
9882                         fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
9883                         CHECK_CFG_ERROR;
9884
9885                         mono_save_token_info (cfg, image, token, cmethod);
9886
9887                         if (!mono_class_init (cmethod->klass))
9888                                 TYPE_LOAD_ERROR (cmethod->klass);
9889
9890                         context_used = mini_method_check_context_used (cfg, cmethod);
9891                                         
9892                         if (!dont_verify && !cfg->skip_visibility) {
9893                                 MonoMethod *cil_method = cmethod;
9894                                 MonoMethod *target_method = cil_method;
9895
9896                                 if (method->is_inflated) {
9897                                         target_method = mini_get_method_allow_open (method, token, NULL, &(mono_method_get_generic_container (method_definition)->context), &cfg->error);
9898                                         CHECK_CFG_ERROR;
9899                                 }
9900                                 
9901                                 if (!mono_method_can_access_method (method_definition, target_method) &&
9902                                         !mono_method_can_access_method (method, cil_method))
9903                                         emit_method_access_failure (cfg, method, cil_method);
9904                         }
9905
9906                         if (mono_security_core_clr_enabled ())
9907                                 ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
9908
9909                         if (cfg->gshared && cmethod && cmethod->klass != method->klass && mono_class_is_ginst (cmethod->klass) && mono_method_is_generic_sharable (cmethod, TRUE) && mono_class_needs_cctor_run (cmethod->klass, method)) {
9910                                 emit_class_init (cfg, cmethod->klass);
9911                                 CHECK_TYPELOAD (cmethod->klass);
9912                         }
9913
9914                         /*
9915                         if (cfg->gsharedvt) {
9916                                 if (mini_is_gsharedvt_variable_signature (sig))
9917                                         GSHAREDVT_FAILURE (*ip);
9918                         }
9919                         */
9920
9921                         n = fsig->param_count;
9922                         CHECK_STACK (n);
9923
9924                         /* 
9925                          * Generate smaller code for the common newobj <exception> instruction in
9926                          * argument checking code.
9927                          */
9928                         if (cfg->cbb->out_of_line && cmethod->klass->image == mono_defaults.corlib &&
9929                                 is_exception_class (cmethod->klass) && n <= 2 &&
9930                                 ((n < 1) || (!fsig->params [0]->byref && fsig->params [0]->type == MONO_TYPE_STRING)) && 
9931                                 ((n < 2) || (!fsig->params [1]->byref && fsig->params [1]->type == MONO_TYPE_STRING))) {
9932                                 MonoInst *iargs [3];
9933
9934                                 sp -= n;
9935
9936                                 EMIT_NEW_ICONST (cfg, iargs [0], cmethod->klass->type_token);
9937                                 switch (n) {
9938                                 case 0:
9939                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_0, iargs);
9940                                         break;
9941                                 case 1:
9942                                         iargs [1] = sp [0];
9943                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_1, iargs);
9944                                         break;
9945                                 case 2:
9946                                         iargs [1] = sp [0];
9947                                         iargs [2] = sp [1];
9948                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_2, iargs);
9949                                         break;
9950                                 default:
9951                                         g_assert_not_reached ();
9952                                 }
9953
9954                                 ip += 5;
9955                                 inline_costs += 5;
9956                                 break;
9957                         }
9958
9959                         /* move the args to allow room for 'this' in the first position */
9960                         while (n--) {
9961                                 --sp;
9962                                 sp [1] = sp [0];
9963                         }
9964
9965                         /* check_call_signature () requires sp[0] to be set */
9966                         this_ins.type = STACK_OBJ;
9967                         sp [0] = &this_ins;
9968                         if (check_call_signature (cfg, fsig, sp))
9969                                 UNVERIFIED;
9970
9971                         iargs [0] = NULL;
9972
9973                         if (mini_class_is_system_array (cmethod->klass)) {
9974                                 *sp = emit_get_rgctx_method (cfg, context_used,
9975                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
9976
9977                                 /* Avoid varargs in the common case */
9978                                 if (fsig->param_count == 1)
9979                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_1, sp);
9980                                 else if (fsig->param_count == 2)
9981                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_2, sp);
9982                                 else if (fsig->param_count == 3)
9983                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_3, sp);
9984                                 else if (fsig->param_count == 4)
9985                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_4, sp);
9986                                 else
9987                                         alloc = handle_array_new (cfg, fsig->param_count, sp, ip);
9988                         } else if (cmethod->string_ctor) {
9989                                 g_assert (!context_used);
9990                                 g_assert (!vtable_arg);
9991                                 /* we simply pass a null pointer */
9992                                 EMIT_NEW_PCONST (cfg, *sp, NULL); 
9993                                 /* now call the string ctor */
9994                                 alloc = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, NULL, NULL, NULL);
9995                         } else {
9996                                 if (cmethod->klass->valuetype) {
9997                                         iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
9998                                         emit_init_rvar (cfg, iargs [0]->dreg, &cmethod->klass->byval_arg);
9999                                         EMIT_NEW_TEMPLOADA (cfg, *sp, iargs [0]->inst_c0);
10000
10001                                         alloc = NULL;
10002
10003                                         /* 
10004                                          * The code generated by mini_emit_virtual_call () expects
10005                                          * iargs [0] to be a boxed instance, but luckily the vcall
10006                                          * will be transformed into a normal call there.
10007                                          */
10008                                 } else if (context_used) {
10009                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, context_used);
10010                                         *sp = alloc;
10011                                 } else {
10012                                         MonoVTable *vtable = NULL;
10013
10014                                         if (!cfg->compile_aot)
10015                                                 vtable = mono_class_vtable (cfg->domain, cmethod->klass);
10016                                         CHECK_TYPELOAD (cmethod->klass);
10017
10018                                         /*
10019                                          * TypeInitializationExceptions thrown from the mono_runtime_class_init
10020                                          * call in mono_jit_runtime_invoke () can abort the finalizer thread.
10021                                          * As a workaround, we call class cctors before allocating objects.
10022                                          */
10023                                         if (mini_field_access_needs_cctor_run (cfg, method, cmethod->klass, vtable) && !(g_slist_find (class_inits, cmethod->klass))) {
10024                                                 emit_class_init (cfg, cmethod->klass);
10025                                                 if (cfg->verbose_level > 2)
10026                                                         printf ("class %s.%s needs init call for ctor\n", cmethod->klass->name_space, cmethod->klass->name);
10027                                                 class_inits = g_slist_prepend (class_inits, cmethod->klass);
10028                                         }
10029
10030                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, 0);
10031                                         *sp = alloc;
10032                                 }
10033                                 CHECK_CFG_EXCEPTION; /*for handle_alloc*/
10034
10035                                 if (alloc)
10036                                         MONO_EMIT_NEW_UNALU (cfg, OP_NOT_NULL, -1, alloc->dreg);
10037
10038                                 /* Now call the actual ctor */
10039                                 handle_ctor_call (cfg, cmethod, fsig, context_used, sp, ip, &inline_costs);
10040                                 CHECK_CFG_EXCEPTION;
10041                         }
10042
10043                         if (alloc == NULL) {
10044                                 /* Valuetype */
10045                                 EMIT_NEW_TEMPLOAD (cfg, ins, iargs [0]->inst_c0);
10046                                 type_to_eval_stack_type (cfg, &ins->klass->byval_arg, ins);
10047                                 *sp++= ins;
10048                         } else {
10049                                 *sp++ = alloc;
10050                         }
10051                         
10052                         ip += 5;
10053                         inline_costs += 5;
10054                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip - header->code)))
10055                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
10056                         break;
10057                 }
10058                 case CEE_CASTCLASS:
10059                 case CEE_ISINST: {
10060                         CHECK_STACK (1);
10061                         --sp;
10062                         CHECK_OPSIZE (5);
10063                         token = read32 (ip + 1);
10064                         klass = mini_get_class (method, token, generic_context);
10065                         CHECK_TYPELOAD (klass);
10066                         if (sp [0]->type != STACK_OBJ)
10067                                 UNVERIFIED;
10068
10069                         MONO_INST_NEW (cfg, ins, *ip == CEE_ISINST ? OP_ISINST : OP_CASTCLASS);
10070                         ins->dreg = alloc_preg (cfg);
10071                         ins->sreg1 = (*sp)->dreg;
10072                         ins->klass = klass;
10073                         ins->type = STACK_OBJ;
10074                         MONO_ADD_INS (cfg->cbb, ins);
10075
10076                         CHECK_CFG_EXCEPTION;
10077                         *sp++ = ins;
10078                         ip += 5;
10079
10080                         cfg->flags |= MONO_CFG_HAS_TYPE_CHECK;
10081                         break;
10082                 }
10083                 case CEE_UNBOX_ANY: {
10084                         MonoInst *res, *addr;
10085
10086                         CHECK_STACK (1);
10087                         --sp;
10088                         CHECK_OPSIZE (5);
10089                         token = read32 (ip + 1);
10090                         klass = mini_get_class (method, token, generic_context);
10091                         CHECK_TYPELOAD (klass);
10092
10093                         mono_save_token_info (cfg, image, token, klass);
10094
10095                         context_used = mini_class_check_context_used (cfg, klass);
10096
10097                         if (mini_is_gsharedvt_klass (klass)) {
10098                                 res = handle_unbox_gsharedvt (cfg, klass, *sp);
10099                                 inline_costs += 2;
10100                         } else if (generic_class_is_reference_type (cfg, klass)) {
10101                                 if (MONO_INS_IS_PCONST_NULL (*sp)) {
10102                                         EMIT_NEW_PCONST (cfg, res, NULL);
10103                                         res->type = STACK_OBJ;
10104                                 } else {
10105                                         MONO_INST_NEW (cfg, res, OP_CASTCLASS);
10106                                         res->dreg = alloc_preg (cfg);
10107                                         res->sreg1 = (*sp)->dreg;
10108                                         res->klass = klass;
10109                                         res->type = STACK_OBJ;
10110                                         MONO_ADD_INS (cfg->cbb, res);
10111                                         cfg->flags |= MONO_CFG_HAS_TYPE_CHECK;
10112                                 }
10113                         } else if (mono_class_is_nullable (klass)) {
10114                                 res = handle_unbox_nullable (cfg, *sp, klass, context_used);
10115                         } else {
10116                                 addr = handle_unbox (cfg, klass, sp, context_used);
10117                                 /* LDOBJ */
10118                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
10119                                 res = ins;
10120                                 inline_costs += 2;
10121                         }
10122
10123                         *sp ++ = res;
10124                         ip += 5;
10125                         break;
10126                 }
10127                 case CEE_BOX: {
10128                         MonoInst *val;
10129                         MonoClass *enum_class;
10130                         MonoMethod *has_flag;
10131
10132                         CHECK_STACK (1);
10133                         --sp;
10134                         val = *sp;
10135                         CHECK_OPSIZE (5);
10136                         token = read32 (ip + 1);
10137                         klass = mini_get_class (method, token, generic_context);
10138                         CHECK_TYPELOAD (klass);
10139
10140                         mono_save_token_info (cfg, image, token, klass);
10141
10142                         context_used = mini_class_check_context_used (cfg, klass);
10143
10144                         if (generic_class_is_reference_type (cfg, klass)) {
10145                                 *sp++ = val;
10146                                 ip += 5;
10147                                 break;
10148                         }
10149
10150                         if (klass == mono_defaults.void_class)
10151                                 UNVERIFIED;
10152                         if (target_type_is_incompatible (cfg, &klass->byval_arg, *sp))
10153                                 UNVERIFIED;
10154                         /* frequent check in generic code: box (struct), brtrue */
10155
10156                         /*
10157                          * Look for:
10158                          *
10159                          *   <push int/long ptr>
10160                          *   <push int/long>
10161                          *   box MyFlags
10162                          *   constrained. MyFlags
10163                          *   callvirt instace bool class [mscorlib] System.Enum::HasFlag (class [mscorlib] System.Enum)
10164                          *
10165                          * If we find this sequence and the operand types on box and constrained
10166                          * are equal, we can emit a specialized instruction sequence instead of
10167                          * the very slow HasFlag () call.
10168                          */
10169                         if ((cfg->opt & MONO_OPT_INTRINS) &&
10170                             /* Cheap checks first. */
10171                             ip + 5 + 6 + 5 < end &&
10172                             ip [5] == CEE_PREFIX1 &&
10173                             ip [6] == CEE_CONSTRAINED_ &&
10174                             ip [11] == CEE_CALLVIRT &&
10175                             ip_in_bb (cfg, cfg->cbb, ip + 5 + 6 + 5) &&
10176                             mono_class_is_enum (klass) &&
10177                             (enum_class = mini_get_class (method, read32 (ip + 7), generic_context)) &&
10178                             (has_flag = mini_get_method (cfg, method, read32 (ip + 12), NULL, generic_context)) &&
10179                             has_flag->klass == mono_defaults.enum_class &&
10180                             !strcmp (has_flag->name, "HasFlag") &&
10181                             has_flag->signature->hasthis &&
10182                             has_flag->signature->param_count == 1) {
10183                                 CHECK_TYPELOAD (enum_class);
10184
10185                                 if (enum_class == klass) {
10186                                         MonoInst *enum_this, *enum_flag;
10187
10188                                         ip += 5 + 6 + 5;
10189                                         --sp;
10190
10191                                         enum_this = sp [0];
10192                                         enum_flag = sp [1];
10193
10194                                         *sp++ = handle_enum_has_flag (cfg, klass, enum_this, enum_flag);
10195                                         break;
10196                                 }
10197                         }
10198
10199                         // FIXME: LLVM can't handle the inconsistent bb linking
10200                         if (!mono_class_is_nullable (klass) &&
10201                                 !mini_is_gsharedvt_klass (klass) &&
10202                                 ip + 5 < end && ip_in_bb (cfg, cfg->cbb, ip + 5) &&
10203                                 (ip [5] == CEE_BRTRUE || 
10204                                  ip [5] == CEE_BRTRUE_S ||
10205                                  ip [5] == CEE_BRFALSE ||
10206                                  ip [5] == CEE_BRFALSE_S)) {
10207                                 gboolean is_true = ip [5] == CEE_BRTRUE || ip [5] == CEE_BRTRUE_S;
10208                                 int dreg;
10209                                 MonoBasicBlock *true_bb, *false_bb;
10210
10211                                 ip += 5;
10212
10213                                 if (cfg->verbose_level > 3) {
10214                                         printf ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
10215                                         printf ("<box+brtrue opt>\n");
10216                                 }
10217
10218                                 switch (*ip) {
10219                                 case CEE_BRTRUE_S:
10220                                 case CEE_BRFALSE_S:
10221                                         CHECK_OPSIZE (2);
10222                                         ip++;
10223                                         target = ip + 1 + (signed char)(*ip);
10224                                         ip++;
10225                                         break;
10226                                 case CEE_BRTRUE:
10227                                 case CEE_BRFALSE:
10228                                         CHECK_OPSIZE (5);
10229                                         ip++;
10230                                         target = ip + 4 + (gint)(read32 (ip));
10231                                         ip += 4;
10232                                         break;
10233                                 default:
10234                                         g_assert_not_reached ();
10235                                 }
10236
10237                                 /* 
10238                                  * We need to link both bblocks, since it is needed for handling stack
10239                                  * arguments correctly (See test_0_box_brtrue_opt_regress_81102).
10240                                  * Branching to only one of them would lead to inconsistencies, so
10241                                  * generate an ICONST+BRTRUE, the branch opts will get rid of them.
10242                                  */
10243                                 GET_BBLOCK (cfg, true_bb, target);
10244                                 GET_BBLOCK (cfg, false_bb, ip);
10245
10246                                 mono_link_bblock (cfg, cfg->cbb, true_bb);
10247                                 mono_link_bblock (cfg, cfg->cbb, false_bb);
10248
10249                                 if (sp != stack_start) {
10250                                         handle_stack_args (cfg, stack_start, sp - stack_start);
10251                                         sp = stack_start;
10252                                         CHECK_UNVERIFIABLE (cfg);
10253                                 }
10254
10255                                 if (COMPILE_LLVM (cfg)) {
10256                                         dreg = alloc_ireg (cfg);
10257                                         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
10258                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, dreg, is_true ? 0 : 1);
10259
10260                                         MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, OP_IBEQ, true_bb, false_bb);
10261                                 } else {
10262                                         /* The JIT can't eliminate the iconst+compare */
10263                                         MONO_INST_NEW (cfg, ins, OP_BR);
10264                                         ins->inst_target_bb = is_true ? true_bb : false_bb;
10265                                         MONO_ADD_INS (cfg->cbb, ins);
10266                                 }
10267
10268                                 start_new_bblock = 1;
10269                                 break;
10270                         }
10271
10272                         *sp++ = handle_box (cfg, val, klass, context_used);
10273
10274                         CHECK_CFG_EXCEPTION;
10275                         ip += 5;
10276                         inline_costs += 1;
10277                         break;
10278                 }
10279                 case CEE_UNBOX: {
10280                         CHECK_STACK (1);
10281                         --sp;
10282                         CHECK_OPSIZE (5);
10283                         token = read32 (ip + 1);
10284                         klass = mini_get_class (method, token, generic_context);
10285                         CHECK_TYPELOAD (klass);
10286
10287                         mono_save_token_info (cfg, image, token, klass);
10288
10289                         context_used = mini_class_check_context_used (cfg, klass);
10290
10291                         if (mono_class_is_nullable (klass)) {
10292                                 MonoInst *val;
10293
10294                                 val = handle_unbox_nullable (cfg, *sp, klass, context_used);
10295                                 EMIT_NEW_VARLOADA (cfg, ins, get_vreg_to_inst (cfg, val->dreg), &val->klass->byval_arg);
10296
10297                                 *sp++= ins;
10298                         } else {
10299                                 ins = handle_unbox (cfg, klass, sp, context_used);
10300                                 *sp++ = ins;
10301                         }
10302                         ip += 5;
10303                         inline_costs += 2;
10304                         break;
10305                 }
10306                 case CEE_LDFLD:
10307                 case CEE_LDFLDA:
10308                 case CEE_STFLD:
10309                 case CEE_LDSFLD:
10310                 case CEE_LDSFLDA:
10311                 case CEE_STSFLD: {
10312                         MonoClassField *field;
10313 #ifndef DISABLE_REMOTING
10314                         int costs;
10315 #endif
10316                         guint foffset;
10317                         gboolean is_instance;
10318                         int op;
10319                         gpointer addr = NULL;
10320                         gboolean is_special_static;
10321                         MonoType *ftype;
10322                         MonoInst *store_val = NULL;
10323                         MonoInst *thread_ins;
10324
10325                         op = *ip;
10326                         is_instance = (op == CEE_LDFLD || op == CEE_LDFLDA || op == CEE_STFLD);
10327                         if (is_instance) {
10328                                 if (op == CEE_STFLD) {
10329                                         CHECK_STACK (2);
10330                                         sp -= 2;
10331                                         store_val = sp [1];
10332                                 } else {
10333                                         CHECK_STACK (1);
10334                                         --sp;
10335                                 }
10336                                 if (sp [0]->type == STACK_I4 || sp [0]->type == STACK_I8 || sp [0]->type == STACK_R8)
10337                                         UNVERIFIED;
10338                                 if (*ip != CEE_LDFLD && sp [0]->type == STACK_VTYPE)
10339                                         UNVERIFIED;
10340                         } else {
10341                                 if (op == CEE_STSFLD) {
10342                                         CHECK_STACK (1);
10343                                         sp--;
10344                                         store_val = sp [0];
10345                                 }
10346                         }
10347
10348                         CHECK_OPSIZE (5);
10349                         token = read32 (ip + 1);
10350                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
10351                                 field = (MonoClassField *)mono_method_get_wrapper_data (method, token);
10352                                 klass = field->parent;
10353                         }
10354                         else {
10355                                 field = mono_field_from_token_checked (image, token, &klass, generic_context, &cfg->error);
10356                                 CHECK_CFG_ERROR;
10357                         }
10358                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
10359                                 FIELD_ACCESS_FAILURE (method, field);
10360                         mono_class_init (klass);
10361
10362                         /* if the class is Critical then transparent code cannot access it's fields */
10363                         if (!is_instance && mono_security_core_clr_enabled ())
10364                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
10365
10366                         /* XXX this is technically required but, so far (SL2), no [SecurityCritical] types (not many exists) have
10367                            any visible *instance* field  (in fact there's a single case for a static field in Marshal) XXX
10368                         if (mono_security_core_clr_enabled ())
10369                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
10370                         */
10371
10372                         ftype = mono_field_get_type (field);
10373
10374                         /*
10375                          * LDFLD etc. is usable on static fields as well, so convert those cases to
10376                          * the static case.
10377                          */
10378                         if (is_instance && ftype->attrs & FIELD_ATTRIBUTE_STATIC) {
10379                                 switch (op) {
10380                                 case CEE_LDFLD:
10381                                         op = CEE_LDSFLD;
10382                                         break;
10383                                 case CEE_STFLD:
10384                                         op = CEE_STSFLD;
10385                                         break;
10386                                 case CEE_LDFLDA:
10387                                         op = CEE_LDSFLDA;
10388                                         break;
10389                                 default:
10390                                         g_assert_not_reached ();
10391                                 }
10392                                 is_instance = FALSE;
10393                         }
10394
10395                         context_used = mini_class_check_context_used (cfg, klass);
10396
10397                         /* INSTANCE CASE */
10398
10399                         foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
10400                         if (op == CEE_STFLD) {
10401                                 if (target_type_is_incompatible (cfg, field->type, sp [1]))
10402                                         UNVERIFIED;
10403 #ifndef DISABLE_REMOTING
10404                                 if ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class) {
10405                                         MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type); 
10406                                         MonoInst *iargs [5];
10407
10408                                         GSHAREDVT_FAILURE (op);
10409
10410                                         iargs [0] = sp [0];
10411                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
10412                                         EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
10413                                         EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : 
10414                                                     field->offset);
10415                                         iargs [4] = sp [1];
10416
10417                                         if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
10418                                                 costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), 
10419                                                                                            iargs, ip, cfg->real_offset, TRUE);
10420                                                 CHECK_CFG_EXCEPTION;
10421                                                 g_assert (costs > 0);
10422                                                       
10423                                                 cfg->real_offset += 5;
10424
10425                                                 inline_costs += costs;
10426                                         } else {
10427                                                 mono_emit_method_call (cfg, stfld_wrapper, iargs, NULL);
10428                                         }
10429                                 } else
10430 #endif
10431                                 {
10432                                         MonoInst *store, *wbarrier_ptr_ins = NULL;
10433
10434                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
10435
10436                                         if (ins_flag & MONO_INST_VOLATILE) {
10437                                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
10438                                                 mini_emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
10439                                         }
10440
10441                                         if (mini_is_gsharedvt_klass (klass)) {
10442                                                 MonoInst *offset_ins;
10443
10444                                                 context_used = mini_class_check_context_used (cfg, klass);
10445
10446                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10447                                                 /* The value is offset by 1 */
10448                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
10449                                                 dreg = alloc_ireg_mp (cfg);
10450                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
10451                                                 wbarrier_ptr_ins = ins;
10452                                                 /* The decomposition will call mini_emit_memory_copy () which will emit a wbarrier if needed */
10453                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, dreg, 0, sp [1]->dreg);
10454                                         } else {
10455                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, sp [0]->dreg, foffset, sp [1]->dreg);
10456                                         }
10457                                         if (sp [0]->opcode != OP_LDADDR)
10458                                                 store->flags |= MONO_INST_FAULT;
10459
10460                                         if (cfg->gen_write_barriers && mini_type_to_stind (cfg, field->type) == CEE_STIND_REF && !MONO_INS_IS_PCONST_NULL (sp [1])) {
10461                                                 if (mini_is_gsharedvt_klass (klass)) {
10462                                                         g_assert (wbarrier_ptr_ins);
10463                                                         mini_emit_write_barrier (cfg, wbarrier_ptr_ins, sp [1]);
10464                                                 } else {
10465                                                         /* insert call to write barrier */
10466                                                         MonoInst *ptr;
10467                                                         int dreg;
10468
10469                                                         dreg = alloc_ireg_mp (cfg);
10470                                                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
10471                                                         mini_emit_write_barrier (cfg, ptr, sp [1]);
10472                                                 }
10473                                         }
10474
10475                                         store->flags |= ins_flag;
10476                                 }
10477                                 ins_flag = 0;
10478                                 ip += 5;
10479                                 break;
10480                         }
10481
10482 #ifndef DISABLE_REMOTING
10483                         if (is_instance && ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class)) {
10484                                 MonoMethod *wrapper = (op == CEE_LDFLDA) ? mono_marshal_get_ldflda_wrapper (field->type) : mono_marshal_get_ldfld_wrapper (field->type); 
10485                                 MonoInst *iargs [4];
10486
10487                                 GSHAREDVT_FAILURE (op);
10488
10489                                 iargs [0] = sp [0];
10490                                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
10491                                 EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
10492                                 EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
10493                                 if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
10494                                         costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), 
10495                                                                                    iargs, ip, cfg->real_offset, TRUE);
10496                                         CHECK_CFG_EXCEPTION;
10497                                         g_assert (costs > 0);
10498                                                       
10499                                         cfg->real_offset += 5;
10500
10501                                         *sp++ = iargs [0];
10502
10503                                         inline_costs += costs;
10504                                 } else {
10505                                         ins = mono_emit_method_call (cfg, wrapper, iargs, NULL);
10506                                         *sp++ = ins;
10507                                 }
10508                         } else 
10509 #endif
10510                         if (is_instance) {
10511                                 if (sp [0]->type == STACK_VTYPE) {
10512                                         MonoInst *var;
10513
10514                                         /* Have to compute the address of the variable */
10515
10516                                         var = get_vreg_to_inst (cfg, sp [0]->dreg);
10517                                         if (!var)
10518                                                 var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, sp [0]->dreg);
10519                                         else
10520                                                 g_assert (var->klass == klass);
10521                                         
10522                                         EMIT_NEW_VARLOADA (cfg, ins, var, &var->klass->byval_arg);
10523                                         sp [0] = ins;
10524                                 }
10525
10526                                 if (op == CEE_LDFLDA) {
10527                                         if (sp [0]->type == STACK_OBJ) {
10528                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
10529                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "NullReferenceException");
10530                                         }
10531
10532                                         dreg = alloc_ireg_mp (cfg);
10533
10534                                         if (mini_is_gsharedvt_klass (klass)) {
10535                                                 MonoInst *offset_ins;
10536
10537                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10538                                                 /* The value is offset by 1 */
10539                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
10540                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
10541                                         } else {
10542                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
10543                                         }
10544                                         ins->klass = mono_class_from_mono_type (field->type);
10545                                         ins->type = STACK_MP;
10546                                         *sp++ = ins;
10547                                 } else {
10548                                         MonoInst *load;
10549
10550                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
10551
10552                                         if (sp [0]->opcode == OP_LDADDR && klass->simd_type && cfg->opt & MONO_OPT_SIMD) {
10553                                                 ins = mono_emit_simd_field_load (cfg, field, sp [0]);
10554                                                 if (ins) {
10555                                                         *sp++ = ins;
10556                                                         ins_flag = 0;
10557                                                         ip += 5;
10558                                                         break;
10559                                                 }
10560                                         }
10561
10562                                         MonoInst *field_add_inst = sp [0];
10563                                         if (mini_is_gsharedvt_klass (klass)) {
10564                                                 MonoInst *offset_ins;
10565
10566                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10567                                                 /* The value is offset by 1 */
10568                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
10569                                                 EMIT_NEW_BIALU (cfg, field_add_inst, OP_PADD, alloc_ireg_mp (cfg), sp [0]->dreg, offset_ins->dreg);
10570                                                 foffset = 0;
10571                                         }
10572
10573                                         load = mini_emit_memory_load (cfg, field->type, field_add_inst, foffset, ins_flag);
10574
10575                                         if (sp [0]->opcode != OP_LDADDR)
10576                                                 load->flags |= MONO_INST_FAULT;
10577                                         *sp++ = load;
10578                                 }
10579                         }
10580
10581                         if (is_instance) {
10582                                 ins_flag = 0;
10583                                 ip += 5;
10584                                 break;
10585                         }
10586
10587                         /* STATIC CASE */
10588                         context_used = mini_class_check_context_used (cfg, klass);
10589
10590                         if (ftype->attrs & FIELD_ATTRIBUTE_LITERAL) {
10591                                 mono_error_set_field_load (&cfg->error, field->parent, field->name, "Using static instructions with literal field");
10592                                 CHECK_CFG_ERROR;
10593                         }
10594
10595                         /* The special_static_fields field is init'd in mono_class_vtable, so it needs
10596                          * to be called here.
10597                          */
10598                         if (!context_used && !(cfg->opt & MONO_OPT_SHARED)) {
10599                                 mono_class_vtable (cfg->domain, klass);
10600                                 CHECK_TYPELOAD (klass);
10601                         }
10602                         mono_domain_lock (cfg->domain);
10603                         if (cfg->domain->special_static_fields)
10604                                 addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
10605                         mono_domain_unlock (cfg->domain);
10606
10607                         is_special_static = mono_class_field_is_special_static (field);
10608
10609                         if (is_special_static && ((gsize)addr & 0x80000000) == 0)
10610                                 thread_ins = mono_create_tls_get (cfg, TLS_KEY_THREAD);
10611                         else
10612                                 thread_ins = NULL;
10613
10614                         /* Generate IR to compute the field address */
10615                         if (is_special_static && ((gsize)addr & 0x80000000) == 0 && thread_ins && !(cfg->opt & MONO_OPT_SHARED) && !context_used) {
10616                                 /*
10617                                  * Fast access to TLS data
10618                                  * Inline version of get_thread_static_data () in
10619                                  * threads.c.
10620                                  */
10621                                 guint32 offset;
10622                                 int idx, static_data_reg, array_reg, dreg;
10623
10624                                 if (context_used && cfg->gsharedvt && mini_is_gsharedvt_klass (klass))
10625                                         GSHAREDVT_FAILURE (op);
10626
10627                                 static_data_reg = alloc_ireg (cfg);
10628                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, MONO_STRUCT_OFFSET (MonoInternalThread, static_data));
10629
10630                                 if (cfg->compile_aot) {
10631                                         int offset_reg, offset2_reg, idx_reg;
10632
10633                                         /* For TLS variables, this will return the TLS offset */
10634                                         EMIT_NEW_SFLDACONST (cfg, ins, field);
10635                                         offset_reg = ins->dreg;
10636                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset_reg, offset_reg, 0x7fffffff);
10637                                         idx_reg = alloc_ireg (cfg);
10638                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, idx_reg, offset_reg, 0x3f);
10639                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
10640                                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
10641                                         array_reg = alloc_ireg (cfg);
10642                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
10643                                         offset2_reg = alloc_ireg (cfg);
10644                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, offset2_reg, offset_reg, 6);
10645                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset2_reg, 0x1ffffff);
10646                                         dreg = alloc_ireg (cfg);
10647                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, array_reg, offset2_reg);
10648                                 } else {
10649                                         offset = (gsize)addr & 0x7fffffff;
10650                                         idx = offset & 0x3f;
10651
10652                                         array_reg = alloc_ireg (cfg);
10653                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, idx * sizeof (gpointer));
10654                                         dreg = alloc_ireg (cfg);
10655                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_ADD_IMM, dreg, array_reg, ((offset >> 6) & 0x1ffffff));
10656                                 }
10657                         } else if ((cfg->opt & MONO_OPT_SHARED) ||
10658                                         (cfg->compile_aot && is_special_static) ||
10659                                         (context_used && is_special_static)) {
10660                                 MonoInst *iargs [2];
10661
10662                                 g_assert (field->parent);
10663                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10664                                 if (context_used) {
10665                                         iargs [1] = emit_get_rgctx_field (cfg, context_used,
10666                                                 field, MONO_RGCTX_INFO_CLASS_FIELD);
10667                                 } else {
10668                                         EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
10669                                 }
10670                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
10671                         } else if (context_used) {
10672                                 MonoInst *static_data;
10673
10674                                 /*
10675                                 g_print ("sharing static field access in %s.%s.%s - depth %d offset %d\n",
10676                                         method->klass->name_space, method->klass->name, method->name,
10677                                         depth, field->offset);
10678                                 */
10679
10680                                 if (mono_class_needs_cctor_run (klass, method))
10681                                         emit_class_init (cfg, klass);
10682
10683                                 /*
10684                                  * The pointer we're computing here is
10685                                  *
10686                                  *   super_info.static_data + field->offset
10687                                  */
10688                                 static_data = mini_emit_get_rgctx_klass (cfg, context_used,
10689                                         klass, MONO_RGCTX_INFO_STATIC_DATA);
10690
10691                                 if (mini_is_gsharedvt_klass (klass)) {
10692                                         MonoInst *offset_ins;
10693
10694                                         offset_ins = emit_get_rgctx_field (cfg, context_used, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10695                                         /* The value is offset by 1 */
10696                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
10697                                         dreg = alloc_ireg_mp (cfg);
10698                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, static_data->dreg, offset_ins->dreg);
10699                                 } else if (field->offset == 0) {
10700                                         ins = static_data;
10701                                 } else {
10702                                         int addr_reg = mono_alloc_preg (cfg);
10703                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, addr_reg, static_data->dreg, field->offset);
10704                                 }
10705                         } else if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
10706                                 MonoInst *iargs [2];
10707
10708                                 g_assert (field->parent);
10709                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10710                                 EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
10711                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
10712                         } else {
10713                                 MonoVTable *vtable = NULL;
10714
10715                                 if (!cfg->compile_aot)
10716                                         vtable = mono_class_vtable (cfg->domain, klass);
10717                                 CHECK_TYPELOAD (klass);
10718
10719                                 if (!addr) {
10720                                         if (mini_field_access_needs_cctor_run (cfg, method, klass, vtable)) {
10721                                                 if (!(g_slist_find (class_inits, klass))) {
10722                                                         emit_class_init (cfg, klass);
10723                                                         if (cfg->verbose_level > 2)
10724                                                                 printf ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, mono_field_get_name (field));
10725                                                         class_inits = g_slist_prepend (class_inits, klass);
10726                                                 }
10727                                         } else {
10728                                                 if (cfg->run_cctors) {
10729                                                         /* This makes so that inline cannot trigger */
10730                                                         /* .cctors: too many apps depend on them */
10731                                                         /* running with a specific order... */
10732                                                         g_assert (vtable);
10733                                                         if (! vtable->initialized)
10734                                                                 INLINE_FAILURE ("class init");
10735                                                         if (!mono_runtime_class_init_full (vtable, &cfg->error)) {
10736                                                                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
10737                                                                 goto exception_exit;
10738                                                         }
10739                                                 }
10740                                         }
10741                                         if (cfg->compile_aot)
10742                                                 EMIT_NEW_SFLDACONST (cfg, ins, field);
10743                                         else {
10744                                                 g_assert (vtable);
10745                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
10746                                                 g_assert (addr);
10747                                                 EMIT_NEW_PCONST (cfg, ins, addr);
10748                                         }
10749                                 } else {
10750                                         MonoInst *iargs [1];
10751                                         EMIT_NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
10752                                         ins = mono_emit_jit_icall (cfg, mono_get_special_static_data, iargs);
10753                                 }
10754                         }
10755
10756                         /* Generate IR to do the actual load/store operation */
10757
10758                         if ((op == CEE_STFLD || op == CEE_STSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
10759                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
10760                                 mini_emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
10761                         }
10762
10763                         if (op == CEE_LDSFLDA) {
10764                                 ins->klass = mono_class_from_mono_type (ftype);
10765                                 ins->type = STACK_PTR;
10766                                 *sp++ = ins;
10767                         } else if (op == CEE_STSFLD) {
10768                                 MonoInst *store;
10769
10770                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, ftype, ins->dreg, 0, store_val->dreg);
10771                                 store->flags |= ins_flag;
10772                         } else {
10773                                 gboolean is_const = FALSE;
10774                                 MonoVTable *vtable = NULL;
10775                                 gpointer addr = NULL;
10776
10777                                 if (!context_used) {
10778                                         vtable = mono_class_vtable (cfg->domain, klass);
10779                                         CHECK_TYPELOAD (klass);
10780                                 }
10781                                 if ((ftype->attrs & FIELD_ATTRIBUTE_INIT_ONLY) && (((addr = mono_aot_readonly_field_override (field)) != NULL) ||
10782                                                 (!context_used && !((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && vtable->initialized))) {
10783                                         int ro_type = ftype->type;
10784                                         if (!addr)
10785                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
10786                                         if (ro_type == MONO_TYPE_VALUETYPE && ftype->data.klass->enumtype) {
10787                                                 ro_type = mono_class_enum_basetype (ftype->data.klass)->type;
10788                                         }
10789
10790                                         GSHAREDVT_FAILURE (op);
10791
10792                                         /* printf ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, mono_field_get_name (field));*/
10793                                         is_const = TRUE;
10794                                         switch (ro_type) {
10795                                         case MONO_TYPE_BOOLEAN:
10796                                         case MONO_TYPE_U1:
10797                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint8 *)addr));
10798                                                 sp++;
10799                                                 break;
10800                                         case MONO_TYPE_I1:
10801                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint8 *)addr));
10802                                                 sp++;
10803                                                 break;                                          
10804                                         case MONO_TYPE_CHAR:
10805                                         case MONO_TYPE_U2:
10806                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint16 *)addr));
10807                                                 sp++;
10808                                                 break;
10809                                         case MONO_TYPE_I2:
10810                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint16 *)addr));
10811                                                 sp++;
10812                                                 break;
10813                                                 break;
10814                                         case MONO_TYPE_I4:
10815                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint32 *)addr));
10816                                                 sp++;
10817                                                 break;                                          
10818                                         case MONO_TYPE_U4:
10819                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint32 *)addr));
10820                                                 sp++;
10821                                                 break;
10822                                         case MONO_TYPE_I:
10823                                         case MONO_TYPE_U:
10824                                         case MONO_TYPE_PTR:
10825                                         case MONO_TYPE_FNPTR:
10826                                                 EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
10827                                                 type_to_eval_stack_type ((cfg), field->type, *sp);
10828                                                 sp++;
10829                                                 break;
10830                                         case MONO_TYPE_STRING:
10831                                         case MONO_TYPE_OBJECT:
10832                                         case MONO_TYPE_CLASS:
10833                                         case MONO_TYPE_SZARRAY:
10834                                         case MONO_TYPE_ARRAY:
10835                                                 if (!mono_gc_is_moving ()) {
10836                                                         EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
10837                                                         type_to_eval_stack_type ((cfg), field->type, *sp);
10838                                                         sp++;
10839                                                 } else {
10840                                                         is_const = FALSE;
10841                                                 }
10842                                                 break;
10843                                         case MONO_TYPE_I8:
10844                                         case MONO_TYPE_U8:
10845                                                 EMIT_NEW_I8CONST (cfg, *sp, *((gint64 *)addr));
10846                                                 sp++;
10847                                                 break;
10848                                         case MONO_TYPE_R4:
10849                                         case MONO_TYPE_R8:
10850                                         case MONO_TYPE_VALUETYPE:
10851                                         default:
10852                                                 is_const = FALSE;
10853                                                 break;
10854                                         }
10855                                 }
10856
10857                                 if (!is_const) {
10858                                         MonoInst *load;
10859
10860                                         CHECK_STACK_OVF (1);
10861
10862                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, ins->dreg, 0);
10863                                         load->flags |= ins_flag;
10864                                         ins_flag = 0;
10865                                         *sp++ = load;
10866                                 }
10867                         }
10868
10869                         if ((op == CEE_LDFLD || op == CEE_LDSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
10870                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10871                                 mini_emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10872                         }
10873
10874                         ins_flag = 0;
10875                         ip += 5;
10876                         break;
10877                 }
10878                 case CEE_STOBJ:
10879                         CHECK_STACK (2);
10880                         sp -= 2;
10881                         CHECK_OPSIZE (5);
10882                         token = read32 (ip + 1);
10883                         klass = mini_get_class (method, token, generic_context);
10884                         CHECK_TYPELOAD (klass);
10885
10886                         /* FIXME: should check item at sp [1] is compatible with the type of the store. */
10887                         mini_emit_memory_store (cfg, &klass->byval_arg, sp [0], sp [1], ins_flag);
10888                         ins_flag = 0;
10889                         ip += 5;
10890                         inline_costs += 1;
10891                         break;
10892
10893                         /*
10894                          * Array opcodes
10895                          */
10896                 case CEE_NEWARR: {
10897                         MonoInst *len_ins;
10898                         const char *data_ptr;
10899                         int data_size = 0;
10900                         guint32 field_token;
10901
10902                         CHECK_STACK (1);
10903                         --sp;
10904
10905                         CHECK_OPSIZE (5);
10906                         token = read32 (ip + 1);
10907
10908                         klass = mini_get_class (method, token, generic_context);
10909                         CHECK_TYPELOAD (klass);
10910                         if (klass->byval_arg.type == MONO_TYPE_VOID)
10911                                 UNVERIFIED;
10912
10913                         context_used = mini_class_check_context_used (cfg, klass);
10914
10915                         if (sp [0]->type == STACK_I8 || (SIZEOF_VOID_P == 8 && sp [0]->type == STACK_PTR)) {
10916                                 MONO_INST_NEW (cfg, ins, OP_LCONV_TO_OVF_U4);
10917                                 ins->sreg1 = sp [0]->dreg;
10918                                 ins->type = STACK_I4;
10919                                 ins->dreg = alloc_ireg (cfg);
10920                                 MONO_ADD_INS (cfg->cbb, ins);
10921                                 *sp = mono_decompose_opcode (cfg, ins);
10922                         }
10923
10924                         if (context_used) {
10925                                 MonoInst *args [3];
10926                                 MonoClass *array_class = mono_array_class_get (klass, 1);
10927                                 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
10928
10929                                 /* FIXME: Use OP_NEWARR and decompose later to help abcrem */
10930
10931                                 /* vtable */
10932                                 args [0] = mini_emit_get_rgctx_klass (cfg, context_used,
10933                                         array_class, MONO_RGCTX_INFO_VTABLE);
10934                                 /* array len */
10935                                 args [1] = sp [0];
10936
10937                                 if (managed_alloc)
10938                                         ins = mono_emit_method_call (cfg, managed_alloc, args, NULL);
10939                                 else
10940                                         ins = mono_emit_jit_icall (cfg, ves_icall_array_new_specific, args);
10941                         } else {
10942                                 if (cfg->opt & MONO_OPT_SHARED) {
10943                                         /* Decompose now to avoid problems with references to the domainvar */
10944                                         MonoInst *iargs [3];
10945
10946                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10947                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
10948                                         iargs [2] = sp [0];
10949
10950                                         ins = mono_emit_jit_icall (cfg, ves_icall_array_new, iargs);
10951                                 } else {
10952                                         /* Decompose later since it is needed by abcrem */
10953                                         MonoClass *array_type = mono_array_class_get (klass, 1);
10954                                         mono_class_vtable (cfg->domain, array_type);
10955                                         CHECK_TYPELOAD (array_type);
10956
10957                                         MONO_INST_NEW (cfg, ins, OP_NEWARR);
10958                                         ins->dreg = alloc_ireg_ref (cfg);
10959                                         ins->sreg1 = sp [0]->dreg;
10960                                         ins->inst_newa_class = klass;
10961                                         ins->type = STACK_OBJ;
10962                                         ins->klass = array_type;
10963                                         MONO_ADD_INS (cfg->cbb, ins);
10964                                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
10965                                         cfg->cbb->has_array_access = TRUE;
10966
10967                                         /* Needed so mono_emit_load_get_addr () gets called */
10968                                         mono_get_got_var (cfg);
10969                                 }
10970                         }
10971
10972                         len_ins = sp [0];
10973                         ip += 5;
10974                         *sp++ = ins;
10975                         inline_costs += 1;
10976
10977                         /* 
10978                          * we inline/optimize the initialization sequence if possible.
10979                          * we should also allocate the array as not cleared, since we spend as much time clearing to 0 as initializing
10980                          * for small sizes open code the memcpy
10981                          * ensure the rva field is big enough
10982                          */
10983                         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))) {
10984                                 MonoMethod *memcpy_method = mini_get_memcpy_method ();
10985                                 MonoInst *iargs [3];
10986                                 int add_reg = alloc_ireg_mp (cfg);
10987
10988                                 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, add_reg, ins->dreg, MONO_STRUCT_OFFSET (MonoArray, vector));
10989                                 if (cfg->compile_aot) {
10990                                         EMIT_NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(field_token), STACK_PTR, NULL);
10991                                 } else {
10992                                         EMIT_NEW_PCONST (cfg, iargs [1], (char*)data_ptr);
10993                                 }
10994                                 EMIT_NEW_ICONST (cfg, iargs [2], data_size);
10995                                 mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
10996                                 ip += 11;
10997                         }
10998
10999                         break;
11000                 }
11001                 case CEE_LDLEN:
11002                         CHECK_STACK (1);
11003                         --sp;
11004                         if (sp [0]->type != STACK_OBJ)
11005                                 UNVERIFIED;
11006
11007                         MONO_INST_NEW (cfg, ins, OP_LDLEN);
11008                         ins->dreg = alloc_preg (cfg);
11009                         ins->sreg1 = sp [0]->dreg;
11010                         ins->type = STACK_I4;
11011                         /* This flag will be inherited by the decomposition */
11012                         ins->flags |= MONO_INST_FAULT;
11013                         MONO_ADD_INS (cfg->cbb, ins);
11014                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11015                         cfg->cbb->has_array_access = TRUE;
11016                         ip ++;
11017                         *sp++ = ins;
11018                         break;
11019                 case CEE_LDELEMA:
11020                         CHECK_STACK (2);
11021                         sp -= 2;
11022                         CHECK_OPSIZE (5);
11023                         if (sp [0]->type != STACK_OBJ)
11024                                 UNVERIFIED;
11025
11026                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11027
11028                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11029                         CHECK_TYPELOAD (klass);
11030                         /* we need to make sure that this array is exactly the type it needs
11031                          * to be for correctness. the wrappers are lax with their usage
11032                          * so we need to ignore them here
11033                          */
11034                         if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE && !readonly) {
11035                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11036                                 mini_emit_check_array_type (cfg, sp [0], array_class);
11037                                 CHECK_TYPELOAD (array_class);
11038                         }
11039
11040                         readonly = FALSE;
11041                         ins = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11042                         *sp++ = ins;
11043                         ip += 5;
11044                         break;
11045                 case CEE_LDELEM:
11046                 case CEE_LDELEM_I1:
11047                 case CEE_LDELEM_U1:
11048                 case CEE_LDELEM_I2:
11049                 case CEE_LDELEM_U2:
11050                 case CEE_LDELEM_I4:
11051                 case CEE_LDELEM_U4:
11052                 case CEE_LDELEM_I8:
11053                 case CEE_LDELEM_I:
11054                 case CEE_LDELEM_R4:
11055                 case CEE_LDELEM_R8:
11056                 case CEE_LDELEM_REF: {
11057                         MonoInst *addr;
11058
11059                         CHECK_STACK (2);
11060                         sp -= 2;
11061
11062                         if (*ip == CEE_LDELEM) {
11063                                 CHECK_OPSIZE (5);
11064                                 token = read32 (ip + 1);
11065                                 klass = mini_get_class (method, token, generic_context);
11066                                 CHECK_TYPELOAD (klass);
11067                                 mono_class_init (klass);
11068                         }
11069                         else
11070                                 klass = array_access_to_klass (*ip);
11071
11072                         if (sp [0]->type != STACK_OBJ)
11073                                 UNVERIFIED;
11074
11075                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11076
11077                         if (mini_is_gsharedvt_variable_klass (klass)) {
11078                                 // FIXME-VT: OP_ICONST optimization
11079                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11080                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11081                                 ins->opcode = OP_LOADV_MEMBASE;
11082                         } else if (sp [1]->opcode == OP_ICONST) {
11083                                 int array_reg = sp [0]->dreg;
11084                                 int index_reg = sp [1]->dreg;
11085                                 int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
11086
11087                                 if (SIZEOF_REGISTER == 8 && COMPILE_LLVM (cfg))
11088                                         MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, index_reg, index_reg);
11089
11090                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
11091                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset);
11092                         } else {
11093                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11094                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11095                         }
11096                         *sp++ = ins;
11097                         if (*ip == CEE_LDELEM)
11098                                 ip += 5;
11099                         else
11100                                 ++ip;
11101                         break;
11102                 }
11103                 case CEE_STELEM_I:
11104                 case CEE_STELEM_I1:
11105                 case CEE_STELEM_I2:
11106                 case CEE_STELEM_I4:
11107                 case CEE_STELEM_I8:
11108                 case CEE_STELEM_R4:
11109                 case CEE_STELEM_R8:
11110                 case CEE_STELEM_REF:
11111                 case CEE_STELEM: {
11112                         CHECK_STACK (3);
11113                         sp -= 3;
11114
11115                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11116
11117                         if (*ip == CEE_STELEM) {
11118                                 CHECK_OPSIZE (5);
11119                                 token = read32 (ip + 1);
11120                                 klass = mini_get_class (method, token, generic_context);
11121                                 CHECK_TYPELOAD (klass);
11122                                 mono_class_init (klass);
11123                         }
11124                         else
11125                                 klass = array_access_to_klass (*ip);
11126
11127                         if (sp [0]->type != STACK_OBJ)
11128                                 UNVERIFIED;
11129
11130                         emit_array_store (cfg, klass, sp, TRUE);
11131
11132                         if (*ip == CEE_STELEM)
11133                                 ip += 5;
11134                         else
11135                                 ++ip;
11136                         inline_costs += 1;
11137                         break;
11138                 }
11139                 case CEE_CKFINITE: {
11140                         CHECK_STACK (1);
11141                         --sp;
11142
11143                         if (cfg->llvm_only) {
11144                                 MonoInst *iargs [1];
11145
11146                                 iargs [0] = sp [0];
11147                                 *sp++ = mono_emit_jit_icall (cfg, mono_ckfinite, iargs);
11148                         } else  {
11149                                 MONO_INST_NEW (cfg, ins, OP_CKFINITE);
11150                                 ins->sreg1 = sp [0]->dreg;
11151                                 ins->dreg = alloc_freg (cfg);
11152                                 ins->type = STACK_R8;
11153                                 MONO_ADD_INS (cfg->cbb, ins);
11154
11155                                 *sp++ = mono_decompose_opcode (cfg, ins);
11156                         }
11157
11158                         ++ip;
11159                         break;
11160                 }
11161                 case CEE_REFANYVAL: {
11162                         MonoInst *src_var, *src;
11163
11164                         int klass_reg = alloc_preg (cfg);
11165                         int dreg = alloc_preg (cfg);
11166
11167                         GSHAREDVT_FAILURE (*ip);
11168
11169                         CHECK_STACK (1);
11170                         MONO_INST_NEW (cfg, ins, *ip);
11171                         --sp;
11172                         CHECK_OPSIZE (5);
11173                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11174                         CHECK_TYPELOAD (klass);
11175
11176                         context_used = mini_class_check_context_used (cfg, klass);
11177
11178                         // FIXME:
11179                         src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
11180                         if (!src_var)
11181                                 src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
11182                         EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
11183                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass));
11184
11185                         if (context_used) {
11186                                 MonoInst *klass_ins;
11187
11188                                 klass_ins = mini_emit_get_rgctx_klass (cfg, context_used,
11189                                                 klass, MONO_RGCTX_INFO_KLASS);
11190
11191                                 // FIXME:
11192                                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_ins->dreg);
11193                                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
11194                         } else {
11195                                 mini_emit_class_check (cfg, klass_reg, klass);
11196                         }
11197                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value));
11198                         ins->type = STACK_MP;
11199                         ins->klass = klass;
11200                         *sp++ = ins;
11201                         ip += 5;
11202                         break;
11203                 }
11204                 case CEE_MKREFANY: {
11205                         MonoInst *loc, *addr;
11206
11207                         GSHAREDVT_FAILURE (*ip);
11208
11209                         CHECK_STACK (1);
11210                         MONO_INST_NEW (cfg, ins, *ip);
11211                         --sp;
11212                         CHECK_OPSIZE (5);
11213                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11214                         CHECK_TYPELOAD (klass);
11215
11216                         context_used = mini_class_check_context_used (cfg, klass);
11217
11218                         loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
11219                         EMIT_NEW_TEMPLOADA (cfg, addr, loc->inst_c0);
11220
11221                         if (context_used) {
11222                                 MonoInst *const_ins;
11223                                 int type_reg = alloc_preg (cfg);
11224
11225                                 const_ins = mini_emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
11226                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_ins->dreg);
11227                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_ins->dreg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
11228                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
11229                         } else {
11230                                 int const_reg = alloc_preg (cfg);
11231                                 int type_reg = alloc_preg (cfg);
11232
11233                                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
11234                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_reg);
11235                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_reg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
11236                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
11237                         }
11238                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value), sp [0]->dreg);
11239
11240                         EMIT_NEW_TEMPLOAD (cfg, ins, loc->inst_c0);
11241                         ins->type = STACK_VTYPE;
11242                         ins->klass = mono_defaults.typed_reference_class;
11243                         *sp++ = ins;
11244                         ip += 5;
11245                         break;
11246                 }
11247                 case CEE_LDTOKEN: {
11248                         gpointer handle;
11249                         MonoClass *handle_class;
11250
11251                         CHECK_STACK_OVF (1);
11252
11253                         CHECK_OPSIZE (5);
11254                         n = read32 (ip + 1);
11255
11256                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD ||
11257                                         method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
11258                                 handle = mono_method_get_wrapper_data (method, n);
11259                                 handle_class = (MonoClass *)mono_method_get_wrapper_data (method, n + 1);
11260                                 if (handle_class == mono_defaults.typehandle_class)
11261                                         handle = &((MonoClass*)handle)->byval_arg;
11262                         }
11263                         else {
11264                                 handle = mono_ldtoken_checked (image, n, &handle_class, generic_context, &cfg->error);
11265                                 CHECK_CFG_ERROR;
11266                         }
11267                         if (!handle)
11268                                 LOAD_ERROR;
11269                         mono_class_init (handle_class);
11270                         if (cfg->gshared) {
11271                                 if (mono_metadata_token_table (n) == MONO_TABLE_TYPEDEF ||
11272                                                 mono_metadata_token_table (n) == MONO_TABLE_TYPEREF) {
11273                                         /* This case handles ldtoken
11274                                            of an open type, like for
11275                                            typeof(Gen<>). */
11276                                         context_used = 0;
11277                                 } else if (handle_class == mono_defaults.typehandle_class) {
11278                                         context_used = mini_class_check_context_used (cfg, mono_class_from_mono_type ((MonoType *)handle));
11279                                 } else if (handle_class == mono_defaults.fieldhandle_class)
11280                                         context_used = mini_class_check_context_used (cfg, ((MonoClassField*)handle)->parent);
11281                                 else if (handle_class == mono_defaults.methodhandle_class)
11282                                         context_used = mini_method_check_context_used (cfg, (MonoMethod *)handle);
11283                                 else
11284                                         g_assert_not_reached ();
11285                         }
11286
11287                         if ((cfg->opt & MONO_OPT_SHARED) &&
11288                                         method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD &&
11289                                         method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED) {
11290                                 MonoInst *addr, *vtvar, *iargs [3];
11291                                 int method_context_used;
11292
11293                                 method_context_used = mini_method_check_context_used (cfg, method);
11294
11295                                 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL); 
11296
11297                                 EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
11298                                 EMIT_NEW_ICONST (cfg, iargs [1], n);
11299                                 if (method_context_used) {
11300                                         iargs [2] = emit_get_rgctx_method (cfg, method_context_used,
11301                                                 method, MONO_RGCTX_INFO_METHOD);
11302                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper_generic_shared, iargs);
11303                                 } else {
11304                                         EMIT_NEW_PCONST (cfg, iargs [2], generic_context);
11305                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper, iargs);
11306                                 }
11307                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
11308
11309                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
11310
11311                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
11312                         } else {
11313                                 if ((ip + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 5) && 
11314                                         ((ip [5] == CEE_CALL) || (ip [5] == CEE_CALLVIRT)) && 
11315                                         (cmethod = mini_get_method (cfg, method, read32 (ip + 6), NULL, generic_context)) &&
11316                                         (cmethod->klass == mono_defaults.systemtype_class) &&
11317                                         (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
11318                                         MonoClass *tclass = mono_class_from_mono_type ((MonoType *)handle);
11319
11320                                         mono_class_init (tclass);
11321                                         if (context_used) {
11322                                                 ins = mini_emit_get_rgctx_klass (cfg, context_used,
11323                                                         tclass, MONO_RGCTX_INFO_REFLECTION_TYPE);
11324                                         } else if (cfg->compile_aot) {
11325                                                 if (method->wrapper_type) {
11326                                                         error_init (&error); //got to do it since there are multiple conditionals below
11327                                                         if (mono_class_get_checked (tclass->image, tclass->type_token, &error) == tclass && !generic_context) {
11328                                                                 /* Special case for static synchronized wrappers */
11329                                                                 EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, tclass->image, tclass->type_token, generic_context);
11330                                                         } else {
11331                                                                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
11332                                                                 /* FIXME: n is not a normal token */
11333                                                                 DISABLE_AOT (cfg);
11334                                                                 EMIT_NEW_PCONST (cfg, ins, NULL);
11335                                                         }
11336                                                 } else {
11337                                                         EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n, generic_context);
11338                                                 }
11339                                         } else {
11340                                                 MonoReflectionType *rt = mono_type_get_object_checked (cfg->domain, (MonoType *)handle, &cfg->error);
11341                                                 CHECK_CFG_ERROR;
11342                                                 EMIT_NEW_PCONST (cfg, ins, rt);
11343                                         }
11344                                         ins->type = STACK_OBJ;
11345                                         ins->klass = cmethod->klass;
11346                                         ip += 5;
11347                                 } else {
11348                                         MonoInst *addr, *vtvar;
11349
11350                                         vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
11351
11352                                         if (context_used) {
11353                                                 if (handle_class == mono_defaults.typehandle_class) {
11354                                                         ins = mini_emit_get_rgctx_klass (cfg, context_used,
11355                                                                         mono_class_from_mono_type ((MonoType *)handle),
11356                                                                         MONO_RGCTX_INFO_TYPE);
11357                                                 } else if (handle_class == mono_defaults.methodhandle_class) {
11358                                                         ins = emit_get_rgctx_method (cfg, context_used,
11359                                                                         (MonoMethod *)handle, MONO_RGCTX_INFO_METHOD);
11360                                                 } else if (handle_class == mono_defaults.fieldhandle_class) {
11361                                                         ins = emit_get_rgctx_field (cfg, context_used,
11362                                                                         (MonoClassField *)handle, MONO_RGCTX_INFO_CLASS_FIELD);
11363                                                 } else {
11364                                                         g_assert_not_reached ();
11365                                                 }
11366                                         } else if (cfg->compile_aot) {
11367                                                 EMIT_NEW_LDTOKENCONST (cfg, ins, image, n, generic_context);
11368                                         } else {
11369                                                 EMIT_NEW_PCONST (cfg, ins, handle);
11370                                         }
11371                                         EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
11372                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
11373                                         EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
11374                                 }
11375                         }
11376
11377                         *sp++ = ins;
11378                         ip += 5;
11379                         break;
11380                 }
11381                 case CEE_THROW:
11382                         CHECK_STACK (1);
11383                         if (sp [-1]->type != STACK_OBJ)
11384                                 UNVERIFIED;
11385
11386                         MONO_INST_NEW (cfg, ins, OP_THROW);
11387                         --sp;
11388                         ins->sreg1 = sp [0]->dreg;
11389                         ip++;
11390                         cfg->cbb->out_of_line = TRUE;
11391                         MONO_ADD_INS (cfg->cbb, ins);
11392                         MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
11393                         MONO_ADD_INS (cfg->cbb, ins);
11394                         sp = stack_start;
11395                         
11396                         link_bblock (cfg, cfg->cbb, end_bblock);
11397                         start_new_bblock = 1;
11398                         /* This can complicate code generation for llvm since the return value might not be defined */
11399                         if (COMPILE_LLVM (cfg))
11400                                 INLINE_FAILURE ("throw");
11401                         break;
11402                 case CEE_ENDFINALLY:
11403                         if (!ip_in_finally_clause (cfg, ip - header->code))
11404                                 UNVERIFIED;
11405                         /* mono_save_seq_point_info () depends on this */
11406                         if (sp != stack_start)
11407                                 emit_seq_point (cfg, method, ip, FALSE, FALSE);
11408                         MONO_INST_NEW (cfg, ins, OP_ENDFINALLY);
11409                         MONO_ADD_INS (cfg->cbb, ins);
11410                         ip++;
11411                         start_new_bblock = 1;
11412
11413                         /*
11414                          * Control will leave the method so empty the stack, otherwise
11415                          * the next basic block will start with a nonempty stack.
11416                          */
11417                         while (sp != stack_start) {
11418                                 sp--;
11419                         }
11420                         break;
11421                 case CEE_LEAVE:
11422                 case CEE_LEAVE_S: {
11423                         GList *handlers;
11424
11425                         if (*ip == CEE_LEAVE) {
11426                                 CHECK_OPSIZE (5);
11427                                 target = ip + 5 + (gint32)read32(ip + 1);
11428                         } else {
11429                                 CHECK_OPSIZE (2);
11430                                 target = ip + 2 + (signed char)(ip [1]);
11431                         }
11432
11433                         /* empty the stack */
11434                         while (sp != stack_start) {
11435                                 sp--;
11436                         }
11437
11438                         /* 
11439                          * If this leave statement is in a catch block, check for a
11440                          * pending exception, and rethrow it if necessary.
11441                          * We avoid doing this in runtime invoke wrappers, since those are called
11442                          * by native code which excepts the wrapper to catch all exceptions.
11443                          */
11444                         for (i = 0; i < header->num_clauses; ++i) {
11445                                 MonoExceptionClause *clause = &header->clauses [i];
11446
11447                                 /* 
11448                                  * Use <= in the final comparison to handle clauses with multiple
11449                                  * leave statements, like in bug #78024.
11450                                  * The ordering of the exception clauses guarantees that we find the
11451                                  * innermost clause.
11452                                  */
11453                                 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) {
11454                                         MonoInst *exc_ins;
11455                                         MonoBasicBlock *dont_throw;
11456
11457                                         /*
11458                                           MonoInst *load;
11459
11460                                           NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, clause->handler_offset)->inst_c0);
11461                                         */
11462
11463                                         exc_ins = mono_emit_jit_icall (cfg, mono_thread_get_undeniable_exception, NULL);
11464
11465                                         NEW_BBLOCK (cfg, dont_throw);
11466
11467                                         /*
11468                                          * Currently, we always rethrow the abort exception, despite the 
11469                                          * fact that this is not correct. See thread6.cs for an example. 
11470                                          * But propagating the abort exception is more important than 
11471                                          * getting the sematics right.
11472                                          */
11473                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, exc_ins->dreg, 0);
11474                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, dont_throw);
11475                                         MONO_EMIT_NEW_UNALU (cfg, OP_THROW, -1, exc_ins->dreg);
11476
11477                                         MONO_START_BB (cfg, dont_throw);
11478                                 }
11479                         }
11480
11481 #ifdef ENABLE_LLVM
11482                         cfg->cbb->try_end = (intptr_t)(ip - header->code);
11483 #endif
11484
11485                         if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
11486                                 GList *tmp;
11487
11488                                 for (tmp = handlers; tmp; tmp = tmp->next) {
11489                                         MonoExceptionClause *clause = (MonoExceptionClause *)tmp->data;
11490                                         MonoInst *abort_exc = (MonoInst *)mono_find_exvar_for_offset (cfg, clause->handler_offset);
11491                                         MonoBasicBlock *dont_throw;
11492
11493                                         tblock = cfg->cil_offset_to_bb [clause->handler_offset];
11494                                         g_assert (tblock);
11495                                         link_bblock (cfg, cfg->cbb, tblock);
11496
11497                                         MONO_EMIT_NEW_PCONST (cfg, abort_exc->dreg, 0);
11498
11499                                         MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
11500                                         ins->inst_target_bb = tblock;
11501                                         ins->inst_eh_block = clause;
11502                                         MONO_ADD_INS (cfg->cbb, ins);
11503                                         cfg->cbb->has_call_handler = 1;
11504
11505                                         /* Throw exception if exvar is set */
11506                                         /* FIXME Do we need this for calls from catch/filter ? */
11507                                         NEW_BBLOCK (cfg, dont_throw);
11508                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, abort_exc->dreg, 0);
11509                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, dont_throw);
11510                                         mono_emit_jit_icall (cfg, mono_thread_self_abort, NULL);
11511                                         cfg->cbb->clause_hole = clause;
11512
11513                                         MONO_START_BB (cfg, dont_throw);
11514                                         cfg->cbb->clause_hole = clause;
11515
11516                                         if (COMPILE_LLVM (cfg)) {
11517                                                 MonoBasicBlock *target_bb;
11518
11519                                                 /* 
11520                                                  * Link the finally bblock with the target, since it will
11521                                                  * conceptually branch there.
11522                                                  */
11523                                                 GET_BBLOCK (cfg, tblock, cfg->cil_start + clause->handler_offset + clause->handler_len - 1);
11524                                                 GET_BBLOCK (cfg, target_bb, target);
11525                                                 link_bblock (cfg, tblock, target_bb);
11526                                         }
11527                                 }
11528                                 g_list_free (handlers);
11529                         } 
11530
11531                         MONO_INST_NEW (cfg, ins, OP_BR);
11532                         MONO_ADD_INS (cfg->cbb, ins);
11533                         GET_BBLOCK (cfg, tblock, target);
11534                         link_bblock (cfg, cfg->cbb, tblock);
11535                         ins->inst_target_bb = tblock;
11536
11537                         start_new_bblock = 1;
11538
11539                         if (*ip == CEE_LEAVE)
11540                                 ip += 5;
11541                         else
11542                                 ip += 2;
11543
11544                         break;
11545                 }
11546
11547                         /*
11548                          * Mono specific opcodes
11549                          */
11550                 case MONO_CUSTOM_PREFIX: {
11551
11552                         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
11553
11554                         CHECK_OPSIZE (2);
11555                         switch (ip [1]) {
11556                         case CEE_MONO_ICALL: {
11557                                 gpointer func;
11558                                 MonoJitICallInfo *info;
11559
11560                                 token = read32 (ip + 2);
11561                                 func = mono_method_get_wrapper_data (method, token);
11562                                 info = mono_find_jit_icall_by_addr (func);
11563                                 if (!info)
11564                                         g_error ("Could not find icall address in wrapper %s", mono_method_full_name (method, 1));
11565                                 g_assert (info);
11566
11567                                 CHECK_STACK (info->sig->param_count);
11568                                 sp -= info->sig->param_count;
11569
11570                                 if (cfg->compile_aot && !strcmp (info->name, "mono_threads_attach_coop")) {
11571                                         MonoInst *addr;
11572
11573                                         /*
11574                                          * This is called on unattached threads, so it cannot go through the trampoline
11575                                          * infrastructure. Use an indirect call through a got slot initialized at load time
11576                                          * instead.
11577                                          */
11578                                         EMIT_NEW_AOTCONST (cfg, addr, MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL, (char*)info->name);
11579                                         ins = mini_emit_calli (cfg, info->sig, sp, addr, NULL, NULL);
11580                                 } else {
11581                                         ins = mono_emit_jit_icall (cfg, info->func, sp);
11582                                 }
11583
11584                                 if (!MONO_TYPE_IS_VOID (info->sig->ret))
11585                                         *sp++ = ins;
11586
11587                                 ip += 6;
11588                                 inline_costs += 10 * num_calls++;
11589
11590                                 break;
11591                         }
11592                         case CEE_MONO_LDPTR_CARD_TABLE:
11593                         case CEE_MONO_LDPTR_NURSERY_START:
11594                         case CEE_MONO_LDPTR_NURSERY_BITS:
11595                         case CEE_MONO_LDPTR_INT_REQ_FLAG:
11596                         case CEE_MONO_LDPTR_PROFILER_ALLOCATION_COUNT: {
11597                                 CHECK_STACK_OVF (1);
11598
11599                                 switch (ip [1]) {
11600                                 case CEE_MONO_LDPTR_CARD_TABLE:
11601                                         ins = mini_emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR, NULL);
11602                                         break;
11603                                 case CEE_MONO_LDPTR_NURSERY_START:
11604                                         ins = mini_emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_NURSERY_START, NULL);
11605                                         break;
11606                                 case CEE_MONO_LDPTR_NURSERY_BITS:
11607                                         ins = mini_emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_NURSERY_BITS, NULL);
11608                                         break;
11609                                 case CEE_MONO_LDPTR_INT_REQ_FLAG:
11610                                         ins = mini_emit_runtime_constant (cfg, MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG, NULL);
11611                                         break;
11612                                 case CEE_MONO_LDPTR_PROFILER_ALLOCATION_COUNT:
11613                                         ins = mini_emit_runtime_constant (cfg, MONO_PATCH_INFO_PROFILER_ALLOCATION_COUNT, NULL);
11614                                         break;
11615                                 default:
11616                                         g_assert_not_reached ();
11617                                         break;
11618                                 }
11619
11620                                 *sp++ = ins;
11621                                 ip += 2;
11622                                 inline_costs += 10 * num_calls++;
11623                                 break;
11624                         }
11625                         case CEE_MONO_LDPTR: {
11626                                 gpointer ptr;
11627
11628                                 CHECK_STACK_OVF (1);
11629                                 CHECK_OPSIZE (6);
11630                                 token = read32 (ip + 2);
11631
11632                                 ptr = mono_method_get_wrapper_data (method, token);
11633                                 EMIT_NEW_PCONST (cfg, ins, ptr);
11634                                 *sp++ = ins;
11635                                 ip += 6;
11636                                 inline_costs += 10 * num_calls++;
11637                                 /* Can't embed random pointers into AOT code */
11638                                 DISABLE_AOT (cfg);
11639                                 break;
11640                         }
11641                         case CEE_MONO_JIT_ICALL_ADDR: {
11642                                 MonoJitICallInfo *callinfo;
11643                                 gpointer ptr;
11644
11645                                 CHECK_STACK_OVF (1);
11646                                 CHECK_OPSIZE (6);
11647                                 token = read32 (ip + 2);
11648
11649                                 ptr = mono_method_get_wrapper_data (method, token);
11650                                 callinfo = mono_find_jit_icall_by_addr (ptr);
11651                                 g_assert (callinfo);
11652                                 EMIT_NEW_JIT_ICALL_ADDRCONST (cfg, ins, (char*)callinfo->name);
11653                                 *sp++ = ins;
11654                                 ip += 6;
11655                                 inline_costs += 10 * num_calls++;
11656                                 break;
11657                         }
11658                         case CEE_MONO_ICALL_ADDR: {
11659                                 MonoMethod *cmethod;
11660                                 gpointer ptr;
11661
11662                                 CHECK_STACK_OVF (1);
11663                                 CHECK_OPSIZE (6);
11664                                 token = read32 (ip + 2);
11665
11666                                 cmethod = (MonoMethod *)mono_method_get_wrapper_data (method, token);
11667
11668                                 if (cfg->compile_aot) {
11669                                         if (cfg->direct_pinvoke && ip + 6 < end && (ip [6] == CEE_POP)) {
11670                                                 /*
11671                                                  * This is generated by emit_native_wrapper () to resolve the pinvoke address
11672                                                  * before the call, its not needed when using direct pinvoke.
11673                                                  * This is not an optimization, but its used to avoid looking up pinvokes
11674                                                  * on platforms which don't support dlopen ().
11675                                                  */
11676                                                 EMIT_NEW_PCONST (cfg, ins, NULL);
11677                                         } else {
11678                                                 EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, cmethod);
11679                                         }
11680                                 } else {
11681                                         ptr = mono_lookup_internal_call (cmethod);
11682                                         g_assert (ptr);
11683                                         EMIT_NEW_PCONST (cfg, ins, ptr);
11684                                 }
11685                                 *sp++ = ins;
11686                                 ip += 6;
11687                                 break;
11688                         }
11689                         case CEE_MONO_VTADDR: {
11690                                 MonoInst *src_var, *src;
11691
11692                                 CHECK_STACK (1);
11693                                 --sp;
11694
11695                                 // FIXME:
11696                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
11697                                 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
11698                                 *sp++ = src;
11699                                 ip += 2;
11700                                 break;
11701                         }
11702                         case CEE_MONO_NEWOBJ: {
11703                                 MonoInst *iargs [2];
11704
11705                                 CHECK_STACK_OVF (1);
11706                                 CHECK_OPSIZE (6);
11707                                 token = read32 (ip + 2);
11708                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
11709                                 mono_class_init (klass);
11710                                 NEW_DOMAINCONST (cfg, iargs [0]);
11711                                 MONO_ADD_INS (cfg->cbb, iargs [0]);
11712                                 NEW_CLASSCONST (cfg, iargs [1], klass);
11713                                 MONO_ADD_INS (cfg->cbb, iargs [1]);
11714                                 *sp++ = mono_emit_jit_icall (cfg, ves_icall_object_new, iargs);
11715                                 ip += 6;
11716                                 inline_costs += 10 * num_calls++;
11717                                 break;
11718                         }
11719                         case CEE_MONO_OBJADDR:
11720                                 CHECK_STACK (1);
11721                                 --sp;
11722                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
11723                                 ins->dreg = alloc_ireg_mp (cfg);
11724                                 ins->sreg1 = sp [0]->dreg;
11725                                 ins->type = STACK_MP;
11726                                 MONO_ADD_INS (cfg->cbb, ins);
11727                                 *sp++ = ins;
11728                                 ip += 2;
11729                                 break;
11730                         case CEE_MONO_LDNATIVEOBJ:
11731                                 /*
11732                                  * Similar to LDOBJ, but instead load the unmanaged 
11733                                  * representation of the vtype to the stack.
11734                                  */
11735                                 CHECK_STACK (1);
11736                                 CHECK_OPSIZE (6);
11737                                 --sp;
11738                                 token = read32 (ip + 2);
11739                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
11740                                 g_assert (klass->valuetype);
11741                                 mono_class_init (klass);
11742
11743                                 {
11744                                         MonoInst *src, *dest, *temp;
11745
11746                                         src = sp [0];
11747                                         temp = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
11748                                         temp->backend.is_pinvoke = 1;
11749                                         EMIT_NEW_TEMPLOADA (cfg, dest, temp->inst_c0);
11750                                         mini_emit_memory_copy (cfg, dest, src, klass, TRUE, 0);
11751
11752                                         EMIT_NEW_TEMPLOAD (cfg, dest, temp->inst_c0);
11753                                         dest->type = STACK_VTYPE;
11754                                         dest->klass = klass;
11755
11756                                         *sp ++ = dest;
11757                                         ip += 6;
11758                                 }
11759                                 break;
11760                         case CEE_MONO_RETOBJ: {
11761                                 /*
11762                                  * Same as RET, but return the native representation of a vtype
11763                                  * to the caller.
11764                                  */
11765                                 g_assert (cfg->ret);
11766                                 g_assert (mono_method_signature (method)->pinvoke); 
11767                                 CHECK_STACK (1);
11768                                 --sp;
11769                                 
11770                                 CHECK_OPSIZE (6);
11771                                 token = read32 (ip + 2);    
11772                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
11773
11774                                 if (!cfg->vret_addr) {
11775                                         g_assert (cfg->ret_var_is_local);
11776
11777                                         EMIT_NEW_VARLOADA (cfg, ins, cfg->ret, cfg->ret->inst_vtype);
11778                                 } else {
11779                                         EMIT_NEW_RETLOADA (cfg, ins);
11780                                 }
11781                                 mini_emit_memory_copy (cfg, ins, sp [0], klass, TRUE, 0);
11782                                 
11783                                 if (sp != stack_start)
11784                                         UNVERIFIED;
11785                                 
11786                                 mini_profiler_emit_leave (cfg, sp [0]);
11787
11788                                 MONO_INST_NEW (cfg, ins, OP_BR);
11789                                 ins->inst_target_bb = end_bblock;
11790                                 MONO_ADD_INS (cfg->cbb, ins);
11791                                 link_bblock (cfg, cfg->cbb, end_bblock);
11792                                 start_new_bblock = 1;
11793                                 ip += 6;
11794                                 break;
11795                         }
11796                         case CEE_MONO_SAVE_LMF:
11797                         case CEE_MONO_RESTORE_LMF:
11798                                 ip += 2;
11799                                 break;
11800                         case CEE_MONO_CLASSCONST:
11801                                 CHECK_STACK_OVF (1);
11802                                 CHECK_OPSIZE (6);
11803                                 token = read32 (ip + 2);
11804                                 EMIT_NEW_CLASSCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
11805                                 *sp++ = ins;
11806                                 ip += 6;
11807                                 inline_costs += 10 * num_calls++;
11808                                 break;
11809                         case CEE_MONO_NOT_TAKEN:
11810                                 cfg->cbb->out_of_line = TRUE;
11811                                 ip += 2;
11812                                 break;
11813                         case CEE_MONO_TLS: {
11814                                 MonoTlsKey key;
11815
11816                                 CHECK_STACK_OVF (1);
11817                                 CHECK_OPSIZE (6);
11818                                 key = (MonoTlsKey)read32 (ip + 2);
11819                                 g_assert (key < TLS_KEY_NUM);
11820
11821                                 ins = mono_create_tls_get (cfg, key);
11822                                 g_assert (ins);
11823                                 ins->type = STACK_PTR;
11824                                 *sp++ = ins;
11825                                 ip += 6;
11826                                 break;
11827                         }
11828                         case CEE_MONO_DYN_CALL: {
11829                                 MonoCallInst *call;
11830
11831                                 /* It would be easier to call a trampoline, but that would put an
11832                                  * extra frame on the stack, confusing exception handling. So
11833                                  * implement it inline using an opcode for now.
11834                                  */
11835
11836                                 if (!cfg->dyn_call_var) {
11837                                         cfg->dyn_call_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
11838                                         /* prevent it from being register allocated */
11839                                         cfg->dyn_call_var->flags |= MONO_INST_VOLATILE;
11840                                 }
11841
11842                                 /* Has to use a call inst since local regalloc expects it */
11843                                 MONO_INST_NEW_CALL (cfg, call, OP_DYN_CALL);
11844                                 ins = (MonoInst*)call;
11845                                 sp -= 2;
11846                                 ins->sreg1 = sp [0]->dreg;
11847                                 ins->sreg2 = sp [1]->dreg;
11848                                 MONO_ADD_INS (cfg->cbb, ins);
11849
11850                                 cfg->param_area = MAX (cfg->param_area, cfg->backend->dyn_call_param_area);
11851                                 /* OP_DYN_CALL might need to allocate a dynamically sized param area */
11852                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
11853
11854                                 ip += 2;
11855                                 inline_costs += 10 * num_calls++;
11856
11857                                 break;
11858                         }
11859                         case CEE_MONO_MEMORY_BARRIER: {
11860                                 CHECK_OPSIZE (6);
11861                                 mini_emit_memory_barrier (cfg, (int)read32 (ip + 2));
11862                                 ip += 6;
11863                                 break;
11864                         }
11865                         case CEE_MONO_ATOMIC_STORE_I4: {
11866                                 g_assert (mono_arch_opcode_supported (OP_ATOMIC_STORE_I4));
11867
11868                                 CHECK_OPSIZE (6);
11869                                 CHECK_STACK (2);
11870                                 sp -= 2;
11871
11872                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_STORE_I4);
11873                                 ins->dreg = sp [0]->dreg;
11874                                 ins->sreg1 = sp [1]->dreg;
11875                                 ins->backend.memory_barrier_kind = (int) read32 (ip + 2);
11876                                 MONO_ADD_INS (cfg->cbb, ins);
11877
11878                                 ip += 6;
11879                                 break;
11880                         }
11881                         case CEE_MONO_JIT_ATTACH: {
11882                                 MonoInst *args [16], *domain_ins;
11883                                 MonoInst *ad_ins, *jit_tls_ins;
11884                                 MonoBasicBlock *next_bb = NULL, *call_bb = NULL;
11885
11886                                 g_assert (!mono_threads_is_blocking_transition_enabled ());
11887
11888                                 cfg->orig_domain_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
11889
11890                                 EMIT_NEW_PCONST (cfg, ins, NULL);
11891                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
11892
11893                                 ad_ins = mono_create_tls_get (cfg, TLS_KEY_DOMAIN);
11894                                 jit_tls_ins = mono_create_tls_get (cfg, TLS_KEY_JIT_TLS);
11895
11896                                 if (ad_ins && jit_tls_ins) {
11897                                         NEW_BBLOCK (cfg, next_bb);
11898                                         NEW_BBLOCK (cfg, call_bb);
11899
11900                                         if (cfg->compile_aot) {
11901                                                 /* AOT code is only used in the root domain */
11902                                                 EMIT_NEW_PCONST (cfg, domain_ins, NULL);
11903                                         } else {
11904                                                 EMIT_NEW_PCONST (cfg, domain_ins, cfg->domain);
11905                                         }
11906                                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, ad_ins->dreg, domain_ins->dreg);
11907                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, call_bb);
11908
11909                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, jit_tls_ins->dreg, 0);
11910                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, call_bb);
11911
11912                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, next_bb);
11913                                         MONO_START_BB (cfg, call_bb);
11914                                 }
11915
11916                                 /* AOT code is only used in the root domain */
11917                                 EMIT_NEW_PCONST (cfg, args [0], cfg->compile_aot ? NULL : cfg->domain);
11918                                 if (cfg->compile_aot) {
11919                                         MonoInst *addr;
11920
11921                                         /*
11922                                          * This is called on unattached threads, so it cannot go through the trampoline
11923                                          * infrastructure. Use an indirect call through a got slot initialized at load time
11924                                          * instead.
11925                                          */
11926                                         EMIT_NEW_AOTCONST (cfg, addr, MONO_PATCH_INFO_JIT_THREAD_ATTACH, NULL);
11927                                         ins = mini_emit_calli (cfg, helper_sig_jit_thread_attach, args, addr, NULL, NULL);
11928                                 } else {
11929                                         ins = mono_emit_jit_icall (cfg, mono_jit_thread_attach, args);
11930                                 }
11931                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
11932
11933                                 if (next_bb)
11934                                         MONO_START_BB (cfg, next_bb);
11935
11936                                 ip += 2;
11937                                 break;
11938                         }
11939                         case CEE_MONO_JIT_DETACH: {
11940                                 MonoInst *args [16];
11941
11942                                 /* Restore the original domain */
11943                                 dreg = alloc_ireg (cfg);
11944                                 EMIT_NEW_UNALU (cfg, args [0], OP_MOVE, dreg, cfg->orig_domain_var->dreg);
11945                                 mono_emit_jit_icall (cfg, mono_jit_set_domain, args);
11946                                 ip += 2;
11947                                 break;
11948                         }
11949                         case CEE_MONO_CALLI_EXTRA_ARG: {
11950                                 MonoInst *addr;
11951                                 MonoMethodSignature *fsig;
11952                                 MonoInst *arg;
11953
11954                                 /*
11955                                  * This is the same as CEE_CALLI, but passes an additional argument
11956                                  * to the called method in llvmonly mode.
11957                                  * This is only used by delegate invoke wrappers to call the
11958                                  * actual delegate method.
11959                                  */
11960                                 g_assert (method->wrapper_type == MONO_WRAPPER_DELEGATE_INVOKE);
11961
11962                                 CHECK_OPSIZE (6);
11963                                 token = read32 (ip + 2);
11964
11965                                 ins = NULL;
11966
11967                                 cmethod = NULL;
11968                                 CHECK_STACK (1);
11969                                 --sp;
11970                                 addr = *sp;
11971                                 fsig = mini_get_signature (method, token, generic_context, &cfg->error);
11972                                 CHECK_CFG_ERROR;
11973
11974                                 if (cfg->llvm_only)
11975                                         cfg->signatures = g_slist_prepend_mempool (cfg->mempool, cfg->signatures, fsig);
11976
11977                                 n = fsig->param_count + fsig->hasthis + 1;
11978
11979                                 CHECK_STACK (n);
11980
11981                                 sp -= n;
11982                                 arg = sp [n - 1];
11983
11984                                 if (cfg->llvm_only) {
11985                                         /*
11986                                          * The lowest bit of 'arg' determines whenever the callee uses the gsharedvt
11987                                          * cconv. This is set by mono_init_delegate ().
11988                                          */
11989                                         if (cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig)) {
11990                                                 MonoInst *callee = addr;
11991                                                 MonoInst *call, *localloc_ins;
11992                                                 MonoBasicBlock *is_gsharedvt_bb, *end_bb;
11993                                                 int low_bit_reg = alloc_preg (cfg);
11994
11995                                                 NEW_BBLOCK (cfg, is_gsharedvt_bb);
11996                                                 NEW_BBLOCK (cfg, end_bb);
11997
11998                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, low_bit_reg, arg->dreg, 1);
11999                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_bit_reg, 0);
12000                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, is_gsharedvt_bb);
12001
12002                                                 /* Normal case: callee uses a normal cconv, have to add an out wrapper */
12003                                                 addr = emit_get_rgctx_sig (cfg, context_used,
12004                                                                                                    fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
12005                                                 /*
12006                                                  * ADDR points to a gsharedvt-out wrapper, have to pass <callee, arg> as an extra arg.
12007                                                  */
12008                                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
12009                                                 ins->dreg = alloc_preg (cfg);
12010                                                 ins->inst_imm = 2 * SIZEOF_VOID_P;
12011                                                 MONO_ADD_INS (cfg->cbb, ins);
12012                                                 localloc_ins = ins;
12013                                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12014                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, 0, callee->dreg);
12015                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, SIZEOF_VOID_P, arg->dreg);
12016
12017                                                 call = emit_extra_arg_calli (cfg, fsig, sp, localloc_ins->dreg, addr);
12018                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12019
12020                                                 /* Gsharedvt case: callee uses a gsharedvt cconv, no conversion is needed */
12021                                                 MONO_START_BB (cfg, is_gsharedvt_bb);
12022                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PXOR_IMM, arg->dreg, arg->dreg, 1);
12023                                                 ins = emit_extra_arg_calli (cfg, fsig, sp, arg->dreg, callee);
12024                                                 ins->dreg = call->dreg;
12025
12026                                                 MONO_START_BB (cfg, end_bb);
12027                                         } else {
12028                                                 /* Caller uses a normal calling conv */
12029
12030                                                 MonoInst *callee = addr;
12031                                                 MonoInst *call, *localloc_ins;
12032                                                 MonoBasicBlock *is_gsharedvt_bb, *end_bb;
12033                                                 int low_bit_reg = alloc_preg (cfg);
12034
12035                                                 NEW_BBLOCK (cfg, is_gsharedvt_bb);
12036                                                 NEW_BBLOCK (cfg, end_bb);
12037
12038                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, low_bit_reg, arg->dreg, 1);
12039                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_bit_reg, 0);
12040                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, is_gsharedvt_bb);
12041
12042                                                 /* Normal case: callee uses a normal cconv, no conversion is needed */
12043                                                 call = emit_extra_arg_calli (cfg, fsig, sp, arg->dreg, callee);
12044                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12045                                                 /* Gsharedvt case: callee uses a gsharedvt cconv, have to add an in wrapper */
12046                                                 MONO_START_BB (cfg, is_gsharedvt_bb);
12047                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PXOR_IMM, arg->dreg, arg->dreg, 1);
12048                                                 NEW_AOTCONST (cfg, addr, MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER, fsig);
12049                                                 MONO_ADD_INS (cfg->cbb, addr);
12050                                                 /*
12051                                                  * ADDR points to a gsharedvt-in wrapper, have to pass <callee, arg> as an extra arg.
12052                                                  */
12053                                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
12054                                                 ins->dreg = alloc_preg (cfg);
12055                                                 ins->inst_imm = 2 * SIZEOF_VOID_P;
12056                                                 MONO_ADD_INS (cfg->cbb, ins);
12057                                                 localloc_ins = ins;
12058                                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12059                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, 0, callee->dreg);
12060                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, SIZEOF_VOID_P, arg->dreg);
12061
12062                                                 ins = emit_extra_arg_calli (cfg, fsig, sp, localloc_ins->dreg, addr);
12063                                                 ins->dreg = call->dreg;
12064                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12065
12066                                                 MONO_START_BB (cfg, end_bb);
12067                                         }
12068                                 } else {
12069                                         /* Same as CEE_CALLI */
12070                                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
12071                                                 /*
12072                                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
12073                                                  */
12074                                                 MonoInst *callee = addr;
12075
12076                                                 addr = emit_get_rgctx_sig (cfg, context_used,
12077                                                                                                    fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
12078                                                 ins = (MonoInst*)mini_emit_calli (cfg, fsig, sp, addr, NULL, callee);
12079                                         } else {
12080                                                 ins = (MonoInst*)mini_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
12081                                         }
12082                                 }
12083
12084                                 if (!MONO_TYPE_IS_VOID (fsig->ret))
12085                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
12086
12087                                 CHECK_CFG_EXCEPTION;
12088
12089                                 ip += 6;
12090                                 ins_flag = 0;
12091                                 constrained_class = NULL;
12092                                 break;
12093                         }
12094                         case CEE_MONO_LDDOMAIN:
12095                                 CHECK_STACK_OVF (1);
12096                                 EMIT_NEW_PCONST (cfg, ins, cfg->compile_aot ? NULL : cfg->domain);
12097                                 ip += 2;
12098                                 *sp++ = ins;
12099                                 break;
12100                         case CEE_MONO_GET_LAST_ERROR:
12101                                 CHECK_OPSIZE (2);
12102                                 CHECK_STACK_OVF (1);
12103
12104                                 MONO_INST_NEW (cfg, ins, OP_GET_LAST_ERROR);
12105                                 ins->dreg = alloc_dreg (cfg, STACK_I4);
12106                                 ins->type = STACK_I4;
12107                                 MONO_ADD_INS (cfg->cbb, ins);
12108
12109                                 ip += 2;
12110                                 *sp++ = ins;
12111                                 break;
12112                         case CEE_MONO_GET_RGCTX_ARG:
12113                                 CHECK_OPSIZE (2);
12114                                 CHECK_STACK_OVF (1);
12115
12116                                 mono_create_rgctx_var (cfg);
12117
12118                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
12119                                 ins->dreg = alloc_dreg (cfg, STACK_PTR);
12120                                 ins->sreg1 = cfg->rgctx_var->dreg;
12121                                 ins->type = STACK_PTR;
12122                                 MONO_ADD_INS (cfg->cbb, ins);
12123
12124                                 ip += 2;
12125                                 *sp++ = ins;
12126                                 break;
12127                         default:
12128                                 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
12129                                 break;
12130                         }
12131                         break;
12132                 }
12133
12134                 case CEE_PREFIX1: {
12135                         CHECK_OPSIZE (2);
12136                         switch (ip [1]) {
12137                         case CEE_ARGLIST: {
12138                                 /* somewhat similar to LDTOKEN */
12139                                 MonoInst *addr, *vtvar;
12140                                 CHECK_STACK_OVF (1);
12141                                 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL); 
12142
12143                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
12144                                 EMIT_NEW_UNALU (cfg, ins, OP_ARGLIST, -1, addr->dreg);
12145
12146                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
12147                                 ins->type = STACK_VTYPE;
12148                                 ins->klass = mono_defaults.argumenthandle_class;
12149                                 *sp++ = ins;
12150                                 ip += 2;
12151                                 break;
12152                         }
12153                         case CEE_CEQ:
12154                         case CEE_CGT:
12155                         case CEE_CGT_UN:
12156                         case CEE_CLT:
12157                         case CEE_CLT_UN: {
12158                                 MonoInst *cmp, *arg1, *arg2;
12159
12160                                 CHECK_STACK (2);
12161                                 sp -= 2;
12162                                 arg1 = sp [0];
12163                                 arg2 = sp [1];
12164
12165                                 /*
12166                                  * The following transforms:
12167                                  *    CEE_CEQ    into OP_CEQ
12168                                  *    CEE_CGT    into OP_CGT
12169                                  *    CEE_CGT_UN into OP_CGT_UN
12170                                  *    CEE_CLT    into OP_CLT
12171                                  *    CEE_CLT_UN into OP_CLT_UN
12172                                  */
12173                                 MONO_INST_NEW (cfg, cmp, (OP_CEQ - CEE_CEQ) + ip [1]);
12174
12175                                 MONO_INST_NEW (cfg, ins, cmp->opcode);
12176                                 cmp->sreg1 = arg1->dreg;
12177                                 cmp->sreg2 = arg2->dreg;
12178                                 type_from_op (cfg, cmp, arg1, arg2);
12179                                 CHECK_TYPE (cmp);
12180                                 add_widen_op (cfg, cmp, &arg1, &arg2);
12181                                 if ((arg1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((arg1->type == STACK_PTR) || (arg1->type == STACK_OBJ) || (arg1->type == STACK_MP))))
12182                                         cmp->opcode = OP_LCOMPARE;
12183                                 else if (arg1->type == STACK_R4)
12184                                         cmp->opcode = OP_RCOMPARE;
12185                                 else if (arg1->type == STACK_R8)
12186                                         cmp->opcode = OP_FCOMPARE;
12187                                 else
12188                                         cmp->opcode = OP_ICOMPARE;
12189                                 MONO_ADD_INS (cfg->cbb, cmp);
12190                                 ins->type = STACK_I4;
12191                                 ins->dreg = alloc_dreg (cfg, (MonoStackType)ins->type);
12192                                 type_from_op (cfg, ins, arg1, arg2);
12193
12194                                 if (cmp->opcode == OP_FCOMPARE || cmp->opcode == OP_RCOMPARE) {
12195                                         /*
12196                                          * The backends expect the fceq opcodes to do the
12197                                          * comparison too.
12198                                          */
12199                                         ins->sreg1 = cmp->sreg1;
12200                                         ins->sreg2 = cmp->sreg2;
12201                                         NULLIFY_INS (cmp);
12202                                 }
12203                                 MONO_ADD_INS (cfg->cbb, ins);
12204                                 *sp++ = ins;
12205                                 ip += 2;
12206                                 break;
12207                         }
12208                         case CEE_LDFTN: {
12209                                 MonoInst *argconst;
12210                                 MonoMethod *cil_method;
12211
12212                                 CHECK_STACK_OVF (1);
12213                                 CHECK_OPSIZE (6);
12214                                 n = read32 (ip + 2);
12215                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
12216                                 CHECK_CFG_ERROR;
12217
12218                                 mono_class_init (cmethod->klass);
12219
12220                                 mono_save_token_info (cfg, image, n, cmethod);
12221
12222                                 context_used = mini_method_check_context_used (cfg, cmethod);
12223
12224                                 cil_method = cmethod;
12225                                 if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
12226                                         emit_method_access_failure (cfg, method, cil_method);
12227
12228                                 if (mono_security_core_clr_enabled ())
12229                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
12230
12231                                 /* 
12232                                  * Optimize the common case of ldftn+delegate creation
12233                                  */
12234                                 if ((sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 6) && (ip [6] == CEE_NEWOBJ)) {
12235                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
12236                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
12237                                                 MonoInst *target_ins, *handle_ins;
12238                                                 MonoMethod *invoke;
12239                                                 int invoke_context_used;
12240
12241                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
12242                                                 if (!invoke || !mono_method_signature (invoke))
12243                                                         LOAD_ERROR;
12244
12245                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
12246
12247                                                 target_ins = sp [-1];
12248
12249                                                 if (mono_security_core_clr_enabled ())
12250                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
12251
12252                                                 if (!(cmethod->flags & METHOD_ATTRIBUTE_STATIC)) {
12253                                                         /*LAME IMPL: We must not add a null check for virtual invoke delegates.*/
12254                                                         if (mono_method_signature (invoke)->param_count == mono_method_signature (cmethod)->param_count) {
12255                                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, target_ins->dreg, 0);
12256                                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "ArgumentException");
12257                                                         }
12258                                                 }
12259
12260                                                 /* FIXME: SGEN support */
12261                                                 if (invoke_context_used == 0 || cfg->llvm_only) {
12262                                                         ip += 6;
12263                                                         if (cfg->verbose_level > 3)
12264                                                                 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));
12265                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, FALSE))) {
12266                                                                 sp --;
12267                                                                 *sp = handle_ins;
12268                                                                 CHECK_CFG_EXCEPTION;
12269                                                                 ip += 5;
12270                                                                 sp ++;
12271                                                                 break;
12272                                                         }
12273                                                         ip -= 6;
12274                                                 }
12275                                         }
12276                                 }
12277
12278                                 argconst = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD);
12279                                 ins = mono_emit_jit_icall (cfg, mono_ldftn, &argconst);
12280                                 *sp++ = ins;
12281                                 
12282                                 ip += 6;
12283                                 inline_costs += 10 * num_calls++;
12284                                 break;
12285                         }
12286                         case CEE_LDVIRTFTN: {
12287                                 MonoInst *args [2];
12288
12289                                 CHECK_STACK (1);
12290                                 CHECK_OPSIZE (6);
12291                                 n = read32 (ip + 2);
12292                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
12293                                 CHECK_CFG_ERROR;
12294
12295                                 mono_class_init (cmethod->klass);
12296  
12297                                 context_used = mini_method_check_context_used (cfg, cmethod);
12298
12299                                 if (mono_security_core_clr_enabled ())
12300                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
12301
12302                                 /*
12303                                  * Optimize the common case of ldvirtftn+delegate creation
12304                                  */
12305                                 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)) {
12306                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
12307                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
12308                                                 MonoInst *target_ins, *handle_ins;
12309                                                 MonoMethod *invoke;
12310                                                 int invoke_context_used;
12311                                                 gboolean is_virtual = cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL;
12312
12313                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
12314                                                 if (!invoke || !mono_method_signature (invoke))
12315                                                         LOAD_ERROR;
12316
12317                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
12318
12319                                                 target_ins = sp [-1];
12320
12321                                                 if (mono_security_core_clr_enabled ())
12322                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
12323
12324                                                 /* FIXME: SGEN support */
12325                                                 if (invoke_context_used == 0 || cfg->llvm_only) {
12326                                                         ip += 6;
12327                                                         if (cfg->verbose_level > 3)
12328                                                                 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));
12329                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, is_virtual))) {
12330                                                                 sp -= 2;
12331                                                                 *sp = handle_ins;
12332                                                                 CHECK_CFG_EXCEPTION;
12333                                                                 ip += 5;
12334                                                                 sp ++;
12335                                                                 break;
12336                                                         }
12337                                                         ip -= 6;
12338                                                 }
12339                                         }
12340                                 }
12341
12342                                 --sp;
12343                                 args [0] = *sp;
12344
12345                                 args [1] = emit_get_rgctx_method (cfg, context_used,
12346                                                                                                   cmethod, MONO_RGCTX_INFO_METHOD);
12347
12348                                 if (context_used)
12349                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn_gshared, args);
12350                                 else
12351                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn, args);
12352
12353                                 ip += 6;
12354                                 inline_costs += 10 * num_calls++;
12355                                 break;
12356                         }
12357                         case CEE_LDARG:
12358                                 CHECK_STACK_OVF (1);
12359                                 CHECK_OPSIZE (4);
12360                                 n = read16 (ip + 2);
12361                                 CHECK_ARG (n);
12362                                 EMIT_NEW_ARGLOAD (cfg, ins, n);
12363                                 *sp++ = ins;
12364                                 ip += 4;
12365                                 break;
12366                         case CEE_LDARGA:
12367                                 CHECK_STACK_OVF (1);
12368                                 CHECK_OPSIZE (4);
12369                                 n = read16 (ip + 2);
12370                                 CHECK_ARG (n);
12371                                 NEW_ARGLOADA (cfg, ins, n);
12372                                 MONO_ADD_INS (cfg->cbb, ins);
12373                                 *sp++ = ins;
12374                                 ip += 4;
12375                                 break;
12376                         case CEE_STARG:
12377                                 CHECK_STACK (1);
12378                                 --sp;
12379                                 CHECK_OPSIZE (4);
12380                                 n = read16 (ip + 2);
12381                                 CHECK_ARG (n);
12382                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
12383                                         UNVERIFIED;
12384                                 emit_starg_ir (cfg, sp, n);
12385                                 ip += 4;
12386                                 break;
12387                         case CEE_LDLOC:
12388                                 CHECK_STACK_OVF (1);
12389                                 CHECK_OPSIZE (4);
12390                                 n = read16 (ip + 2);
12391                                 CHECK_LOCAL (n);
12392                                 if ((ip [4] == CEE_LDFLD) && ip_in_bb (cfg, cfg->cbb, ip + 4) && header->locals [n]->type == MONO_TYPE_VALUETYPE) {
12393                                         /* Avoid loading a struct just to load one of its fields */
12394                                         EMIT_NEW_LOCLOADA (cfg, ins, n);
12395                                 } else {
12396                                         EMIT_NEW_LOCLOAD (cfg, ins, n);
12397                                 }
12398                                 *sp++ = ins;
12399                                 ip += 4;
12400                                 break;
12401                         case CEE_LDLOCA: {
12402                                 unsigned char *tmp_ip;
12403                                 CHECK_STACK_OVF (1);
12404                                 CHECK_OPSIZE (4);
12405                                 n = read16 (ip + 2);
12406                                 CHECK_LOCAL (n);
12407
12408                                 if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 2))) {
12409                                         ip = tmp_ip;
12410                                         inline_costs += 1;
12411                                         break;
12412                                 }                       
12413                                 
12414                                 EMIT_NEW_LOCLOADA (cfg, ins, n);
12415                                 *sp++ = ins;
12416                                 ip += 4;
12417                                 break;
12418                         }
12419                         case CEE_STLOC:
12420                                 CHECK_STACK (1);
12421                                 --sp;
12422                                 CHECK_OPSIZE (4);
12423                                 n = read16 (ip + 2);
12424                                 CHECK_LOCAL (n);
12425                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
12426                                         UNVERIFIED;
12427                                 emit_stloc_ir (cfg, sp, header, n);
12428                                 ip += 4;
12429                                 inline_costs += 1;
12430                                 break;
12431                         case CEE_LOCALLOC: {
12432                                 CHECK_STACK (1);
12433                                 MonoBasicBlock *non_zero_bb, *end_bb;
12434                                 int alloc_ptr = alloc_preg (cfg);
12435                                 --sp;
12436                                 if (sp != stack_start) 
12437                                         UNVERIFIED;
12438                                 if (cfg->method != method) 
12439                                         /* 
12440                                          * Inlining this into a loop in a parent could lead to 
12441                                          * stack overflows which is different behavior than the
12442                                          * non-inlined case, thus disable inlining in this case.
12443                                          */
12444                                         INLINE_FAILURE("localloc");
12445
12446                                 NEW_BBLOCK (cfg, non_zero_bb);
12447                                 NEW_BBLOCK (cfg, end_bb);
12448
12449                                 /* if size != zero */
12450                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
12451                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, non_zero_bb);
12452
12453                                 //size is zero, so result is NULL
12454                                 MONO_EMIT_NEW_PCONST (cfg, alloc_ptr, NULL);
12455                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12456
12457                                 MONO_START_BB (cfg, non_zero_bb);
12458                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
12459                                 ins->dreg = alloc_ptr;
12460                                 ins->sreg1 = sp [0]->dreg;
12461                                 ins->type = STACK_PTR;
12462                                 MONO_ADD_INS (cfg->cbb, ins);
12463
12464                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12465                                 if (init_locals)
12466                                         ins->flags |= MONO_INST_INIT;
12467
12468                                 MONO_START_BB (cfg, end_bb);
12469                                 EMIT_NEW_UNALU (cfg, ins, OP_MOVE, alloc_preg (cfg), alloc_ptr);
12470                                 ins->type = STACK_PTR;
12471
12472                                 *sp++ = ins;
12473                                 ip += 2;
12474                                 break;
12475                         }
12476                         case CEE_ENDFILTER: {
12477                                 MonoExceptionClause *clause, *nearest;
12478                                 int cc;
12479
12480                                 CHECK_STACK (1);
12481                                 --sp;
12482                                 if ((sp != stack_start) || (sp [0]->type != STACK_I4)) 
12483                                         UNVERIFIED;
12484                                 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
12485                                 ins->sreg1 = (*sp)->dreg;
12486                                 MONO_ADD_INS (cfg->cbb, ins);
12487                                 start_new_bblock = 1;
12488                                 ip += 2;
12489
12490                                 nearest = NULL;
12491                                 for (cc = 0; cc < header->num_clauses; ++cc) {
12492                                         clause = &header->clauses [cc];
12493                                         if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
12494                                                 ((ip - header->code) > clause->data.filter_offset && (ip - header->code) <= clause->handler_offset) &&
12495                                             (!nearest || (clause->data.filter_offset < nearest->data.filter_offset)))
12496                                                 nearest = clause;
12497                                 }
12498                                 g_assert (nearest);
12499                                 if ((ip - header->code) != nearest->handler_offset)
12500                                         UNVERIFIED;
12501
12502                                 break;
12503                         }
12504                         case CEE_UNALIGNED_:
12505                                 ins_flag |= MONO_INST_UNALIGNED;
12506                                 /* FIXME: record alignment? we can assume 1 for now */
12507                                 CHECK_OPSIZE (3);
12508                                 ip += 3;
12509                                 break;
12510                         case CEE_VOLATILE_:
12511                                 ins_flag |= MONO_INST_VOLATILE;
12512                                 ip += 2;
12513                                 break;
12514                         case CEE_TAIL_:
12515                                 ins_flag   |= MONO_INST_TAILCALL;
12516                                 cfg->flags |= MONO_CFG_HAS_TAIL;
12517                                 /* Can't inline tail calls at this time */
12518                                 inline_costs += 100000;
12519                                 ip += 2;
12520                                 break;
12521                         case CEE_INITOBJ:
12522                                 CHECK_STACK (1);
12523                                 --sp;
12524                                 CHECK_OPSIZE (6);
12525                                 token = read32 (ip + 2);
12526                                 klass = mini_get_class (method, token, generic_context);
12527                                 CHECK_TYPELOAD (klass);
12528                                 if (generic_class_is_reference_type (cfg, klass))
12529                                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, sp [0]->dreg, 0, 0);
12530                                 else
12531                                         mini_emit_initobj (cfg, *sp, NULL, klass);
12532                                 ip += 6;
12533                                 inline_costs += 1;
12534                                 break;
12535                         case CEE_CONSTRAINED_:
12536                                 CHECK_OPSIZE (6);
12537                                 token = read32 (ip + 2);
12538                                 constrained_class = mini_get_class (method, token, generic_context);
12539                                 CHECK_TYPELOAD (constrained_class);
12540                                 ip += 6;
12541                                 break;
12542                         case CEE_CPBLK:
12543                                 CHECK_STACK (3);
12544                                 sp -= 3;
12545                                 mini_emit_memory_copy_bytes (cfg, sp [0], sp [1], sp [2], ins_flag);
12546                                 ip += 2;
12547                                 ins_flag = 0;
12548                                 inline_costs += 1;
12549                                 break;
12550                         case CEE_INITBLK:
12551                                 CHECK_STACK (3);
12552                                 sp -= 3;
12553                                 mini_emit_memory_init_bytes (cfg, sp [0], sp [1], sp [2], ins_flag);
12554                                 ip += 2;
12555                                 ins_flag = 0;
12556                                 inline_costs += 1;
12557                                 break;
12558                         case CEE_NO_:
12559                                 CHECK_OPSIZE (3);
12560                                 if (ip [2] & 0x1)
12561                                         ins_flag |= MONO_INST_NOTYPECHECK;
12562                                 if (ip [2] & 0x2)
12563                                         ins_flag |= MONO_INST_NORANGECHECK;
12564                                 /* we ignore the no-nullcheck for now since we
12565                                  * really do it explicitly only when doing callvirt->call
12566                                  */
12567                                 ip += 3;
12568                                 break;
12569                         case CEE_RETHROW: {
12570                                 MonoInst *load;
12571                                 int handler_offset = -1;
12572
12573                                 for (i = 0; i < header->num_clauses; ++i) {
12574                                         MonoExceptionClause *clause = &header->clauses [i];
12575                                         if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
12576                                                 handler_offset = clause->handler_offset;
12577                                                 break;
12578                                         }
12579                                 }
12580
12581                                 cfg->cbb->flags |= BB_EXCEPTION_UNSAFE;
12582
12583                                 if (handler_offset == -1)
12584                                         UNVERIFIED;
12585
12586                                 EMIT_NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
12587                                 MONO_INST_NEW (cfg, ins, OP_RETHROW);
12588                                 ins->sreg1 = load->dreg;
12589                                 MONO_ADD_INS (cfg->cbb, ins);
12590
12591                                 MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
12592                                 MONO_ADD_INS (cfg->cbb, ins);
12593
12594                                 sp = stack_start;
12595                                 link_bblock (cfg, cfg->cbb, end_bblock);
12596                                 start_new_bblock = 1;
12597                                 ip += 2;
12598                                 break;
12599                         }
12600                         case CEE_SIZEOF: {
12601                                 guint32 val;
12602                                 int ialign;
12603
12604                                 CHECK_STACK_OVF (1);
12605                                 CHECK_OPSIZE (6);
12606                                 token = read32 (ip + 2);
12607                                 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC && !image_is_dynamic (method->klass->image) && !generic_context) {
12608                                         MonoType *type = mono_type_create_from_typespec_checked (image, token, &cfg->error);
12609                                         CHECK_CFG_ERROR;
12610
12611                                         val = mono_type_size (type, &ialign);
12612                                 } else {
12613                                         MonoClass *klass = mini_get_class (method, token, generic_context);
12614                                         CHECK_TYPELOAD (klass);
12615
12616                                         val = mono_type_size (&klass->byval_arg, &ialign);
12617
12618                                         if (mini_is_gsharedvt_klass (klass))
12619                                                 GSHAREDVT_FAILURE (*ip);
12620                                 }
12621                                 EMIT_NEW_ICONST (cfg, ins, val);
12622                                 *sp++= ins;
12623                                 ip += 6;
12624                                 break;
12625                         }
12626                         case CEE_REFANYTYPE: {
12627                                 MonoInst *src_var, *src;
12628
12629                                 GSHAREDVT_FAILURE (*ip);
12630
12631                                 CHECK_STACK (1);
12632                                 --sp;
12633
12634                                 // FIXME:
12635                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
12636                                 if (!src_var)
12637                                         src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
12638                                 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
12639                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &mono_defaults.typehandle_class->byval_arg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type));
12640                                 *sp++ = ins;
12641                                 ip += 2;
12642                                 break;
12643                         }
12644                         case CEE_READONLY_:
12645                                 readonly = TRUE;
12646                                 ip += 2;
12647                                 break;
12648
12649                         case CEE_UNUSED56:
12650                         case CEE_UNUSED57:
12651                         case CEE_UNUSED70:
12652                         case CEE_UNUSED:
12653                         case CEE_UNUSED99:
12654                                 UNVERIFIED;
12655                                 
12656                         default:
12657                                 g_warning ("opcode 0xfe 0x%02x not handled", ip [1]);
12658                                 UNVERIFIED;
12659                         }
12660                         break;
12661                 }
12662                 case CEE_UNUSED58:
12663                 case CEE_UNUSED1:
12664                         UNVERIFIED;
12665
12666                 default:
12667                         g_warning ("opcode 0x%02x not handled", *ip);
12668                         UNVERIFIED;
12669                 }
12670         }
12671         if (start_new_bblock != 1)
12672                 UNVERIFIED;
12673
12674         cfg->cbb->cil_length = ip - cfg->cbb->cil_code;
12675         if (cfg->cbb->next_bb) {
12676                 /* This could already be set because of inlining, #693905 */
12677                 MonoBasicBlock *bb = cfg->cbb;
12678
12679                 while (bb->next_bb)
12680                         bb = bb->next_bb;
12681                 bb->next_bb = end_bblock;
12682         } else {
12683                 cfg->cbb->next_bb = end_bblock;
12684         }
12685
12686         if (cfg->method == method && cfg->domainvar) {
12687                 MonoInst *store;
12688                 MonoInst *get_domain;
12689
12690                 cfg->cbb = init_localsbb;
12691
12692                 get_domain = mono_create_tls_get (cfg, TLS_KEY_DOMAIN);
12693                 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, get_domain);
12694                 MONO_ADD_INS (cfg->cbb, store);
12695         }
12696
12697 #if defined(TARGET_POWERPC) || defined(TARGET_X86)
12698         if (cfg->compile_aot)
12699                 /* FIXME: The plt slots require a GOT var even if the method doesn't use it */
12700                 mono_get_got_var (cfg);
12701 #endif
12702
12703         if (cfg->method == method && cfg->got_var)
12704                 mono_emit_load_got_addr (cfg);
12705
12706         if (init_localsbb) {
12707                 cfg->cbb = init_localsbb;
12708                 cfg->ip = NULL;
12709                 for (i = 0; i < header->num_locals; ++i) {
12710                         emit_init_local (cfg, i, header->locals [i], init_locals);
12711                 }
12712         }
12713
12714         if (cfg->init_ref_vars && cfg->method == method) {
12715                 /* Emit initialization for ref vars */
12716                 // FIXME: Avoid duplication initialization for IL locals.
12717                 for (i = 0; i < cfg->num_varinfo; ++i) {
12718                         MonoInst *ins = cfg->varinfo [i];
12719
12720                         if (ins->opcode == OP_LOCAL && ins->type == STACK_OBJ)
12721                                 MONO_EMIT_NEW_PCONST (cfg, ins->dreg, NULL);
12722                 }
12723         }
12724
12725         if (cfg->lmf_var && cfg->method == method && !cfg->llvm_only) {
12726                 cfg->cbb = init_localsbb;
12727                 emit_push_lmf (cfg);
12728         }
12729
12730         cfg->cbb = init_localsbb;
12731         mini_profiler_emit_enter (cfg);
12732
12733         if (seq_points) {
12734                 MonoBasicBlock *bb;
12735
12736                 /*
12737                  * Make seq points at backward branch targets interruptable.
12738                  */
12739                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
12740                         if (bb->code && bb->in_count > 1 && bb->code->opcode == OP_SEQ_POINT)
12741                                 bb->code->flags |= MONO_INST_SINGLE_STEP_LOC;
12742         }
12743
12744         /* Add a sequence point for method entry/exit events */
12745         if (seq_points && cfg->gen_sdb_seq_points) {
12746                 NEW_SEQ_POINT (cfg, ins, METHOD_ENTRY_IL_OFFSET, FALSE);
12747                 MONO_ADD_INS (init_localsbb, ins);
12748                 NEW_SEQ_POINT (cfg, ins, METHOD_EXIT_IL_OFFSET, FALSE);
12749                 MONO_ADD_INS (cfg->bb_exit, ins);
12750         }
12751
12752         /*
12753          * Add seq points for IL offsets which have line number info, but wasn't generated a seq point during JITting because
12754          * the code they refer to was dead (#11880).
12755          */
12756         if (sym_seq_points) {
12757                 for (i = 0; i < header->code_size; ++i) {
12758                         if (mono_bitset_test_fast (seq_point_locs, i) && !mono_bitset_test_fast (seq_point_set_locs, i)) {
12759                                 MonoInst *ins;
12760
12761                                 NEW_SEQ_POINT (cfg, ins, i, FALSE);
12762                                 mono_add_seq_point (cfg, NULL, ins, SEQ_POINT_NATIVE_OFFSET_DEAD_CODE);
12763                         }
12764                 }
12765         }
12766
12767         cfg->ip = NULL;
12768
12769         if (cfg->method == method) {
12770                 MonoBasicBlock *bb;
12771                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
12772                         if (bb == cfg->bb_init)
12773                                 bb->region = -1;
12774                         else
12775                                 bb->region = mono_find_block_region (cfg, bb->real_offset);
12776                         if (cfg->spvars)
12777                                 mono_create_spvar_for_region (cfg, bb->region);
12778                         if (cfg->verbose_level > 2)
12779                                 printf ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
12780                 }
12781         } else {
12782                 MonoBasicBlock *bb;
12783                 /* get_most_deep_clause () in mini-llvm.c depends on this for inlined bblocks */
12784                 for (bb = start_bblock; bb != end_bblock; bb  = bb->next_bb) {
12785                         bb->real_offset = inline_offset;
12786                 }
12787         }
12788
12789         if (inline_costs < 0) {
12790                 char *mname;
12791
12792                 /* Method is too large */
12793                 mname = mono_method_full_name (method, TRUE);
12794                 mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("Method %s is too complex.", mname));
12795                 g_free (mname);
12796         }
12797
12798         if ((cfg->verbose_level > 2) && (cfg->method == method)) 
12799                 mono_print_code (cfg, "AFTER METHOD-TO-IR");
12800
12801         goto cleanup;
12802
12803 mono_error_exit:
12804         g_assert (!mono_error_ok (&cfg->error));
12805         goto cleanup;
12806  
12807  exception_exit:
12808         g_assert (cfg->exception_type != MONO_EXCEPTION_NONE);
12809         goto cleanup;
12810
12811  unverified:
12812         set_exception_type_from_invalid_il (cfg, method, ip);
12813         goto cleanup;
12814
12815  cleanup:
12816         g_slist_free (class_inits);
12817         mono_basic_block_free (original_bb);
12818         cfg->dont_inline = g_list_remove (cfg->dont_inline, method);
12819         if (cfg->exception_type)
12820                 return -1;
12821         else
12822                 return inline_costs;
12823 }
12824
12825 static int
12826 store_membase_reg_to_store_membase_imm (int opcode)
12827 {
12828         switch (opcode) {
12829         case OP_STORE_MEMBASE_REG:
12830                 return OP_STORE_MEMBASE_IMM;
12831         case OP_STOREI1_MEMBASE_REG:
12832                 return OP_STOREI1_MEMBASE_IMM;
12833         case OP_STOREI2_MEMBASE_REG:
12834                 return OP_STOREI2_MEMBASE_IMM;
12835         case OP_STOREI4_MEMBASE_REG:
12836                 return OP_STOREI4_MEMBASE_IMM;
12837         case OP_STOREI8_MEMBASE_REG:
12838                 return OP_STOREI8_MEMBASE_IMM;
12839         default:
12840                 g_assert_not_reached ();
12841         }
12842
12843         return -1;
12844 }               
12845
12846 int
12847 mono_op_to_op_imm (int opcode)
12848 {
12849         switch (opcode) {
12850         case OP_IADD:
12851                 return OP_IADD_IMM;
12852         case OP_ISUB:
12853                 return OP_ISUB_IMM;
12854         case OP_IDIV:
12855                 return OP_IDIV_IMM;
12856         case OP_IDIV_UN:
12857                 return OP_IDIV_UN_IMM;
12858         case OP_IREM:
12859                 return OP_IREM_IMM;
12860         case OP_IREM_UN:
12861                 return OP_IREM_UN_IMM;
12862         case OP_IMUL:
12863                 return OP_IMUL_IMM;
12864         case OP_IAND:
12865                 return OP_IAND_IMM;
12866         case OP_IOR:
12867                 return OP_IOR_IMM;
12868         case OP_IXOR:
12869                 return OP_IXOR_IMM;
12870         case OP_ISHL:
12871                 return OP_ISHL_IMM;
12872         case OP_ISHR:
12873                 return OP_ISHR_IMM;
12874         case OP_ISHR_UN:
12875                 return OP_ISHR_UN_IMM;
12876
12877         case OP_LADD:
12878                 return OP_LADD_IMM;
12879         case OP_LSUB:
12880                 return OP_LSUB_IMM;
12881         case OP_LAND:
12882                 return OP_LAND_IMM;
12883         case OP_LOR:
12884                 return OP_LOR_IMM;
12885         case OP_LXOR:
12886                 return OP_LXOR_IMM;
12887         case OP_LSHL:
12888                 return OP_LSHL_IMM;
12889         case OP_LSHR:
12890                 return OP_LSHR_IMM;
12891         case OP_LSHR_UN:
12892                 return OP_LSHR_UN_IMM;
12893 #if SIZEOF_REGISTER == 8
12894         case OP_LREM:
12895                 return OP_LREM_IMM;
12896 #endif
12897
12898         case OP_COMPARE:
12899                 return OP_COMPARE_IMM;
12900         case OP_ICOMPARE:
12901                 return OP_ICOMPARE_IMM;
12902         case OP_LCOMPARE:
12903                 return OP_LCOMPARE_IMM;
12904
12905         case OP_STORE_MEMBASE_REG:
12906                 return OP_STORE_MEMBASE_IMM;
12907         case OP_STOREI1_MEMBASE_REG:
12908                 return OP_STOREI1_MEMBASE_IMM;
12909         case OP_STOREI2_MEMBASE_REG:
12910                 return OP_STOREI2_MEMBASE_IMM;
12911         case OP_STOREI4_MEMBASE_REG:
12912                 return OP_STOREI4_MEMBASE_IMM;
12913
12914 #if defined(TARGET_X86) || defined (TARGET_AMD64)
12915         case OP_X86_PUSH:
12916                 return OP_X86_PUSH_IMM;
12917         case OP_X86_COMPARE_MEMBASE_REG:
12918                 return OP_X86_COMPARE_MEMBASE_IMM;
12919 #endif
12920 #if defined(TARGET_AMD64)
12921         case OP_AMD64_ICOMPARE_MEMBASE_REG:
12922                 return OP_AMD64_ICOMPARE_MEMBASE_IMM;
12923 #endif
12924         case OP_VOIDCALL_REG:
12925                 return OP_VOIDCALL;
12926         case OP_CALL_REG:
12927                 return OP_CALL;
12928         case OP_LCALL_REG:
12929                 return OP_LCALL;
12930         case OP_FCALL_REG:
12931                 return OP_FCALL;
12932         case OP_LOCALLOC:
12933                 return OP_LOCALLOC_IMM;
12934         }
12935
12936         return -1;
12937 }
12938
12939 static int
12940 ldind_to_load_membase (int opcode)
12941 {
12942         switch (opcode) {
12943         case CEE_LDIND_I1:
12944                 return OP_LOADI1_MEMBASE;
12945         case CEE_LDIND_U1:
12946                 return OP_LOADU1_MEMBASE;
12947         case CEE_LDIND_I2:
12948                 return OP_LOADI2_MEMBASE;
12949         case CEE_LDIND_U2:
12950                 return OP_LOADU2_MEMBASE;
12951         case CEE_LDIND_I4:
12952                 return OP_LOADI4_MEMBASE;
12953         case CEE_LDIND_U4:
12954                 return OP_LOADU4_MEMBASE;
12955         case CEE_LDIND_I:
12956                 return OP_LOAD_MEMBASE;
12957         case CEE_LDIND_REF:
12958                 return OP_LOAD_MEMBASE;
12959         case CEE_LDIND_I8:
12960                 return OP_LOADI8_MEMBASE;
12961         case CEE_LDIND_R4:
12962                 return OP_LOADR4_MEMBASE;
12963         case CEE_LDIND_R8:
12964                 return OP_LOADR8_MEMBASE;
12965         default:
12966                 g_assert_not_reached ();
12967         }
12968
12969         return -1;
12970 }
12971
12972 static int
12973 stind_to_store_membase (int opcode)
12974 {
12975         switch (opcode) {
12976         case CEE_STIND_I1:
12977                 return OP_STOREI1_MEMBASE_REG;
12978         case CEE_STIND_I2:
12979                 return OP_STOREI2_MEMBASE_REG;
12980         case CEE_STIND_I4:
12981                 return OP_STOREI4_MEMBASE_REG;
12982         case CEE_STIND_I:
12983         case CEE_STIND_REF:
12984                 return OP_STORE_MEMBASE_REG;
12985         case CEE_STIND_I8:
12986                 return OP_STOREI8_MEMBASE_REG;
12987         case CEE_STIND_R4:
12988                 return OP_STORER4_MEMBASE_REG;
12989         case CEE_STIND_R8:
12990                 return OP_STORER8_MEMBASE_REG;
12991         default:
12992                 g_assert_not_reached ();
12993         }
12994
12995         return -1;
12996 }
12997
12998 int
12999 mono_load_membase_to_load_mem (int opcode)
13000 {
13001         // FIXME: Add a MONO_ARCH_HAVE_LOAD_MEM macro
13002 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13003         switch (opcode) {
13004         case OP_LOAD_MEMBASE:
13005                 return OP_LOAD_MEM;
13006         case OP_LOADU1_MEMBASE:
13007                 return OP_LOADU1_MEM;
13008         case OP_LOADU2_MEMBASE:
13009                 return OP_LOADU2_MEM;
13010         case OP_LOADI4_MEMBASE:
13011                 return OP_LOADI4_MEM;
13012         case OP_LOADU4_MEMBASE:
13013                 return OP_LOADU4_MEM;
13014 #if SIZEOF_REGISTER == 8
13015         case OP_LOADI8_MEMBASE:
13016                 return OP_LOADI8_MEM;
13017 #endif
13018         }
13019 #endif
13020
13021         return -1;
13022 }
13023
13024 static inline int
13025 op_to_op_dest_membase (int store_opcode, int opcode)
13026 {
13027 #if defined(TARGET_X86)
13028         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG)))
13029                 return -1;
13030
13031         switch (opcode) {
13032         case OP_IADD:
13033                 return OP_X86_ADD_MEMBASE_REG;
13034         case OP_ISUB:
13035                 return OP_X86_SUB_MEMBASE_REG;
13036         case OP_IAND:
13037                 return OP_X86_AND_MEMBASE_REG;
13038         case OP_IOR:
13039                 return OP_X86_OR_MEMBASE_REG;
13040         case OP_IXOR:
13041                 return OP_X86_XOR_MEMBASE_REG;
13042         case OP_ADD_IMM:
13043         case OP_IADD_IMM:
13044                 return OP_X86_ADD_MEMBASE_IMM;
13045         case OP_SUB_IMM:
13046         case OP_ISUB_IMM:
13047                 return OP_X86_SUB_MEMBASE_IMM;
13048         case OP_AND_IMM:
13049         case OP_IAND_IMM:
13050                 return OP_X86_AND_MEMBASE_IMM;
13051         case OP_OR_IMM:
13052         case OP_IOR_IMM:
13053                 return OP_X86_OR_MEMBASE_IMM;
13054         case OP_XOR_IMM:
13055         case OP_IXOR_IMM:
13056                 return OP_X86_XOR_MEMBASE_IMM;
13057         case OP_MOVE:
13058                 return OP_NOP;
13059         }
13060 #endif
13061
13062 #if defined(TARGET_AMD64)
13063         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG) || (store_opcode == OP_STOREI8_MEMBASE_REG)))
13064                 return -1;
13065
13066         switch (opcode) {
13067         case OP_IADD:
13068                 return OP_X86_ADD_MEMBASE_REG;
13069         case OP_ISUB:
13070                 return OP_X86_SUB_MEMBASE_REG;
13071         case OP_IAND:
13072                 return OP_X86_AND_MEMBASE_REG;
13073         case OP_IOR:
13074                 return OP_X86_OR_MEMBASE_REG;
13075         case OP_IXOR:
13076                 return OP_X86_XOR_MEMBASE_REG;
13077         case OP_IADD_IMM:
13078                 return OP_X86_ADD_MEMBASE_IMM;
13079         case OP_ISUB_IMM:
13080                 return OP_X86_SUB_MEMBASE_IMM;
13081         case OP_IAND_IMM:
13082                 return OP_X86_AND_MEMBASE_IMM;
13083         case OP_IOR_IMM:
13084                 return OP_X86_OR_MEMBASE_IMM;
13085         case OP_IXOR_IMM:
13086                 return OP_X86_XOR_MEMBASE_IMM;
13087         case OP_LADD:
13088                 return OP_AMD64_ADD_MEMBASE_REG;
13089         case OP_LSUB:
13090                 return OP_AMD64_SUB_MEMBASE_REG;
13091         case OP_LAND:
13092                 return OP_AMD64_AND_MEMBASE_REG;
13093         case OP_LOR:
13094                 return OP_AMD64_OR_MEMBASE_REG;
13095         case OP_LXOR:
13096                 return OP_AMD64_XOR_MEMBASE_REG;
13097         case OP_ADD_IMM:
13098         case OP_LADD_IMM:
13099                 return OP_AMD64_ADD_MEMBASE_IMM;
13100         case OP_SUB_IMM:
13101         case OP_LSUB_IMM:
13102                 return OP_AMD64_SUB_MEMBASE_IMM;
13103         case OP_AND_IMM:
13104         case OP_LAND_IMM:
13105                 return OP_AMD64_AND_MEMBASE_IMM;
13106         case OP_OR_IMM:
13107         case OP_LOR_IMM:
13108                 return OP_AMD64_OR_MEMBASE_IMM;
13109         case OP_XOR_IMM:
13110         case OP_LXOR_IMM:
13111                 return OP_AMD64_XOR_MEMBASE_IMM;
13112         case OP_MOVE:
13113                 return OP_NOP;
13114         }
13115 #endif
13116
13117         return -1;
13118 }
13119
13120 static inline int
13121 op_to_op_store_membase (int store_opcode, int opcode)
13122 {
13123 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13124         switch (opcode) {
13125         case OP_ICEQ:
13126                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13127                         return OP_X86_SETEQ_MEMBASE;
13128         case OP_CNE:
13129                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13130                         return OP_X86_SETNE_MEMBASE;
13131         }
13132 #endif
13133
13134         return -1;
13135 }
13136
13137 static inline int
13138 op_to_op_src1_membase (MonoCompile *cfg, int load_opcode, int opcode)
13139 {
13140 #ifdef TARGET_X86
13141         /* FIXME: This has sign extension issues */
13142         /*
13143         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
13144                 return OP_X86_COMPARE_MEMBASE8_IMM;
13145         */
13146
13147         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
13148                 return -1;
13149
13150         switch (opcode) {
13151         case OP_X86_PUSH:
13152                 return OP_X86_PUSH_MEMBASE;
13153         case OP_COMPARE_IMM:
13154         case OP_ICOMPARE_IMM:
13155                 return OP_X86_COMPARE_MEMBASE_IMM;
13156         case OP_COMPARE:
13157         case OP_ICOMPARE:
13158                 return OP_X86_COMPARE_MEMBASE_REG;
13159         }
13160 #endif
13161
13162 #ifdef TARGET_AMD64
13163         /* FIXME: This has sign extension issues */
13164         /*
13165         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
13166                 return OP_X86_COMPARE_MEMBASE8_IMM;
13167         */
13168
13169         switch (opcode) {
13170         case OP_X86_PUSH:
13171                 if ((load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32) || (load_opcode == OP_LOADI8_MEMBASE))
13172                         return OP_X86_PUSH_MEMBASE;
13173                 break;
13174                 /* FIXME: This only works for 32 bit immediates
13175         case OP_COMPARE_IMM:
13176         case OP_LCOMPARE_IMM:
13177                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
13178                         return OP_AMD64_COMPARE_MEMBASE_IMM;
13179                 */
13180         case OP_ICOMPARE_IMM:
13181                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
13182                         return OP_AMD64_ICOMPARE_MEMBASE_IMM;
13183                 break;
13184         case OP_COMPARE:
13185         case OP_LCOMPARE:
13186                 if (cfg->backend->ilp32 && load_opcode == OP_LOAD_MEMBASE)
13187                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
13188                 if ((load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32) || (load_opcode == OP_LOADI8_MEMBASE))
13189                         return OP_AMD64_COMPARE_MEMBASE_REG;
13190                 break;
13191         case OP_ICOMPARE:
13192                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
13193                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
13194                 break;
13195         }
13196 #endif
13197
13198         return -1;
13199 }
13200
13201 static inline int
13202 op_to_op_src2_membase (MonoCompile *cfg, int load_opcode, int opcode)
13203 {
13204 #ifdef TARGET_X86
13205         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
13206                 return -1;
13207         
13208         switch (opcode) {
13209         case OP_COMPARE:
13210         case OP_ICOMPARE:
13211                 return OP_X86_COMPARE_REG_MEMBASE;
13212         case OP_IADD:
13213                 return OP_X86_ADD_REG_MEMBASE;
13214         case OP_ISUB:
13215                 return OP_X86_SUB_REG_MEMBASE;
13216         case OP_IAND:
13217                 return OP_X86_AND_REG_MEMBASE;
13218         case OP_IOR:
13219                 return OP_X86_OR_REG_MEMBASE;
13220         case OP_IXOR:
13221                 return OP_X86_XOR_REG_MEMBASE;
13222         }
13223 #endif
13224
13225 #ifdef TARGET_AMD64
13226         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE && cfg->backend->ilp32)) {
13227                 switch (opcode) {
13228                 case OP_ICOMPARE:
13229                         return OP_AMD64_ICOMPARE_REG_MEMBASE;
13230                 case OP_IADD:
13231                         return OP_X86_ADD_REG_MEMBASE;
13232                 case OP_ISUB:
13233                         return OP_X86_SUB_REG_MEMBASE;
13234                 case OP_IAND:
13235                         return OP_X86_AND_REG_MEMBASE;
13236                 case OP_IOR:
13237                         return OP_X86_OR_REG_MEMBASE;
13238                 case OP_IXOR:
13239                         return OP_X86_XOR_REG_MEMBASE;
13240                 }
13241         } else if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32)) {
13242                 switch (opcode) {
13243                 case OP_COMPARE:
13244                 case OP_LCOMPARE:
13245                         return OP_AMD64_COMPARE_REG_MEMBASE;
13246                 case OP_LADD:
13247                         return OP_AMD64_ADD_REG_MEMBASE;
13248                 case OP_LSUB:
13249                         return OP_AMD64_SUB_REG_MEMBASE;
13250                 case OP_LAND:
13251                         return OP_AMD64_AND_REG_MEMBASE;
13252                 case OP_LOR:
13253                         return OP_AMD64_OR_REG_MEMBASE;
13254                 case OP_LXOR:
13255                         return OP_AMD64_XOR_REG_MEMBASE;
13256                 }
13257         }
13258 #endif
13259
13260         return -1;
13261 }
13262
13263 int
13264 mono_op_to_op_imm_noemul (int opcode)
13265 {
13266         switch (opcode) {
13267 #if SIZEOF_REGISTER == 4 && !defined(MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS)
13268         case OP_LSHR:
13269         case OP_LSHL:
13270         case OP_LSHR_UN:
13271                 return -1;
13272 #endif
13273 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
13274         case OP_IDIV:
13275         case OP_IDIV_UN:
13276         case OP_IREM:
13277         case OP_IREM_UN:
13278                 return -1;
13279 #endif
13280 #if defined(MONO_ARCH_EMULATE_MUL_DIV)
13281         case OP_IMUL:
13282                 return -1;
13283 #endif
13284         default:
13285                 return mono_op_to_op_imm (opcode);
13286         }
13287 }
13288
13289 /**
13290  * mono_handle_global_vregs:
13291  *
13292  *   Make vregs used in more than one bblock 'global', i.e. allocate a variable
13293  * for them.
13294  */
13295 void
13296 mono_handle_global_vregs (MonoCompile *cfg)
13297 {
13298         gint32 *vreg_to_bb;
13299         MonoBasicBlock *bb;
13300         int i, pos;
13301
13302         vreg_to_bb = (gint32 *)mono_mempool_alloc0 (cfg->mempool, sizeof (gint32*) * cfg->next_vreg + 1);
13303
13304 #ifdef MONO_ARCH_SIMD_INTRINSICS
13305         if (cfg->uses_simd_intrinsics)
13306                 mono_simd_simplify_indirection (cfg);
13307 #endif
13308
13309         /* Find local vregs used in more than one bb */
13310         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13311                 MonoInst *ins = bb->code;       
13312                 int block_num = bb->block_num;
13313
13314                 if (cfg->verbose_level > 2)
13315                         printf ("\nHANDLE-GLOBAL-VREGS BLOCK %d:\n", bb->block_num);
13316
13317                 cfg->cbb = bb;
13318                 for (; ins; ins = ins->next) {
13319                         const char *spec = INS_INFO (ins->opcode);
13320                         int regtype = 0, regindex;
13321                         gint32 prev_bb;
13322
13323                         if (G_UNLIKELY (cfg->verbose_level > 2))
13324                                 mono_print_ins (ins);
13325
13326                         g_assert (ins->opcode >= MONO_CEE_LAST);
13327
13328                         for (regindex = 0; regindex < 4; regindex ++) {
13329                                 int vreg = 0;
13330
13331                                 if (regindex == 0) {
13332                                         regtype = spec [MONO_INST_DEST];
13333                                         if (regtype == ' ')
13334                                                 continue;
13335                                         vreg = ins->dreg;
13336                                 } else if (regindex == 1) {
13337                                         regtype = spec [MONO_INST_SRC1];
13338                                         if (regtype == ' ')
13339                                                 continue;
13340                                         vreg = ins->sreg1;
13341                                 } else if (regindex == 2) {
13342                                         regtype = spec [MONO_INST_SRC2];
13343                                         if (regtype == ' ')
13344                                                 continue;
13345                                         vreg = ins->sreg2;
13346                                 } else if (regindex == 3) {
13347                                         regtype = spec [MONO_INST_SRC3];
13348                                         if (regtype == ' ')
13349                                                 continue;
13350                                         vreg = ins->sreg3;
13351                                 }
13352
13353 #if SIZEOF_REGISTER == 4
13354                                 /* In the LLVM case, the long opcodes are not decomposed */
13355                                 if (regtype == 'l' && !COMPILE_LLVM (cfg)) {
13356                                         /*
13357                                          * Since some instructions reference the original long vreg,
13358                                          * and some reference the two component vregs, it is quite hard
13359                                          * to determine when it needs to be global. So be conservative.
13360                                          */
13361                                         if (!get_vreg_to_inst (cfg, vreg)) {
13362                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
13363
13364                                                 if (cfg->verbose_level > 2)
13365                                                         printf ("LONG VREG R%d made global.\n", vreg);
13366                                         }
13367
13368                                         /*
13369                                          * Make the component vregs volatile since the optimizations can
13370                                          * get confused otherwise.
13371                                          */
13372                                         get_vreg_to_inst (cfg, MONO_LVREG_LS (vreg))->flags |= MONO_INST_VOLATILE;
13373                                         get_vreg_to_inst (cfg, MONO_LVREG_MS (vreg))->flags |= MONO_INST_VOLATILE;
13374                                 }
13375 #endif
13376
13377                                 g_assert (vreg != -1);
13378
13379                                 prev_bb = vreg_to_bb [vreg];
13380                                 if (prev_bb == 0) {
13381                                         /* 0 is a valid block num */
13382                                         vreg_to_bb [vreg] = block_num + 1;
13383                                 } else if ((prev_bb != block_num + 1) && (prev_bb != -1)) {
13384                                         if (((regtype == 'i' && (vreg < MONO_MAX_IREGS))) || (regtype == 'f' && (vreg < MONO_MAX_FREGS)))
13385                                                 continue;
13386
13387                                         if (!get_vreg_to_inst (cfg, vreg)) {
13388                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
13389                                                         printf ("VREG R%d used in BB%d and BB%d made global.\n", vreg, vreg_to_bb [vreg], block_num);
13390
13391                                                 switch (regtype) {
13392                                                 case 'i':
13393                                                         if (vreg_is_ref (cfg, vreg))
13394                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL, vreg);
13395                                                         else
13396                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL, vreg);
13397                                                         break;
13398                                                 case 'l':
13399                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
13400                                                         break;
13401                                                 case 'f':
13402                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL, vreg);
13403                                                         break;
13404                                                 case 'v':
13405                                                 case 'x':
13406                                                         mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, vreg);
13407                                                         break;
13408                                                 default:
13409                                                         g_assert_not_reached ();
13410                                                 }
13411                                         }
13412
13413                                         /* Flag as having been used in more than one bb */
13414                                         vreg_to_bb [vreg] = -1;
13415                                 }
13416                         }
13417                 }
13418         }
13419
13420         /* If a variable is used in only one bblock, convert it into a local vreg */
13421         for (i = 0; i < cfg->num_varinfo; i++) {
13422                 MonoInst *var = cfg->varinfo [i];
13423                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
13424
13425                 switch (var->type) {
13426                 case STACK_I4:
13427                 case STACK_OBJ:
13428                 case STACK_PTR:
13429                 case STACK_MP:
13430                 case STACK_VTYPE:
13431 #if SIZEOF_REGISTER == 8
13432                 case STACK_I8:
13433 #endif
13434 #if !defined(TARGET_X86)
13435                 /* Enabling this screws up the fp stack on x86 */
13436                 case STACK_R8:
13437 #endif
13438                         if (mono_arch_is_soft_float ())
13439                                 break;
13440
13441                         /*
13442                         if (var->type == STACK_VTYPE && cfg->gsharedvt && mini_is_gsharedvt_variable_type (var->inst_vtype))
13443                                 break;
13444                         */
13445
13446                         /* Arguments are implicitly global */
13447                         /* Putting R4 vars into registers doesn't work currently */
13448                         /* The gsharedvt vars are implicitly referenced by ldaddr opcodes, but those opcodes are only generated later */
13449                         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) {
13450                                 /* 
13451                                  * Make that the variable's liveness interval doesn't contain a call, since
13452                                  * that would cause the lvreg to be spilled, making the whole optimization
13453                                  * useless.
13454                                  */
13455                                 /* This is too slow for JIT compilation */
13456 #if 0
13457                                 if (cfg->compile_aot && vreg_to_bb [var->dreg]) {
13458                                         MonoInst *ins;
13459                                         int def_index, call_index, ins_index;
13460                                         gboolean spilled = FALSE;
13461
13462                                         def_index = -1;
13463                                         call_index = -1;
13464                                         ins_index = 0;
13465                                         for (ins = vreg_to_bb [var->dreg]->code; ins; ins = ins->next) {
13466                                                 const char *spec = INS_INFO (ins->opcode);
13467
13468                                                 if ((spec [MONO_INST_DEST] != ' ') && (ins->dreg == var->dreg))
13469                                                         def_index = ins_index;
13470
13471                                                 if (((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg)) ||
13472                                                         ((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg))) {
13473                                                         if (call_index > def_index) {
13474                                                                 spilled = TRUE;
13475                                                                 break;
13476                                                         }
13477                                                 }
13478
13479                                                 if (MONO_IS_CALL (ins))
13480                                                         call_index = ins_index;
13481
13482                                                 ins_index ++;
13483                                         }
13484
13485                                         if (spilled)
13486                                                 break;
13487                                 }
13488 #endif
13489
13490                                 if (G_UNLIKELY (cfg->verbose_level > 2))
13491                                         printf ("CONVERTED R%d(%d) TO VREG.\n", var->dreg, vmv->idx);
13492                                 var->flags |= MONO_INST_IS_DEAD;
13493                                 cfg->vreg_to_inst [var->dreg] = NULL;
13494                         }
13495                         break;
13496                 }
13497         }
13498
13499         /* 
13500          * Compress the varinfo and vars tables so the liveness computation is faster and
13501          * takes up less space.
13502          */
13503         pos = 0;
13504         for (i = 0; i < cfg->num_varinfo; ++i) {
13505                 MonoInst *var = cfg->varinfo [i];
13506                 if (pos < i && cfg->locals_start == i)
13507                         cfg->locals_start = pos;
13508                 if (!(var->flags & MONO_INST_IS_DEAD)) {
13509                         if (pos < i) {
13510                                 cfg->varinfo [pos] = cfg->varinfo [i];
13511                                 cfg->varinfo [pos]->inst_c0 = pos;
13512                                 memcpy (&cfg->vars [pos], &cfg->vars [i], sizeof (MonoMethodVar));
13513                                 cfg->vars [pos].idx = pos;
13514 #if SIZEOF_REGISTER == 4
13515                                 if (cfg->varinfo [pos]->type == STACK_I8) {
13516                                         /* Modify the two component vars too */
13517                                         MonoInst *var1;
13518
13519                                         var1 = get_vreg_to_inst (cfg, MONO_LVREG_LS (cfg->varinfo [pos]->dreg));
13520                                         var1->inst_c0 = pos;
13521                                         var1 = get_vreg_to_inst (cfg, MONO_LVREG_MS (cfg->varinfo [pos]->dreg));
13522                                         var1->inst_c0 = pos;
13523                                 }
13524 #endif
13525                         }
13526                         pos ++;
13527                 }
13528         }
13529         cfg->num_varinfo = pos;
13530         if (cfg->locals_start > cfg->num_varinfo)
13531                 cfg->locals_start = cfg->num_varinfo;
13532 }
13533
13534 /*
13535  * mono_allocate_gsharedvt_vars:
13536  *
13537  *   Allocate variables with gsharedvt types to entries in the MonoGSharedVtMethodRuntimeInfo.entries array.
13538  * Initialize cfg->gsharedvt_vreg_to_idx with the mapping between vregs and indexes.
13539  */
13540 void
13541 mono_allocate_gsharedvt_vars (MonoCompile *cfg)
13542 {
13543         int i;
13544
13545         cfg->gsharedvt_vreg_to_idx = (int *)mono_mempool_alloc0 (cfg->mempool, sizeof (int) * cfg->next_vreg);
13546
13547         for (i = 0; i < cfg->num_varinfo; ++i) {
13548                 MonoInst *ins = cfg->varinfo [i];
13549                 int idx;
13550
13551                 if (mini_is_gsharedvt_variable_type (ins->inst_vtype)) {
13552                         if (i >= cfg->locals_start) {
13553                                 /* Local */
13554                                 idx = get_gsharedvt_info_slot (cfg, ins->inst_vtype, MONO_RGCTX_INFO_LOCAL_OFFSET);
13555                                 cfg->gsharedvt_vreg_to_idx [ins->dreg] = idx + 1;
13556                                 ins->opcode = OP_GSHAREDVT_LOCAL;
13557                                 ins->inst_imm = idx;
13558                         } else {
13559                                 /* Arg */
13560                                 cfg->gsharedvt_vreg_to_idx [ins->dreg] = -1;
13561                                 ins->opcode = OP_GSHAREDVT_ARG_REGOFFSET;
13562                         }
13563                 }
13564         }
13565 }
13566
13567 /**
13568  * mono_spill_global_vars:
13569  *
13570  *   Generate spill code for variables which are not allocated to registers, 
13571  * and replace vregs with their allocated hregs. *need_local_opts is set to TRUE if
13572  * code is generated which could be optimized by the local optimization passes.
13573  */
13574 void
13575 mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
13576 {
13577         MonoBasicBlock *bb;
13578         char spec2 [16];
13579         int orig_next_vreg;
13580         guint32 *vreg_to_lvreg;
13581         guint32 *lvregs;
13582         guint32 i, lvregs_len, lvregs_size;
13583         gboolean dest_has_lvreg = FALSE;
13584         MonoStackType stacktypes [128];
13585         MonoInst **live_range_start, **live_range_end;
13586         MonoBasicBlock **live_range_start_bb, **live_range_end_bb;
13587
13588         *need_local_opts = FALSE;
13589
13590         memset (spec2, 0, sizeof (spec2));
13591
13592         /* FIXME: Move this function to mini.c */
13593         stacktypes ['i'] = STACK_PTR;
13594         stacktypes ['l'] = STACK_I8;
13595         stacktypes ['f'] = STACK_R8;
13596 #ifdef MONO_ARCH_SIMD_INTRINSICS
13597         stacktypes ['x'] = STACK_VTYPE;
13598 #endif
13599
13600 #if SIZEOF_REGISTER == 4
13601         /* Create MonoInsts for longs */
13602         for (i = 0; i < cfg->num_varinfo; i++) {
13603                 MonoInst *ins = cfg->varinfo [i];
13604
13605                 if ((ins->opcode != OP_REGVAR) && !(ins->flags & MONO_INST_IS_DEAD)) {
13606                         switch (ins->type) {
13607                         case STACK_R8:
13608                         case STACK_I8: {
13609                                 MonoInst *tree;
13610
13611                                 if (ins->type == STACK_R8 && !COMPILE_SOFT_FLOAT (cfg))
13612                                         break;
13613
13614                                 g_assert (ins->opcode == OP_REGOFFSET);
13615
13616                                 tree = get_vreg_to_inst (cfg, MONO_LVREG_LS (ins->dreg));
13617                                 g_assert (tree);
13618                                 tree->opcode = OP_REGOFFSET;
13619                                 tree->inst_basereg = ins->inst_basereg;
13620                                 tree->inst_offset = ins->inst_offset + MINI_LS_WORD_OFFSET;
13621
13622                                 tree = get_vreg_to_inst (cfg, MONO_LVREG_MS (ins->dreg));
13623                                 g_assert (tree);
13624                                 tree->opcode = OP_REGOFFSET;
13625                                 tree->inst_basereg = ins->inst_basereg;
13626                                 tree->inst_offset = ins->inst_offset + MINI_MS_WORD_OFFSET;
13627                                 break;
13628                         }
13629                         default:
13630                                 break;
13631                         }
13632                 }
13633         }
13634 #endif
13635
13636         if (cfg->compute_gc_maps) {
13637                 /* registers need liveness info even for !non refs */
13638                 for (i = 0; i < cfg->num_varinfo; i++) {
13639                         MonoInst *ins = cfg->varinfo [i];
13640
13641                         if (ins->opcode == OP_REGVAR)
13642                                 ins->flags |= MONO_INST_GC_TRACK;
13643                 }
13644         }
13645                 
13646         /* FIXME: widening and truncation */
13647
13648         /*
13649          * As an optimization, when a variable allocated to the stack is first loaded into 
13650          * an lvreg, we will remember the lvreg and use it the next time instead of loading
13651          * the variable again.
13652          */
13653         orig_next_vreg = cfg->next_vreg;
13654         vreg_to_lvreg = (guint32 *)mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * cfg->next_vreg);
13655         lvregs_size = 1024;
13656         lvregs = (guint32 *)mono_mempool_alloc (cfg->mempool, sizeof (guint32) * lvregs_size);
13657         lvregs_len = 0;
13658
13659         /* 
13660          * These arrays contain the first and last instructions accessing a given
13661          * variable.
13662          * Since we emit bblocks in the same order we process them here, and we
13663          * don't split live ranges, these will precisely describe the live range of
13664          * the variable, i.e. the instruction range where a valid value can be found
13665          * in the variables location.
13666          * The live range is computed using the liveness info computed by the liveness pass.
13667          * We can't use vmv->range, since that is an abstract live range, and we need
13668          * one which is instruction precise.
13669          * FIXME: Variables used in out-of-line bblocks have a hole in their live range.
13670          */
13671         /* FIXME: Only do this if debugging info is requested */
13672         live_range_start = g_new0 (MonoInst*, cfg->next_vreg);
13673         live_range_end = g_new0 (MonoInst*, cfg->next_vreg);
13674         live_range_start_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
13675         live_range_end_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
13676         
13677         /* Add spill loads/stores */
13678         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13679                 MonoInst *ins;
13680
13681                 if (cfg->verbose_level > 2)
13682                         printf ("\nSPILL BLOCK %d:\n", bb->block_num);
13683
13684                 /* Clear vreg_to_lvreg array */
13685                 for (i = 0; i < lvregs_len; i++)
13686                         vreg_to_lvreg [lvregs [i]] = 0;
13687                 lvregs_len = 0;
13688
13689                 cfg->cbb = bb;
13690                 MONO_BB_FOR_EACH_INS (bb, ins) {
13691                         const char *spec = INS_INFO (ins->opcode);
13692                         int regtype, srcindex, sreg, tmp_reg, prev_dreg, num_sregs;
13693                         gboolean store, no_lvreg;
13694                         int sregs [MONO_MAX_SRC_REGS];
13695
13696                         if (G_UNLIKELY (cfg->verbose_level > 2))
13697                                 mono_print_ins (ins);
13698
13699                         if (ins->opcode == OP_NOP)
13700                                 continue;
13701
13702                         /* 
13703                          * We handle LDADDR here as well, since it can only be decomposed
13704                          * when variable addresses are known.
13705                          */
13706                         if (ins->opcode == OP_LDADDR) {
13707                                 MonoInst *var = (MonoInst *)ins->inst_p0;
13708
13709                                 if (var->opcode == OP_VTARG_ADDR) {
13710                                         /* Happens on SPARC/S390 where vtypes are passed by reference */
13711                                         MonoInst *vtaddr = var->inst_left;
13712                                         if (vtaddr->opcode == OP_REGVAR) {
13713                                                 ins->opcode = OP_MOVE;
13714                                                 ins->sreg1 = vtaddr->dreg;
13715                                         }
13716                                         else if (var->inst_left->opcode == OP_REGOFFSET) {
13717                                                 ins->opcode = OP_LOAD_MEMBASE;
13718                                                 ins->inst_basereg = vtaddr->inst_basereg;
13719                                                 ins->inst_offset = vtaddr->inst_offset;
13720                                         } else
13721                                                 NOT_IMPLEMENTED;
13722                                 } else if (cfg->gsharedvt && cfg->gsharedvt_vreg_to_idx [var->dreg] < 0) {
13723                                         /* gsharedvt arg passed by ref */
13724                                         g_assert (var->opcode == OP_GSHAREDVT_ARG_REGOFFSET);
13725
13726                                         ins->opcode = OP_LOAD_MEMBASE;
13727                                         ins->inst_basereg = var->inst_basereg;
13728                                         ins->inst_offset = var->inst_offset;
13729                                 } else if (cfg->gsharedvt && cfg->gsharedvt_vreg_to_idx [var->dreg]) {
13730                                         MonoInst *load, *load2, *load3;
13731                                         int idx = cfg->gsharedvt_vreg_to_idx [var->dreg] - 1;
13732                                         int reg1, reg2, reg3;
13733                                         MonoInst *info_var = cfg->gsharedvt_info_var;
13734                                         MonoInst *locals_var = cfg->gsharedvt_locals_var;
13735
13736                                         /*
13737                                          * gsharedvt local.
13738                                          * Compute the address of the local as gsharedvt_locals_var + gsharedvt_info_var->locals_offsets [idx].
13739                                          */
13740
13741                                         g_assert (var->opcode == OP_GSHAREDVT_LOCAL);
13742
13743                                         g_assert (info_var);
13744                                         g_assert (locals_var);
13745
13746                                         /* Mark the instruction used to compute the locals var as used */
13747                                         cfg->gsharedvt_locals_var_ins = NULL;
13748
13749                                         /* Load the offset */
13750                                         if (info_var->opcode == OP_REGOFFSET) {
13751                                                 reg1 = alloc_ireg (cfg);
13752                                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, reg1, info_var->inst_basereg, info_var->inst_offset);
13753                                         } else if (info_var->opcode == OP_REGVAR) {
13754                                                 load = NULL;
13755                                                 reg1 = info_var->dreg;
13756                                         } else {
13757                                                 g_assert_not_reached ();
13758                                         }
13759                                         reg2 = alloc_ireg (cfg);
13760                                         NEW_LOAD_MEMBASE (cfg, load2, OP_LOADI4_MEMBASE, reg2, reg1, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
13761                                         /* Load the locals area address */
13762                                         reg3 = alloc_ireg (cfg);
13763                                         if (locals_var->opcode == OP_REGOFFSET) {
13764                                                 NEW_LOAD_MEMBASE (cfg, load3, OP_LOAD_MEMBASE, reg3, locals_var->inst_basereg, locals_var->inst_offset);
13765                                         } else if (locals_var->opcode == OP_REGVAR) {
13766                                                 NEW_UNALU (cfg, load3, OP_MOVE, reg3, locals_var->dreg);
13767                                         } else {
13768                                                 g_assert_not_reached ();
13769                                         }
13770                                         /* Compute the address */
13771                                         ins->opcode = OP_PADD;
13772                                         ins->sreg1 = reg3;
13773                                         ins->sreg2 = reg2;
13774
13775                                         mono_bblock_insert_before_ins (bb, ins, load3);
13776                                         mono_bblock_insert_before_ins (bb, load3, load2);
13777                                         if (load)
13778                                                 mono_bblock_insert_before_ins (bb, load2, load);
13779                                 } else {
13780                                         g_assert (var->opcode == OP_REGOFFSET);
13781
13782                                         ins->opcode = OP_ADD_IMM;
13783                                         ins->sreg1 = var->inst_basereg;
13784                                         ins->inst_imm = var->inst_offset;
13785                                 }
13786
13787                                 *need_local_opts = TRUE;
13788                                 spec = INS_INFO (ins->opcode);
13789                         }
13790
13791                         if (ins->opcode < MONO_CEE_LAST) {
13792                                 mono_print_ins (ins);
13793                                 g_assert_not_reached ();
13794                         }
13795
13796                         /*
13797                          * Store opcodes have destbasereg in the dreg, but in reality, it is an
13798                          * src register.
13799                          * FIXME:
13800                          */
13801                         if (MONO_IS_STORE_MEMBASE (ins)) {
13802                                 tmp_reg = ins->dreg;
13803                                 ins->dreg = ins->sreg2;
13804                                 ins->sreg2 = tmp_reg;
13805                                 store = TRUE;
13806
13807                                 spec2 [MONO_INST_DEST] = ' ';
13808                                 spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
13809                                 spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
13810                                 spec2 [MONO_INST_SRC3] = ' ';
13811                                 spec = spec2;
13812                         } else if (MONO_IS_STORE_MEMINDEX (ins))
13813                                 g_assert_not_reached ();
13814                         else
13815                                 store = FALSE;
13816                         no_lvreg = FALSE;
13817
13818                         if (G_UNLIKELY (cfg->verbose_level > 2)) {
13819                                 printf ("\t %.3s %d", spec, ins->dreg);
13820                                 num_sregs = mono_inst_get_src_registers (ins, sregs);
13821                                 for (srcindex = 0; srcindex < num_sregs; ++srcindex)
13822                                         printf (" %d", sregs [srcindex]);
13823                                 printf ("\n");
13824                         }
13825
13826                         /***************/
13827                         /*    DREG     */
13828                         /***************/
13829                         regtype = spec [MONO_INST_DEST];
13830                         g_assert (((ins->dreg == -1) && (regtype == ' ')) || ((ins->dreg != -1) && (regtype != ' ')));
13831                         prev_dreg = -1;
13832
13833                         if ((ins->dreg != -1) && get_vreg_to_inst (cfg, ins->dreg)) {
13834                                 MonoInst *var = get_vreg_to_inst (cfg, ins->dreg);
13835                                 MonoInst *store_ins;
13836                                 int store_opcode;
13837                                 MonoInst *def_ins = ins;
13838                                 int dreg = ins->dreg; /* The original vreg */
13839
13840                                 store_opcode = mono_type_to_store_membase (cfg, var->inst_vtype);
13841
13842                                 if (var->opcode == OP_REGVAR) {
13843                                         ins->dreg = var->dreg;
13844                                 } 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)) {
13845                                         /* 
13846                                          * Instead of emitting a load+store, use a _membase opcode.
13847                                          */
13848                                         g_assert (var->opcode == OP_REGOFFSET);
13849                                         if (ins->opcode == OP_MOVE) {
13850                                                 NULLIFY_INS (ins);
13851                                                 def_ins = NULL;
13852                                         } else {
13853                                                 ins->opcode = op_to_op_dest_membase (store_opcode, ins->opcode);
13854                                                 ins->inst_basereg = var->inst_basereg;
13855                                                 ins->inst_offset = var->inst_offset;
13856                                                 ins->dreg = -1;
13857                                         }
13858                                         spec = INS_INFO (ins->opcode);
13859                                 } else {
13860                                         guint32 lvreg;
13861
13862                                         g_assert (var->opcode == OP_REGOFFSET);
13863
13864                                         prev_dreg = ins->dreg;
13865
13866                                         /* Invalidate any previous lvreg for this vreg */
13867                                         vreg_to_lvreg [ins->dreg] = 0;
13868
13869                                         lvreg = 0;
13870
13871                                         if (COMPILE_SOFT_FLOAT (cfg) && store_opcode == OP_STORER8_MEMBASE_REG) {
13872                                                 regtype = 'l';
13873                                                 store_opcode = OP_STOREI8_MEMBASE_REG;
13874                                         }
13875
13876                                         ins->dreg = alloc_dreg (cfg, stacktypes [regtype]);
13877
13878 #if SIZEOF_REGISTER != 8
13879                                         if (regtype == 'l') {
13880                                                 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));
13881                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
13882                                                 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));
13883                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
13884                                                 def_ins = store_ins;
13885                                         }
13886                                         else
13887 #endif
13888                                         {
13889                                                 g_assert (store_opcode != OP_STOREV_MEMBASE);
13890
13891                                                 /* Try to fuse the store into the instruction itself */
13892                                                 /* FIXME: Add more instructions */
13893                                                 if (!lvreg && ((ins->opcode == OP_ICONST) || ((ins->opcode == OP_I8CONST) && (ins->inst_c0 == 0)))) {
13894                                                         ins->opcode = store_membase_reg_to_store_membase_imm (store_opcode);
13895                                                         ins->inst_imm = ins->inst_c0;
13896                                                         ins->inst_destbasereg = var->inst_basereg;
13897                                                         ins->inst_offset = var->inst_offset;
13898                                                         spec = INS_INFO (ins->opcode);
13899                                                 } else if (!lvreg && ((ins->opcode == OP_MOVE) || (ins->opcode == OP_FMOVE) || (ins->opcode == OP_LMOVE) || (ins->opcode == OP_RMOVE))) {
13900                                                         ins->opcode = store_opcode;
13901                                                         ins->inst_destbasereg = var->inst_basereg;
13902                                                         ins->inst_offset = var->inst_offset;
13903
13904                                                         no_lvreg = TRUE;
13905
13906                                                         tmp_reg = ins->dreg;
13907                                                         ins->dreg = ins->sreg2;
13908                                                         ins->sreg2 = tmp_reg;
13909                                                         store = TRUE;
13910
13911                                                         spec2 [MONO_INST_DEST] = ' ';
13912                                                         spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
13913                                                         spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
13914                                                         spec2 [MONO_INST_SRC3] = ' ';
13915                                                         spec = spec2;
13916                                                 } else if (!lvreg && (op_to_op_store_membase (store_opcode, ins->opcode) != -1)) {
13917                                                         // FIXME: The backends expect the base reg to be in inst_basereg
13918                                                         ins->opcode = op_to_op_store_membase (store_opcode, ins->opcode);
13919                                                         ins->dreg = -1;
13920                                                         ins->inst_basereg = var->inst_basereg;
13921                                                         ins->inst_offset = var->inst_offset;
13922                                                         spec = INS_INFO (ins->opcode);
13923                                                 } else {
13924                                                         /* printf ("INS: "); mono_print_ins (ins); */
13925                                                         /* Create a store instruction */
13926                                                         NEW_STORE_MEMBASE (cfg, store_ins, store_opcode, var->inst_basereg, var->inst_offset, ins->dreg);
13927
13928                                                         /* Insert it after the instruction */
13929                                                         mono_bblock_insert_after_ins (bb, ins, store_ins);
13930
13931                                                         def_ins = store_ins;
13932
13933                                                         /* 
13934                                                          * We can't assign ins->dreg to var->dreg here, since the
13935                                                          * sregs could use it. So set a flag, and do it after
13936                                                          * the sregs.
13937                                                          */
13938                                                         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)))
13939                                                                 dest_has_lvreg = TRUE;
13940                                                 }
13941                                         }
13942                                 }
13943
13944                                 if (def_ins && !live_range_start [dreg]) {
13945                                         live_range_start [dreg] = def_ins;
13946                                         live_range_start_bb [dreg] = bb;
13947                                 }
13948
13949                                 if (cfg->compute_gc_maps && def_ins && (var->flags & MONO_INST_GC_TRACK)) {
13950                                         MonoInst *tmp;
13951
13952                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
13953                                         tmp->inst_c1 = dreg;
13954                                         mono_bblock_insert_after_ins (bb, def_ins, tmp);
13955                                 }
13956                         }
13957
13958                         /************/
13959                         /*  SREGS   */
13960                         /************/
13961                         num_sregs = mono_inst_get_src_registers (ins, sregs);
13962                         for (srcindex = 0; srcindex < 3; ++srcindex) {
13963                                 regtype = spec [MONO_INST_SRC1 + srcindex];
13964                                 sreg = sregs [srcindex];
13965
13966                                 g_assert (((sreg == -1) && (regtype == ' ')) || ((sreg != -1) && (regtype != ' ')));
13967                                 if ((sreg != -1) && get_vreg_to_inst (cfg, sreg)) {
13968                                         MonoInst *var = get_vreg_to_inst (cfg, sreg);
13969                                         MonoInst *use_ins = ins;
13970                                         MonoInst *load_ins;
13971                                         guint32 load_opcode;
13972
13973                                         if (var->opcode == OP_REGVAR) {
13974                                                 sregs [srcindex] = var->dreg;
13975                                                 //mono_inst_set_src_registers (ins, sregs);
13976                                                 live_range_end [sreg] = use_ins;
13977                                                 live_range_end_bb [sreg] = bb;
13978
13979                                                 if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
13980                                                         MonoInst *tmp;
13981
13982                                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
13983                                                         /* var->dreg is a hreg */
13984                                                         tmp->inst_c1 = sreg;
13985                                                         mono_bblock_insert_after_ins (bb, ins, tmp);
13986                                                 }
13987
13988                                                 continue;
13989                                         }
13990
13991                                         g_assert (var->opcode == OP_REGOFFSET);
13992                                                 
13993                                         load_opcode = mono_type_to_load_membase (cfg, var->inst_vtype);
13994
13995                                         g_assert (load_opcode != OP_LOADV_MEMBASE);
13996
13997                                         if (vreg_to_lvreg [sreg]) {
13998                                                 g_assert (vreg_to_lvreg [sreg] != -1);
13999
14000                                                 /* The variable is already loaded to an lvreg */
14001                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
14002                                                         printf ("\t\tUse lvreg R%d for R%d.\n", vreg_to_lvreg [sreg], sreg);
14003                                                 sregs [srcindex] = vreg_to_lvreg [sreg];
14004                                                 //mono_inst_set_src_registers (ins, sregs);
14005                                                 continue;
14006                                         }
14007
14008                                         /* Try to fuse the load into the instruction */
14009                                         if ((srcindex == 0) && (op_to_op_src1_membase (cfg, load_opcode, ins->opcode) != -1)) {
14010                                                 ins->opcode = op_to_op_src1_membase (cfg, load_opcode, ins->opcode);
14011                                                 sregs [0] = var->inst_basereg;
14012                                                 //mono_inst_set_src_registers (ins, sregs);
14013                                                 ins->inst_offset = var->inst_offset;
14014                                         } else if ((srcindex == 1) && (op_to_op_src2_membase (cfg, load_opcode, ins->opcode) != -1)) {
14015                                                 ins->opcode = op_to_op_src2_membase (cfg, load_opcode, ins->opcode);
14016                                                 sregs [1] = var->inst_basereg;
14017                                                 //mono_inst_set_src_registers (ins, sregs);
14018                                                 ins->inst_offset = var->inst_offset;
14019                                         } else {
14020                                                 if (MONO_IS_REAL_MOVE (ins)) {
14021                                                         ins->opcode = OP_NOP;
14022                                                         sreg = ins->dreg;
14023                                                 } else {
14024                                                         //printf ("%d ", srcindex); mono_print_ins (ins);
14025
14026                                                         sreg = alloc_dreg (cfg, stacktypes [regtype]);
14027
14028                                                         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) {
14029                                                                 if (var->dreg == prev_dreg) {
14030                                                                         /*
14031                                                                          * sreg refers to the value loaded by the load
14032                                                                          * emitted below, but we need to use ins->dreg
14033                                                                          * since it refers to the store emitted earlier.
14034                                                                          */
14035                                                                         sreg = ins->dreg;
14036                                                                 }
14037                                                                 g_assert (sreg != -1);
14038                                                                 vreg_to_lvreg [var->dreg] = sreg;
14039                                                                 if (lvregs_len >= lvregs_size) {
14040                                                                         guint32 *new_lvregs = mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * lvregs_size * 2);
14041                                                                         memcpy (new_lvregs, lvregs, sizeof (guint32) * lvregs_size);
14042                                                                         lvregs = new_lvregs;
14043                                                                         lvregs_size *= 2;
14044                                                                 }
14045                                                                 lvregs [lvregs_len ++] = var->dreg;
14046                                                         }
14047                                                 }
14048
14049                                                 sregs [srcindex] = sreg;
14050                                                 //mono_inst_set_src_registers (ins, sregs);
14051
14052 #if SIZEOF_REGISTER != 8
14053                                                 if (regtype == 'l') {
14054                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, MONO_LVREG_MS (sreg), var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET);
14055                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14056                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, MONO_LVREG_LS (sreg), var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET);
14057                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14058                                                         use_ins = load_ins;
14059                                                 }
14060                                                 else
14061 #endif
14062                                                 {
14063 #if SIZEOF_REGISTER == 4
14064                                                         g_assert (load_opcode != OP_LOADI8_MEMBASE);
14065 #endif
14066                                                         NEW_LOAD_MEMBASE (cfg, load_ins, load_opcode, sreg, var->inst_basereg, var->inst_offset);
14067                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14068                                                         use_ins = load_ins;
14069                                                 }
14070                                         }
14071
14072                                         if (var->dreg < orig_next_vreg) {
14073                                                 live_range_end [var->dreg] = use_ins;
14074                                                 live_range_end_bb [var->dreg] = bb;
14075                                         }
14076
14077                                         if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14078                                                 MonoInst *tmp;
14079
14080                                                 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14081                                                 tmp->inst_c1 = var->dreg;
14082                                                 mono_bblock_insert_after_ins (bb, ins, tmp);
14083                                         }
14084                                 }
14085                         }
14086                         mono_inst_set_src_registers (ins, sregs);
14087
14088                         if (dest_has_lvreg) {
14089                                 g_assert (ins->dreg != -1);
14090                                 vreg_to_lvreg [prev_dreg] = ins->dreg;
14091                                 if (lvregs_len >= lvregs_size) {
14092                                         guint32 *new_lvregs = mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * lvregs_size * 2);
14093                                         memcpy (new_lvregs, lvregs, sizeof (guint32) * lvregs_size);
14094                                         lvregs = new_lvregs;
14095                                         lvregs_size *= 2;
14096                                 }
14097                                 lvregs [lvregs_len ++] = prev_dreg;
14098                                 dest_has_lvreg = FALSE;
14099                         }
14100
14101                         if (store) {
14102                                 tmp_reg = ins->dreg;
14103                                 ins->dreg = ins->sreg2;
14104                                 ins->sreg2 = tmp_reg;
14105                         }
14106
14107                         if (MONO_IS_CALL (ins)) {
14108                                 /* Clear vreg_to_lvreg array */
14109                                 for (i = 0; i < lvregs_len; i++)
14110                                         vreg_to_lvreg [lvregs [i]] = 0;
14111                                 lvregs_len = 0;
14112                         } else if (ins->opcode == OP_NOP) {
14113                                 ins->dreg = -1;
14114                                 MONO_INST_NULLIFY_SREGS (ins);
14115                         }
14116
14117                         if (cfg->verbose_level > 2)
14118                                 mono_print_ins_index (1, ins);
14119                 }
14120
14121                 /* Extend the live range based on the liveness info */
14122                 if (cfg->compute_precise_live_ranges && bb->live_out_set && bb->code) {
14123                         for (i = 0; i < cfg->num_varinfo; i ++) {
14124                                 MonoMethodVar *vi = MONO_VARINFO (cfg, i);
14125
14126                                 if (vreg_is_volatile (cfg, vi->vreg))
14127                                         /* The liveness info is incomplete */
14128                                         continue;
14129
14130                                 if (mono_bitset_test_fast (bb->live_in_set, i) && !live_range_start [vi->vreg]) {
14131                                         /* Live from at least the first ins of this bb */
14132                                         live_range_start [vi->vreg] = bb->code;
14133                                         live_range_start_bb [vi->vreg] = bb;
14134                                 }
14135
14136                                 if (mono_bitset_test_fast (bb->live_out_set, i)) {
14137                                         /* Live at least until the last ins of this bb */
14138                                         live_range_end [vi->vreg] = bb->last_ins;
14139                                         live_range_end_bb [vi->vreg] = bb;
14140                                 }
14141                         }
14142                 }
14143         }
14144         
14145         /*
14146          * Emit LIVERANGE_START/LIVERANGE_END opcodes, the backend will implement them
14147          * by storing the current native offset into MonoMethodVar->live_range_start/end.
14148          */
14149         if (cfg->backend->have_liverange_ops && cfg->compute_precise_live_ranges && cfg->comp_done & MONO_COMP_LIVENESS) {
14150                 for (i = 0; i < cfg->num_varinfo; ++i) {
14151                         int vreg = MONO_VARINFO (cfg, i)->vreg;
14152                         MonoInst *ins;
14153
14154                         if (live_range_start [vreg]) {
14155                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_START);
14156                                 ins->inst_c0 = i;
14157                                 ins->inst_c1 = vreg;
14158                                 mono_bblock_insert_after_ins (live_range_start_bb [vreg], live_range_start [vreg], ins);
14159                         }
14160                         if (live_range_end [vreg]) {
14161                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_END);
14162                                 ins->inst_c0 = i;
14163                                 ins->inst_c1 = vreg;
14164                                 if (live_range_end [vreg] == live_range_end_bb [vreg]->last_ins)
14165                                         mono_add_ins_to_end (live_range_end_bb [vreg], ins);
14166                                 else
14167                                         mono_bblock_insert_after_ins (live_range_end_bb [vreg], live_range_end [vreg], ins);
14168                         }
14169                 }
14170         }
14171
14172         if (cfg->gsharedvt_locals_var_ins) {
14173                 /* Nullify if unused */
14174                 cfg->gsharedvt_locals_var_ins->opcode = OP_PCONST;
14175                 cfg->gsharedvt_locals_var_ins->inst_imm = 0;
14176         }
14177
14178         g_free (live_range_start);
14179         g_free (live_range_end);
14180         g_free (live_range_start_bb);
14181         g_free (live_range_end_bb);
14182 }
14183
14184
14185 /**
14186  * FIXME:
14187  * - use 'iadd' instead of 'int_add'
14188  * - handling ovf opcodes: decompose in method_to_ir.
14189  * - unify iregs/fregs
14190  *   -> partly done, the missing parts are:
14191  *   - a more complete unification would involve unifying the hregs as well, so
14192  *     code wouldn't need if (fp) all over the place. but that would mean the hregs
14193  *     would no longer map to the machine hregs, so the code generators would need to
14194  *     be modified. Also, on ia64 for example, niregs + nfregs > 256 -> bitmasks
14195  *     wouldn't work any more. Duplicating the code in mono_local_regalloc () into
14196  *     fp/non-fp branches speeds it up by about 15%.
14197  * - use sext/zext opcodes instead of shifts
14198  * - add OP_ICALL
14199  * - get rid of TEMPLOADs if possible and use vregs instead
14200  * - clean up usage of OP_P/OP_ opcodes
14201  * - cleanup usage of DUMMY_USE
14202  * - cleanup the setting of ins->type for MonoInst's which are pushed on the 
14203  *   stack
14204  * - set the stack type and allocate a dreg in the EMIT_NEW macros
14205  * - get rid of all the <foo>2 stuff when the new JIT is ready.
14206  * - make sure handle_stack_args () is called before the branch is emitted
14207  * - when the new IR is done, get rid of all unused stuff
14208  * - COMPARE/BEQ as separate instructions or unify them ?
14209  *   - keeping them separate allows specialized compare instructions like
14210  *     compare_imm, compare_membase
14211  *   - most back ends unify fp compare+branch, fp compare+ceq
14212  * - integrate mono_save_args into inline_method
14213  * - get rid of the empty bblocks created by MONO_EMIT_NEW_BRACH_BLOCK2
14214  * - handle long shift opts on 32 bit platforms somehow: they require 
14215  *   3 sregs (2 for arg1 and 1 for arg2)
14216  * - make byref a 'normal' type.
14217  * - use vregs for bb->out_stacks if possible, handle_global_vreg will make them a
14218  *   variable if needed.
14219  * - do not start a new IL level bblock when cfg->cbb is changed by a function call
14220  *   like inline_method.
14221  * - remove inlining restrictions
14222  * - fix LNEG and enable cfold of INEG
14223  * - generalize x86 optimizations like ldelema as a peephole optimization
14224  * - add store_mem_imm for amd64
14225  * - optimize the loading of the interruption flag in the managed->native wrappers
14226  * - avoid special handling of OP_NOP in passes
14227  * - move code inserting instructions into one function/macro.
14228  * - try a coalescing phase after liveness analysis
14229  * - add float -> vreg conversion + local optimizations on !x86
14230  * - figure out how to handle decomposed branches during optimizations, ie.
14231  *   compare+branch, op_jump_table+op_br etc.
14232  * - promote RuntimeXHandles to vregs
14233  * - vtype cleanups:
14234  *   - add a NEW_VARLOADA_VREG macro
14235  * - the vtype optimizations are blocked by the LDADDR opcodes generated for 
14236  *   accessing vtype fields.
14237  * - get rid of I8CONST on 64 bit platforms
14238  * - dealing with the increase in code size due to branches created during opcode
14239  *   decomposition:
14240  *   - use extended basic blocks
14241  *     - all parts of the JIT
14242  *     - handle_global_vregs () && local regalloc
14243  *   - avoid introducing global vregs during decomposition, like 'vtable' in isinst
14244  * - sources of increase in code size:
14245  *   - vtypes
14246  *   - long compares
14247  *   - isinst and castclass
14248  *   - lvregs not allocated to global registers even if used multiple times
14249  * - call cctors outside the JIT, to make -v output more readable and JIT timings more
14250  *   meaningful.
14251  * - check for fp stack leakage in other opcodes too. (-> 'exceptions' optimization)
14252  * - add all micro optimizations from the old JIT
14253  * - put tree optimizations into the deadce pass
14254  * - decompose op_start_handler/op_endfilter/op_endfinally earlier using an arch
14255  *   specific function.
14256  * - unify the float comparison opcodes with the other comparison opcodes, i.e.
14257  *   fcompare + branchCC.
14258  * - create a helper function for allocating a stack slot, taking into account 
14259  *   MONO_CFG_HAS_SPILLUP.
14260  * - merge r68207.
14261  * - optimize mono_regstate2_alloc_int/float.
14262  * - fix the pessimistic handling of variables accessed in exception handler blocks.
14263  * - need to write a tree optimization pass, but the creation of trees is difficult, i.e.
14264  *   parts of the tree could be separated by other instructions, killing the tree
14265  *   arguments, or stores killing loads etc. Also, should we fold loads into other
14266  *   instructions if the result of the load is used multiple times ?
14267  * - make the REM_IMM optimization in mini-x86.c arch-independent.
14268  * - LAST MERGE: 108395.
14269  * - when returning vtypes in registers, generate IR and append it to the end of the
14270  *   last bb instead of doing it in the epilog.
14271  * - change the store opcodes so they use sreg1 instead of dreg to store the base register.
14272  */
14273
14274 /*
14275
14276 NOTES
14277 -----
14278
14279 - When to decompose opcodes:
14280   - earlier: this makes some optimizations hard to implement, since the low level IR
14281   no longer contains the neccessary information. But it is easier to do.
14282   - later: harder to implement, enables more optimizations.
14283 - Branches inside bblocks:
14284   - created when decomposing complex opcodes. 
14285     - branches to another bblock: harmless, but not tracked by the branch 
14286       optimizations, so need to branch to a label at the start of the bblock.
14287     - branches to inside the same bblock: very problematic, trips up the local
14288       reg allocator. Can be fixed by spitting the current bblock, but that is a
14289       complex operation, since some local vregs can become global vregs etc.
14290 - Local/global vregs:
14291   - local vregs: temporary vregs used inside one bblock. Assigned to hregs by the
14292     local register allocator.
14293   - global vregs: used in more than one bblock. Have an associated MonoMethodVar
14294     structure, created by mono_create_var (). Assigned to hregs or the stack by
14295     the global register allocator.
14296 - When to do optimizations like alu->alu_imm:
14297   - earlier -> saves work later on since the IR will be smaller/simpler
14298   - later -> can work on more instructions
14299 - Handling of valuetypes:
14300   - When a vtype is pushed on the stack, a new temporary is created, an 
14301     instruction computing its address (LDADDR) is emitted and pushed on
14302     the stack. Need to optimize cases when the vtype is used immediately as in
14303     argument passing, stloc etc.
14304 - Instead of the to_end stuff in the old JIT, simply call the function handling
14305   the values on the stack before emitting the last instruction of the bb.
14306 */
14307
14308 #endif /* !DISABLE_JIT */